v157 · web bluetooth
Web Bluetooth: Make BluetoothRemoteGATTServer an EventTarget
Chrome 157 rewires the inheritance of one interface: BluetoothRemoteGATTServer now extends EventTarget, gaining addEventListener(), removeEventListener(), and dispatchEvent(). Small change, load-bearing purpose: the GATT server object is the connection, so connection-level events — starting with maxwritewithoutresponsesizechanged — finally have the right object to fire on. Best of all for a demo site: the whole contract is checkable from the prototype chain, no Bluetooth hardware required.
concepts
-
Prototype chain probe
The exact contract, verified live with zero hardware: walk
BluetoothRemoteGATTServer.prototypelink by link toEventTarget.prototype, confirm the three methods are inherited (not copies), and compare every Web Bluetooth interface's ancestry side by side — the server was the odd one out until 157. -
Live server events
The hardware path: pair a real BLE device behind a user gesture, connect its GATT server, and attach listeners on the server object — the thing this feature makes possible — with an event log showing each event's
target. Degrades honestly when the API, adapter, or hardware is missing. -
Listener migration map
Which object hosts which event now? An interactive map of the Web Bluetooth event surface —
availabilitychangedonBluetooth,gattserverdisconnectedstill on the device, size changes on the server — with a live prototype check per row and the exact listener code generated for each choice. -
Reconnect lifecycle
device.gattis[SameObject]: reconnecting hands you the same server instance, so listeners attached to it survive disconnect/reconnect cycles. This concept proves the identity with hardware, demonstrates the exponential-backoff reconnect pattern that identity enables, and shows the stale-listener bug it prevents.
why it shipped
BluetoothRemoteGATTServer represents the active GATT connection to a device. Connection-level state — like the negotiated maximum write-without-response size — belongs to that connection, so when the companion feature exposed maxWriteWithoutResponseSize with a maxwritewithoutresponsesizechanged event, the event needed a home. Firing connection events on BluetoothDevice (the historical workaround, as gattserverdisconnected does) muddles two lifetimes: a device outlives any one connection. Making the server an EventTarget puts connection events on the object whose lifetime they share, using the standard listener API every other platform object already speaks.
In the spec, the event-bearing siblings — Bluetooth, BluetoothDevice, BluetoothRemoteGATTService, BluetoothRemoteGATTCharacteristic — all declare : EventTarget (only the passive BluetoothRemoteGATTDescriptor does not); the server was the odd one out among objects that plainly need events. Implementations lag the spec in different places — the prototype probe renders a live family table of what your browser actually ships.
the API
// The spec change, in one line of IDL:
// interface BluetoothRemoteGATTServer : EventTarget { ... }
const server = await device.gatt.connect();
// New in 157 — standard listeners on the server object itself:
server.addEventListener("maxwritewithoutresponsesizechanged", () => {
rechunk(server.maxWriteWithoutResponseSize);
});
// Checkable TODAY without any hardware:
BluetoothRemoteGATTServer.prototype instanceof EventTarget // true in 157
typeof BluetoothRemoteGATTServer.prototype.addEventListener // "function"
Availability note: Web Bluetooth is stable on Android, ChromeOS, macOS and Windows. On desktop Linux the WebBluetooth runtime flag is still experimental — enable chrome://flags/#enable-experimental-web-platform-features, or launch with --enable-blink-features=WebBluetooth, or (headless/CI) --enable-experimental-web-platform-features. The demos detect and report the exact missing prerequisite rather than blaming the browser.