From bbc7b06c26b3ab30535dbf26f08649e1aa7492a4 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Thu, 28 Nov 2024 15:45:02 +0100 Subject: [PATCH 1/3] Improvements and additions to Web Serial API docs --- files/en-us/web/api/serial/getports/index.md | 4 +- files/en-us/web/api/serial/index.md | 4 +- .../en-us/web/api/serial/requestport/index.md | 76 +++++++++++++------ files/en-us/web/api/serialport/close/index.md | 4 + .../en-us/web/api/serialport/forget/index.md | 15 +++- .../en-us/web/api/serialport/getinfo/index.md | 40 +++++++++- files/en-us/web/api/serialport/index.md | 4 +- files/en-us/web/api/web_serial_api/index.md | 5 ++ 8 files changed, 115 insertions(+), 37 deletions(-) diff --git a/files/en-us/web/api/serial/getports/index.md b/files/en-us/web/api/serial/getports/index.md index fcae0e2ed57c67a..4e494dba9890791 100644 --- a/files/en-us/web/api/serial/getports/index.md +++ b/files/en-us/web/api/serial/getports/index.md @@ -29,7 +29,9 @@ A {{jsxref("Promise")}} that resolves with an array of {{domxref("SerialPort")}} ### Exceptions - `SecurityError` {{domxref("DOMException")}} - - : The returned `Promise` rejects with this error if a [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) blocks the use of this feature or a user permission prompt was denied. + - : The returned `Promise` rejects with this error if: + - A {{httpheader('Permissions-Policy/serial','serial')}} [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) blocks the use of this feature. + - A user permission prompt was denied. ## Examples diff --git a/files/en-us/web/api/serial/index.md b/files/en-us/web/api/serial/index.md index 46448f4138ffc06..1a5f68bb3219438 100644 --- a/files/en-us/web/api/serial/index.md +++ b/files/en-us/web/api/serial/index.md @@ -17,9 +17,7 @@ The `Serial` interface of the [Web Serial API](/en-US/docs/Web/API/Web_Serial_AP - {{domxref("Serial.requestPort()")}} {{Experimental_Inline}} - - : Returns a {{jsxref("Promise")}} that resolves with an instance of {{domxref("SerialPort")}} representing the device chosen by the user or rejects if no device was selected. - - This method must be called with user activation. + - : Returns a {{jsxref("Promise")}} that resolves with an instance of {{domxref("SerialPort")}} representing the device chosen by the user. This method must be called via [transient activation](/en-US/docs/Glossary/Transient_activation). - {{domxref("Serial.getPorts()")}} {{Experimental_Inline}} - : Returns a {{jsxref("Promise")}} that resolves with an array of {{domxref("SerialPort")}} objects representing serial ports connected to diff --git a/files/en-us/web/api/serial/requestport/index.md b/files/en-us/web/api/serial/requestport/index.md index 2c3d47e483a15ca..474dbbb115d9f31 100644 --- a/files/en-us/web/api/serial/requestport/index.md +++ b/files/en-us/web/api/serial/requestport/index.md @@ -10,7 +10,13 @@ browser-compat: api.Serial.requestPort {{APIRef("Web Serial API")}}{{SecureContext_Header}}{{SeeCompatTable}} -The **`Serial.requestPort()`** method of the {{domxref("Serial")}} interface returns a {{jsxref("Promise")}} that resolves with an instance of {{domxref("SerialPort")}} representing the device chosen by the user or rejects if no device was selected. +The **`Serial.requestPort()`** method of the {{domxref("Serial")}} interface presents the user with a dialog asking them to select a serial device to connect to. It returns a {{jsxref("Promise")}} that resolves with an instance of {{domxref("SerialPort")}} representing the device chosen by the user. + +## Description + +When the user first visits a site it will not have permission to access any serial devices. A site must first call `requestPort()` to prompt the user to select which device the site should be allowed to control. + +This method must be called via [transient activation](/en-US/docs/Glossary/Transient_activation). The user has to interact with the page or a UI element in order for this feature to work. ## Syntax @@ -21,18 +27,20 @@ requestPort(options) ### Parameters -- `options` +- `options` {{optional_inline}} - : An object with the following properties: - - `filters` - - - : A list of objects containing vendor and product IDs used to search for attached devices. The [USB Implementors Forum](https://www.usb.org/) assigns IDs to specific companies. Each company assigns IDs to its products. Filters contain the following values: - - - `usbVendorId` - - : An unsigned short integer that identifies a USB device vendor. - - `usbProductId` - - : An unsigned short integer that identifies a USB device. + - `filters` {{optional_inline}} + - : A list of objects containing vendor, product, or Bluetooth service class IDs used to filter the specific device types made available for the user to request a connection to. If no filters are specified, the user is presented with a list of every available device to choose from. Filters can contain the following values: + - `bluetoothServiceClassId` {{optional_inline}} + - : An unsigned long integer or string representing a Bluetooth service class ID. This can be a 16- or 32-bit UUID aliase, any valid UUID, or a valid name from a GATT assigned services key. + - `usbVendorId` {{optional_inline}} + - : An unsigned short integer that identifies a USB device vendor. The [USB Implementors Forum](https://www.usb.org/) assigns IDs to specific vendors. + - `usbProductId` {{optional_inline}} + - : An unsigned short integer that identifies a USB device. Each vendor assigns IDs to its products. + - `allowedBluetoothServiceClassIds` {{optional_inline}} + - : A list of unsigned long integers and/or strings representing Bluetooth service class IDs. Bluetooth ports with custom service class IDs are excluded from the list of ports presented to the user unless the service class ID is included in this list. ### Return value @@ -41,29 +49,47 @@ A {{jsxref("Promise")}} that resolves with an instance of {{domxref("SerialPort" ### Exceptions - `SecurityError` {{domxref("DOMException")}} - - : The returned `Promise` rejects with this error if a [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) blocks the use of this feature or a user permission prompt was denied. + - : The returned `Promise` rejects with this error if: + - A {{httpheader('Permissions-Policy/serial','serial')}} [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) blocks the use of this feature. + - A user permission prompt was denied. - `NotFoundError` {{domxref("DOMException")}} - - : The returned `Promise` rejects with this if the user does not select a port when prompted. + - : The returned `Promise` rejects with this exception if the user does not select a port when prompted. -## Security +## Examples -{{Glossary("Transient activation")}} is required. The user has to interact with the page or a UI element in order for this feature to work. +### Allow the user to select any device -## Examples +This example prompts the user to select a device via `requestPort()` when a ` +``` + +```js +const connectBtn = document.getElementById("connect"); +connectBtn.addEventListener("click", () => { + try { + const port = await navigator.serial.requestPort(); + // Connect to port or add it to the list of available ports + } catch (e) { + // The user didn't select a device + } +}); +``` + +### Allow the user to select a specific vendor's device -The following example shows a filter being passed to `requestPort()` with a USB vendor ID in order to limit the set of devices shown to the user to only USB devices built by a particular manufacturer. If this filter was omitted the user would be able to select any available port. +In this case, a filter is passed to `requestPort()` with a USB vendor ID to limit the set of devices shown to the user to only USB devices built by a particular manufacturer. ```js -button.addEventListener("click", () => { +connectBtn.addEventListener("click", () => { const usbVendorId = 0xabcd; - navigator.serial - .requestPort({ filters: [{ usbVendorId }] }) - .then((port) => { - // Connect to `port` or add it to the list of available ports. - }) - .catch((e) => { - // The user didn't select a port. - }); + try { + const port = await navigator.serial.requestPort({ filters: [{ usbVendorId }] }); + // Connect to port or add it to the list of available ports + } catch (e) { + // The user didn't select a device + } }); ``` diff --git a/files/en-us/web/api/serialport/close/index.md b/files/en-us/web/api/serialport/close/index.md index afad3908609c467..86195fe70814363 100644 --- a/files/en-us/web/api/serialport/close/index.md +++ b/files/en-us/web/api/serialport/close/index.md @@ -12,6 +12,10 @@ browser-compat: api.SerialPort.close The **`SerialPort.close()`** method of the {{domxref("SerialPort")}} interface returns a {{jsxref("Promise")}} that resolves when the port closes. +## Description + +`close()` closes the serial port if previously-locked {{domxref("SerialPort.readable")}} and {{domxref("SerialPort.writable")}} members are unlocked, meaning the `releaseLock()` methods have been called for their respective reader and writer. However, in some cases it is not that simple, for example when continuously reading data from a serial device using a loop. See [Close a serial port](https://developer.chrome.com/docs/capabilities/serial#close-port) for more guidance. + ## Syntax ```js-nolint diff --git a/files/en-us/web/api/serialport/forget/index.md b/files/en-us/web/api/serialport/forget/index.md index 2c0dae3d704a02d..4f648568f222b04 100644 --- a/files/en-us/web/api/serialport/forget/index.md +++ b/files/en-us/web/api/serialport/forget/index.md @@ -10,7 +10,18 @@ browser-compat: api.SerialPort.forget {{securecontext_header}}{{APIRef("Web Serial API")}}{{SeeCompatTable}}{{AvailableInWorkers("window_and_dedicated")}} -The **`SerialPort.forget()`** method of the {{domxref("SerialPort")}} interface returns a {{jsxref("Promise")}} that resolves when the serial port is closed and is forgotten. +The **`SerialPort.forget()`** method of the {{domxref("SerialPort")}} interface returns a {{jsxref("Promise")}} that resolves when access to the serial port is revoked. + +## Description + +A website can clean up permissions to access a serial port it is no longer interested in retaining by calling `SerialPort.forget()`. In real terms, calling this closes the connection, forgets the device, and resets the permission. + +```js +// Voluntarily revoke access to this serial port +await port.forget(); +``` + +For example, for an educational web application used on a shared computer with many devices, a large number of accumulated user-generated permissions creates a poor user experience. ## Syntax @@ -24,7 +35,7 @@ None. ### Return value -A {{jsxref("Promise")}} that resolves with `undefined` once the connection is closed, the device is forgotten, and the permission is reset. +A {{jsxref("Promise")}} that resolves with `undefined` once the connection is revoked. ## Specifications diff --git a/files/en-us/web/api/serialport/getinfo/index.md b/files/en-us/web/api/serialport/getinfo/index.md index 978321fb3c2c4c8..fe7114da9ca008f 100644 --- a/files/en-us/web/api/serialport/getinfo/index.md +++ b/files/en-us/web/api/serialport/getinfo/index.md @@ -10,7 +10,7 @@ browser-compat: api.SerialPort.getInfo {{SecureContext_Header}}{{APIRef("Web Serial API")}}{{SeeCompatTable}}{{AvailableInWorkers("window_and_dedicated")}} -The **`getInfo()`** method of the {{domxref("SerialPort")}} interface returns an object whose properties are the vendor ID and product ID of the device. +The **`getInfo()`** method of the {{domxref("SerialPort")}} interface returns an object containing identifying information for the device available via the port. ## Syntax @@ -24,12 +24,44 @@ None. ### Return value -An object containing the following values. +An object containing the following properties: - `usbVendorId` - - : If the port is part of a USB device, an unsigned short integer that identifies a USB device vendor, otherwise `undefined`. + - : If the port is part of a USB device, this property is an unsigned short integer that identifies the device's vendor. If not, it is `undefined`. - `usbProductId` - - : If the port is part of a USB device, an unsigned short integer that identifies a USB device, otherwise `undefined`. + - : If the port is part of a USB device, this property is an unsigned short integer that identifies the USB device. If not, it is `undefined`. +- `bluetoothServiceClassId` + - : If the port is a Bluetooth RFCOMM service, this property is an unsigned long integer or string representing the device's Bluetooth service class ID. If not, it is `undefined`. + +## Example + +This snippet calls the {{domxref("Serial.requestPort()")}} method when a ` +``` + +```js +const connectBtn = document.getElementById("connect"); + +// Filter for devices with the Arduino Uno USB Vendor/Product IDs +const filters = [ + { usbVendorId: 0x2341, usbProductId: 0x0043 }, + { usbVendorId: 0x2341, usbProductId: 0x0001 } +]; + +connectBtn.addEventListener("click", () => { + try { + // Prompt the user to select an Arduino Uno device + const port = await navigator.serial.requestPort({ filters }); + + // Return the device's identifying info + const { usbProductId, usbVendorId } = port.getInfo(); + } catch (e) { + // The user didn't select a device + } +}); +``` ## Specifications diff --git a/files/en-us/web/api/serialport/index.md b/files/en-us/web/api/serialport/index.md index 898f57717df3ddb..a0f6a0b583c8fbd 100644 --- a/files/en-us/web/api/serialport/index.md +++ b/files/en-us/web/api/serialport/index.md @@ -27,9 +27,9 @@ Instances of this interface may be obtained by calling methods of the {{domxref( ## Instance methods - {{domxref("SerialPort.forget()")}} {{Experimental_Inline}} - - : Returns a {{jsxref("Promise")}} that resolves when the port closes and is forgotten. + - : Returns a {{jsxref("Promise")}} that resolves when access to the serial port is revoked. In real terms, calling this closes the connection, forgets the device, and resets the permission. - {{domxref("SerialPort.getInfo()")}} {{Experimental_Inline}} - - : Returns an object containing properties of the port. + - : Returns an object containing identifying information for the device available via the port. - {{domxref("SerialPort.open()")}} {{Experimental_Inline}} - : Returns a {{jsxref("Promise")}} that resolves when the port is opened. By default the port is opened with 8 data bits, 1 stop bit and no parity checking. - {{domxref("SerialPort.setSignals()")}} {{Experimental_Inline}} diff --git a/files/en-us/web/api/web_serial_api/index.md b/files/en-us/web/api/web_serial_api/index.md index e6125ec3184be50..673760b42e9ba9c 100644 --- a/files/en-us/web/api/web_serial_api/index.md +++ b/files/en-us/web/api/web_serial_api/index.md @@ -31,6 +31,11 @@ Examples of serial devices include 3D printers, and microcontrollers such as the - {{domxref("WorkerNavigator.serial")}} {{ReadOnlyInline}} {{Experimental_Inline}} - : Returns a {{domxref("Serial")}} object, which represents the entry point into the Web Serial API to enable the control of serial ports. +## HTTP headers + +- {{httpheader("Permissions-Policy")}} {{httpheader('Permissions-Policy/serial','serial')}} directive + - : Controls whether the current document is allowed to use the Web Serial API to communicate with serial devices, either directly connected via a serial port, or via USB or Bluetooth devices emulating a serial port. + ## Examples The following examples demonstrate some of the functionality provided by the Web Serial API. From 85c9bb8d99e26b11a6893fe4f8920984090b781e Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Fri, 29 Nov 2024 13:14:45 +0100 Subject: [PATCH 2/3] Fixes for beaufortfrancois and wbamberg review comments --- files/en-us/web/api/serial/getports/index.md | 2 +- .../en-us/web/api/serial/requestport/index.md | 35 ++++++++++++-- files/en-us/web/api/serialport/close/index.md | 48 ++++++++++++++++++- .../en-us/web/api/serialport/forget/index.md | 7 +-- files/en-us/web/api/serialport/index.md | 2 +- 5 files changed, 82 insertions(+), 12 deletions(-) diff --git a/files/en-us/web/api/serial/getports/index.md b/files/en-us/web/api/serial/getports/index.md index 4e494dba9890791..3cd0d2f4a3f3b25 100644 --- a/files/en-us/web/api/serial/getports/index.md +++ b/files/en-us/web/api/serial/getports/index.md @@ -29,7 +29,7 @@ A {{jsxref("Promise")}} that resolves with an array of {{domxref("SerialPort")}} ### Exceptions - `SecurityError` {{domxref("DOMException")}} - - : The returned `Promise` rejects with this error if: + - : The returned `Promise` rejects with this error in either of the following situations: - A {{httpheader('Permissions-Policy/serial','serial')}} [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) blocks the use of this feature. - A user permission prompt was denied. diff --git a/files/en-us/web/api/serial/requestport/index.md b/files/en-us/web/api/serial/requestport/index.md index 474dbbb115d9f31..e4f585490f5da8e 100644 --- a/files/en-us/web/api/serial/requestport/index.md +++ b/files/en-us/web/api/serial/requestport/index.md @@ -34,13 +34,13 @@ requestPort(options) - `filters` {{optional_inline}} - : A list of objects containing vendor, product, or Bluetooth service class IDs used to filter the specific device types made available for the user to request a connection to. If no filters are specified, the user is presented with a list of every available device to choose from. Filters can contain the following values: - `bluetoothServiceClassId` {{optional_inline}} - - : An unsigned long integer or string representing a Bluetooth service class ID. This can be a 16- or 32-bit UUID aliase, any valid UUID, or a valid name from a GATT assigned services key. + - : An unsigned long integer or string representing a Bluetooth service class ID. This can be a 16- or 32-bit UUID alias, any valid UUID, or a valid name from a [GATT assigned services key](https://github.com/WebBluetoothCG/registries/blob/master/gatt_assigned_services.txt). - `usbVendorId` {{optional_inline}} - : An unsigned short integer that identifies a USB device vendor. The [USB Implementors Forum](https://www.usb.org/) assigns IDs to specific vendors. - `usbProductId` {{optional_inline}} - : An unsigned short integer that identifies a USB device. Each vendor assigns IDs to its products. - `allowedBluetoothServiceClassIds` {{optional_inline}} - - : A list of unsigned long integers and/or strings representing Bluetooth service class IDs. Bluetooth ports with custom service class IDs are excluded from the list of ports presented to the user unless the service class ID is included in this list. + - : A list of unsigned long integers and/or strings representing Bluetooth service class IDs. Bluetooth ports with custom service class IDs are excluded from the list of ports presented to the user unless the service class ID is included in this list. This is true whether you filter the list or not. ### Return value @@ -49,7 +49,7 @@ A {{jsxref("Promise")}} that resolves with an instance of {{domxref("SerialPort" ### Exceptions - `SecurityError` {{domxref("DOMException")}} - - : The returned `Promise` rejects with this error if: + - : The returned `Promise` rejects with this error in either of the following situations: - A {{httpheader('Permissions-Policy/serial','serial')}} [Permissions Policy](/en-US/docs/Web/HTTP/Permissions_Policy) blocks the use of this feature. - A user permission prompt was denied. - `NotFoundError` {{domxref("DOMException")}} @@ -93,6 +93,35 @@ connectBtn.addEventListener("click", () => { }); ``` +### Allow the user to select custom RFCOMM-based services + +Although most devices expose SPP-based communication through the standardized Bluetooth Classic Serial Port Profile, some use custom RFCOMM-based services. These devices have a Service Class ID that is not in the standard Bluetooth UUID range. + +You need to pass the `allowedBluetoothServiceClassIds` list to `requestPort()` to access these custom RFCOMM-based services: + +```js +const myBluetoothServiceUuid = "01234567-89ab-cdef-0123-456789abcdef"; + +// Prompt user to select any serial port +// Access to the custom Bluetooth RFCOMM service above will be allowed +const port = await navigator.serial.requestPort({ + allowedBluetoothServiceClassIds: [myBluetoothServiceUuid], +}); +``` + +You can also use the `bluetoothServiceClassIdfilter` key when calling `requestPort()` to prompt the user with a list of filtered Bluetooth serial ports identified by Service Class IDs: + +```js +const myBluetoothServiceUuid = "01234567-89ab-cdef-0123-456789abcdef"; + +// Prompt the user to select Bluetooth serial ports with +// the custom Bluetooth RFCOMM service above. +const port = await navigator.serial.requestPort({ + allowedBluetoothServiceClassIds: [myBluetoothServiceUuid], + filters: [{ bluetoothServiceClassId: myBluetoothServiceUuid }], +}); +``` + ## Specifications {{Specifications}} diff --git a/files/en-us/web/api/serialport/close/index.md b/files/en-us/web/api/serialport/close/index.md index 86195fe70814363..97fe9d24c6668a2 100644 --- a/files/en-us/web/api/serialport/close/index.md +++ b/files/en-us/web/api/serialport/close/index.md @@ -14,7 +14,53 @@ The **`SerialPort.close()`** method of the {{domxref("SerialPort")}} interface r ## Description -`close()` closes the serial port if previously-locked {{domxref("SerialPort.readable")}} and {{domxref("SerialPort.writable")}} members are unlocked, meaning the `releaseLock()` methods have been called for their respective reader and writer. However, in some cases it is not that simple, for example when continuously reading data from a serial device using a loop. See [Close a serial port](https://developer.chrome.com/docs/capabilities/serial#close-port) for more guidance. +`close()` closes the serial port if previously-locked {{domxref("SerialPort.readable")}} and {{domxref("SerialPort.writable")}} members are unlocked, meaning the `releaseLock()` methods have been called for their respective reader and writer. + +However, when continuously reading data from a serial device using a loop, the associated [readable stream](/en-US/docs/Web/API/ReadableStream) will always be locked until the [reader](/en-US/docs/Web/API/ReadableStreamDefaultReader) encounters an error. In this case, calling [`reader.cancel()`](/en-US/docs/Web/API/ReadableStreamDefaultReader/cancel) will force [`reader.read()`](/en-US/docs/Web/API/ReadableStreamDefaultReader/read) to resolve immediately with `{ value: undefined, done: true }` allowing the loop to call [`reader.releaseLock()`](/en-US/docs/Web/API/ReadableStreamDefaultReader/releaseLock). + +```js +// Without transform streams. + +let keepReading = true; +let reader; + +async function readUntilClosed() { + while (port.readable && keepReading) { + reader = port.readable.getReader(); + try { + while (true) { + const { value, done } = await reader.read(); + if (done) { + // reader.cancel() has been called. + break; + } + // value is a Uint8Array. + console.log(value); + } + } catch (error) { + // Handle error... + } finally { + // Allow the serial port to be closed later. + reader.releaseLock(); + } + } + + await port.close(); +} + +const closedPromise = readUntilClosed(); + +document.querySelector("button").addEventListener("click", async () => { + // User clicked a button to close the serial port. + keepReading = false; + // Force reader.read() to resolve immediately and subsequently + // call reader.releaseLock() in the loop example above. + reader.cancel(); + await closedPromise; +}); +``` + +Closing a serial port is more complicated when using [transform streams](/en-US/docs/Web/API/TransformStream). See [Close a serial port](https://developer.chrome.com/docs/capabilities/serial#close-port) for guidance. ## Syntax diff --git a/files/en-us/web/api/serialport/forget/index.md b/files/en-us/web/api/serialport/forget/index.md index 4f648568f222b04..a253073cd683d92 100644 --- a/files/en-us/web/api/serialport/forget/index.md +++ b/files/en-us/web/api/serialport/forget/index.md @@ -14,12 +14,7 @@ The **`SerialPort.forget()`** method of the {{domxref("SerialPort")}} interface ## Description -A website can clean up permissions to access a serial port it is no longer interested in retaining by calling `SerialPort.forget()`. In real terms, calling this closes the connection, forgets the device, and resets the permission. - -```js -// Voluntarily revoke access to this serial port -await port.forget(); -``` +A website can clean up permissions to access a serial port it is no longer interested in retaining by calling `SerialPort.forget()`. Calling this "forgets" the device, resetting any previously-set permissions so the calling site can no longer communicate with the port. For example, for an educational web application used on a shared computer with many devices, a large number of accumulated user-generated permissions creates a poor user experience. diff --git a/files/en-us/web/api/serialport/index.md b/files/en-us/web/api/serialport/index.md index a0f6a0b583c8fbd..da9b1520fae2d74 100644 --- a/files/en-us/web/api/serialport/index.md +++ b/files/en-us/web/api/serialport/index.md @@ -27,7 +27,7 @@ Instances of this interface may be obtained by calling methods of the {{domxref( ## Instance methods - {{domxref("SerialPort.forget()")}} {{Experimental_Inline}} - - : Returns a {{jsxref("Promise")}} that resolves when access to the serial port is revoked. In real terms, calling this closes the connection, forgets the device, and resets the permission. + - : Returns a {{jsxref("Promise")}} that resolves when access to the serial port is revoked. Calling this "forgets" the device, resetting any previously-set permissions so the calling site can no longer communicate with the port. - {{domxref("SerialPort.getInfo()")}} {{Experimental_Inline}} - : Returns an object containing identifying information for the device available via the port. - {{domxref("SerialPort.open()")}} {{Experimental_Inline}} From 551275b0298f130067611a81fbe5d06c3bfe9317 Mon Sep 17 00:00:00 2001 From: Chris Mills Date: Mon, 2 Dec 2024 10:15:28 +0000 Subject: [PATCH 3/3] Update files/en-us/web/api/serial/requestport/index.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: François Beaufort --- files/en-us/web/api/serial/requestport/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/files/en-us/web/api/serial/requestport/index.md b/files/en-us/web/api/serial/requestport/index.md index e4f585490f5da8e..59773fc8ad196b6 100644 --- a/files/en-us/web/api/serial/requestport/index.md +++ b/files/en-us/web/api/serial/requestport/index.md @@ -109,7 +109,7 @@ const port = await navigator.serial.requestPort({ }); ``` -You can also use the `bluetoothServiceClassIdfilter` key when calling `requestPort()` to prompt the user with a list of filtered Bluetooth serial ports identified by Service Class IDs: +You can also use the `bluetoothServiceClassId` filter key when calling `requestPort()` to prompt the user with a list of filtered Bluetooth serial ports identified by Service Class IDs: ```js const myBluetoothServiceUuid = "01234567-89ab-cdef-0123-456789abcdef";