Web Serial API

リビングドキュメント

ドラフト コミュニティグループ報告

最新の公開版:
なし
最新の編集者ドラフト:
https://wicg.github.io/serial/
編集者:
GHのコントリビューターを見る
フィードバック:
GitHub wicg/serial (プルリクエスト, 新しい issue, 未解決の issue)

要約

Serial API は、Webサイトがスクリプトを通じてシリアルデバイスからの読み書きを可能にする方法を提供します。このようなAPIは、ドキュメントがマイコン、3Dプリンターや他のシリアルデバイスなどの機器と通信できるようにすることで、Webと物理世界を繋ぎます。また、解説ドキュメントもあります。

この文書のステータス

本仕様書は Web Platform Incubator Community Group により発行されました。これはW3C標準でもなく、W3C Standards Track上のものでもありません。 W3C Community Contributor License Agreement (CLA) の下では限定的なオプトアウトやその他の条件があることにご注意ください。 W3C Community and Business Groups について詳しくはリンクをご参照ください。

本仕様は作業中のドラフトです。全ての貢献を歓迎します。

本仕様について議論する場合はGitHub Issuesを推奨します。

1. Navigator インターフェイスの拡張

WebIDL[Exposed=Window, SecureContext]
partial interface Navigator {
  [SameObject] readonly attribute Serial serial;
};

1.1 serial 属性

取得時、serial属性は常に同じSerialオブジェクトのインスタンスを返します。

2. WorkerNavigator インターフェイスの拡張

WebIDL[Exposed=DedicatedWorker, SecureContext]
partial interface WorkerNavigator {
  [SameObject] readonly attribute Serial serial;
};

2.1 serial 属性

取得時、serial属性は常に同じSerialオブジェクトのインスタンスを返します。

3. Serial インターフェイス

WebIDL[Exposed=(DedicatedWorker, Window), SecureContext]
interface Serial : EventTarget {
  attribute EventHandler onconnect;
  attribute EventHandler ondisconnect;
  Promise<sequence<SerialPort>> getPorts();
  [Exposed=Window] Promise<SerialPort> requestPort(optional SerialPortRequestOptions options = {});
};

3.1 requestPort() メソッド

requestPort()メソッドの手順は以下のとおりです:

  1. promise新しいpromiseとして作成する。
  2. this関連グローバルオブジェクト関連付けられたDocument使用許可のある "serial" ポリシー制御機能でない場合、 reject promiseに"SecurityError" DOMExceptionで返し、終了。
  3. 関連グローバルオブジェクトthisトランジェントアクティベーションがなければ、reject promiseに "SecurityError" DOMExceptionで返し、終了。
  4. もしoptions["filters"]が存在する場合、すべてのfilterについて以下を実行する:
    1. もしfilter["bluetoothServiceClassId"] が存在する場合:
      1. filter["usbVendorId"] が存在する場合、 reject promiseTypeErrorで返し、終了。
      2. filter["usbProductId"] が存在する場合、 reject promiseTypeErrorで返し、終了。
    2. もしfilter["usbVendorId"]が存在しない場合、 reject promiseTypeErrorで返し、終了。
      このチェックはSerialPortFilterが空であることはできず、 usbProductIdを指定する場合は usbVendorIdも指定する必要があるという組み合わせルールを実装しています。
  5. 並列で以下を実行:
    1. allPortsを空のリストとして用意する。
    2. システムに登録済みBluetoothデバイスについてデバイスに対し:
      1. デバイスがサポートする BluetoothServiceUUID uuidごとに:
        1. uuidブロックされたBluetoothサービスクラスUUIDでない場合:
    3. 利用可能な非Bluetoothシリアルポートについて:
      1. portを該当ポートを表すSerialPortとして生成。
      2. それをallPorts追加
    4. ユーザーへ、allPortsリストのうちoptions["filters"]のいずれかのフィルターに マッチするもののみ(あるいはフィルターがなければすべて)を選ばせるプロンプトを表示する。
    5. ユーザーがポートを選択しなかった場合は、グローバルタスクをキューし、関連グローバルオブジェクトserial port task sourcereject promiseに "NotFoundError" DOMException で返し、以降中断。
    6. ユーザーが選んだポートを示すportSerialPortとして用意。
    7. グローバルタスクをキューし、 関連グローバルオブジェクトserial port task sourceresolve promiseportを渡す。
  6. promise を返す。

シリアルポートは、利用可能とは、有線の場合は物理的にシステムに接続されているポート、無線の場合はデバイスがシステムに登録されているポートを指します。

3.1.1 SerialPortRequestOptions 辞書

WebIDLdictionary SerialPortRequestOptions {
  sequence<SerialPortFilter> filters;
  sequence<BluetoothServiceUUID> allowedBluetoothServiceClassIds;
};
filters メンバー
シリアルポートのフィルター
allowedBluetoothServiceClassIds メンバー
BluetoothServiceUUID 型のBluetoothサービスクラスIDのリスト。BluetoothポートがカスタムサービスクラスIDを持つ場合は、このリストに含まれていない限り、ユーザーへの提示リストから除外されます。

3.1.2 SerialPortFilter 辞書

WebIDLdictionary SerialPortFilter {
  unsigned short usbVendorId;
  unsigned short usbProductId;
  BluetoothServiceUUID bluetoothServiceClassId;
};
usbVendorId メンバー
USBベンダーID
usbProductId メンバー
USBプロダクトID
bluetoothServiceClassId メンバー
BluetoothサービスクラスID

シリアルポートportがフィルターfilterマッチする条件は以下です:

  1. infoとしてport.getInfo() コールの結果を得る。
  2. もしfilter["bluetoothServiceClassId"]が 存在する場合:
    1. そのシリアルポートがBluetoothデバイスに属さなければ、falseを返す。
    2. もしフィルターのbluetoothServiceClassId値がinfo["bluetoothServiceClassId"]と等しければ、trueを返す。
    3. それ以外はfalseを返す。
  3. もしfilter["usbVendorId"]が存在しない場合、trueを返す。
  4. シリアルポートがUSBデバイスでない場合はfalseを返す。
  5. info["usbVendorId"]が フィルターのusbVendorId値と等しくなければfalseを返す。
  6. もしfilter["usbProductId"]が 存在しない場合はtrueを返す。
  7. info["usbProductId"]が フィルターのusbProductIdと等しくなければfalseを返す。
  8. それ以外はtrueを返す。

シリアルポートportは、シーケンス内の SerialPortFilterのいずれかにマッチする条件は下記:

  1. filterについて下記を実施:
    1. もしportマッチするならtrueを返す。
  2. falseを返す。

3.2 getPorts() メソッド

getPorts()メソッドの手順は以下の通りです:

  1. promise新しいpromiseとして作成する。
  2. this関連グローバルオブジェクト関連付けられたDocument使用許可のある "serial"というポリシー制御機能でない場合、 reject promiseに"SecurityError" DOMExceptionで返し、終了。
  3. 並列で以下を実行:
    1. availablePortsを、ユーザーがrequestPort()の実行でサイトにアクセス許可を付与した利用可能なシリアルポートとする。
    2. portsを、availablePorts内のSerialPort一覧とする。
    3. グローバルタスクをキューし、関連グローバルオブジェクトserial port task sourceresolve promiseportsを渡す。
  4. promise を返す。

3.3 onconnect 属性

onconnectイベントハンドラーIDL属性であり、 connectイベントタイプ用です。

3.4 ondisconnect 属性

ondisconnectイベントハンドラーIDL属性であり、 disconnectイベントタイプ用です。

4. SerialPort インターフェイス

WebIDL[Exposed=(DedicatedWorker,Window), SecureContext]
interface SerialPort : EventTarget {
  attribute EventHandler onconnect;
  attribute EventHandler ondisconnect;
  readonly attribute boolean connected;
  readonly attribute ReadableStream readable;
  readonly attribute WritableStream writable;

  SerialPortInfo getInfo();

  Promise<undefined> open(SerialOptions options);
  Promise<undefined> setSignals(optional SerialOutputSignals signals = {});
  Promise<SerialInputSignals> getSignals();
  Promise<undefined> close();
  Promise<undefined> forget();
};

このインターフェイスのメソッドは、通常非同期に完了し、シリアルポートタスクソース上で作業をキューします。

SerialPort親を取得するアルゴリズムは、そのSerialインスタンスを返します。このインスタンスはSerialPort関連グローバルオブジェクトNavigator オブジェクトのserialゲッターで返されるものと同じです。

SerialPortのインスタンスは、以下の表で説明される内部スロットを持ちます。

内部スロット 初期値 説明(非規範的)
[[state]] "closed" SerialPortの動作状態を追跡します
[[bufferSize]] undefined 送受信でバッファするデータ量
[[connected]] false シリアルポートの論理的接続状態を示すフラグ
[[readable]] null ポートからデータを受信するReadableStream
[[readFatal]] false ポートで重大な読み取りエラーが発生したことを示すフラグ
[[writable]] null ポートへデータを送信するWritableStream
[[writeFatal]] false ポートで重大な書き込みエラーが発生したことを示すフラグ
[[pendingClosePromise]] null Promisereadablewritableのクローズ待機などに利用

4.1 onconnect 属性

onconnectイベントハンドラーIDL属性です。 connectイベント型用です。

ユーザーがrequestPort()の呼び出しでサイトへのアクセスを許可したシリアルポートが 論理的に接続された場合、以下の手順を実行します:

  1. portとして該当のSerialPortを用意する。
  2. port.[[connected]]trueに設定。
  3. イベントconnectportで発火し、そのbubbles属性をtrueで初期化する。

シリアルポートは論理的に接続とは、有線シリアルポートの場合は物理的に接続されているとき、無線の場合はシステムが該当デバイスにアクティブ接続(例: Bluetooth L2CAPチャネルが開いている)を持っているときです。

4.2 ondisconnect 属性

ondisconnectイベントハンドラーIDL属性であり、 disconnectイベント型用です。

ユーザーがrequestPort()の呼び出しでサイトへのアクセスを許可したシリアルポートが 論理的に接続でなくなった場合、以下の手順を実行します:

  1. portとして該当のSerialPortを用意する。
  2. port.[[connected]]falseに設定。
  3. イベントdisconnectportで発火し、そのbubbles属性をtrueで初期化する。

4.3 getInfo() メソッド

getInfo() メソッドの手順は以下の通りです:
  1. infoを空の順序付きマップとして用意する。
  2. ポートがUSBデバイスの一部の場合、以下の手順を実施する:
    1. info["usbVendorId"] にデバイスのベンダーIDを設定。
    2. info["usbProductId"] にデバイスのプロダクトIDを設定。
  3. ポートがBluetoothデバイス上のサービスである場合、以下の手順を実施する:
    1. info["bluetoothServiceClassId"] にBluetoothサービスのサービスクラスUUIDを設定
  4. infoを返す。

4.3.1 SerialPortInfo 辞書

WebIDLdictionary SerialPortInfo {
  unsigned short usbVendorId;
  unsigned short usbProductId;
  BluetoothServiceUUID bluetoothServiceClassId;
};
usbVendorId メンバー
ポートがUSBデバイスの一部である場合、このメンバーはそのデバイスの16ビットベンダーIDとなります。それ以外の場合はundefinedです。
usbProductId メンバー
ポートがUSBデバイスの一部である場合、このメンバーはそのデバイスの16ビットプロダクトIDとなります。それ以外の場合はundefinedです。
bluetoothServiceClassId メンバー
ポートがBluetoothデバイス上のサービスである場合、このメンバーはサービスクラスUUIDを含む BluetoothServiceUUID となります。それ以外の場合はundefinedです。

4.4 open() メソッド

open() メソッドの手順は以下の通りです:

  1. promise新しい promise として用意する。
  2. もし this.[[state]]"closed" 以外なら、 promise を "InvalidStateError" DOMException で reject し返す。
  3. もし options["dataBits"] が 7 または 8 でなければ、 promiseTypeError で reject し返す。
  4. もし options["stopBits"] が 1 または 2 でなければ、 promiseTypeError で reject し返す。
  5. もし options["bufferSize"] が 0 なら、 promiseTypeError で reject し返す。
  6. また、options["bufferSize"] が 実装がサポートできる値より大きい場合も、 promiseTypeError で reject し返すことができる。
  7. this.[[state]]"opening" に設定する。
  8. 並列で以下を実施:
    1. オペレーティングシステムに指示して、options で指定された(またはデフォルト値)接続パラメータで シリアルポートを開く。
    2. 何らかの理由で失敗した場合、グローバルタスクをキューし、 関連グローバルオブジェクトserial port task sourcereject promise を "NetworkError" DOMException で返して、処理を中断する。
    3. this.[[state]]"opened" に設定する。
    4. this.[[bufferSize]]options["bufferSize"] に設定する。
    5. グローバルタスクをキューし、 関連グローバルオブジェクトserial port task sourceresolve promiseundefined にする。
  9. promise を返す。

4.4.1 SerialOptions 辞書

WebIDLdictionary SerialOptions {
  [EnforceRange] required unsigned long baudRate;
  [EnforceRange] octet dataBits = 8;
  [EnforceRange] octet stopBits = 1;
  ParityType parity = "none";
  [EnforceRange] unsigned long bufferSize = 255;
  FlowControlType flowControl = "none";
};
baudRate メンバー
シリアル通信を確立する際の、正かつ0でないボーレート(通信速度)値。
baudRate はこの 辞書で唯一必須なメンバーです。他の接続パラメータには一般的なデフォルトがありますが、接続する機器に応じて正しい値を検討・機器のドキュメントで確認することが重要です。多くは一般的な値ですが、標準化されたボーレートはありません。このパラメータを必須とすることで、仕様が任意のデフォルト値を選択した場合の混乱を防ぎます。
dataBits メンバー
1フレームあたりのデータビット数。7または8。
stopBits メンバー
フレーム末尾のストップビット数。1または2。
parity メンバー
パリティモード。
bufferSize メンバー
読み書き用バッファのサイズを示す正かつ0でない値。
flowControl メンバー
フロー制御のモード。
4.4.1.1 ParityType 列挙型
WebIDLenum ParityType {
  "none",
  "even",
  "odd"
};
none
各データワードごとにパリティビットは送出されません。
even
データワード+パリティビットの合計値が偶数パリティとなります。
odd
データワード+パリティビットの合計値が奇数パリティとなります。
4.4.1.2 FlowControlType 列挙型
WebIDLenum FlowControlType {
  "none",
  "hardware"
};
none
フロー制御なし。
hardware
RTSおよびCTS信号を使用するハードウェアフロー制御を有効化。

4.5 connected 属性

connected ゲッターの手順は:

  1. this.[[connected]] を返す。

4.6 readable 属性

readable ゲッターの手順は以下の通りです:

  1. もしthis.[[readable]]null でなければ this.[[readable]] を返す。
  2. もしthis.[[state]]"opened" でなければ null を返す。
  3. もしthis.[[readFatal]]true なら null を返す。
  4. streamnew ReadableStream として生成。
  5. pullAlgorithm を以下の手順とする:
    1. desiredSizehigh water mark まで埋めるために必要なサイズ とする。対象は this.[[readable]]
    2. もしthis.[[readable]]current BYOB request view が non-null なら desiredSize を当該 view の byte length に設定。
    3. 並列で以下を実施:
      1. OSにポートから desiredSize バイト分読み込みの指示を出し(結果をbyte列bytesに格納)。
        this.[[state]]"forgotten" となる場合は「ポートが切断された」ものとして扱ってください。
      2. グローバルタスクをキュー関連グローバルオブジェクトthis を使い serial port task source で 次の処理:
        1. エラーがなければ:
          1. もしthis.[[readable]]current BYOB request view が non-null ならば、 writebytesthis.[[readable]] の current BYOB request view に書き込んだうえで view をその view に設定。
          2. そうでなければ、createUint8Arraybytesから生成。view を(this関連Realm で)。
          3. Enqueueviewthis.[[readable]] へ。
        2. バッファオーバーランの場合は errorthis.[[readable]]に "BufferOverrunError" DOMException で発生させ、handle closing the readable stream の手順を実行。
        3. ブレーク条件(break)も同上で "BreakError"。
        4. フレームエラーも同上で "FramingError"。
        5. パリティエラーも同上で "ParityError"。
        6. OSエラーは "UnknownError" DOMException で発生し handle closing the readable stream の手順。
        7. ポート切断の場合は下記:
          1. this.[[readFatal]]true に設定
          2. errorthis.[[readable]] に "NetworkError" DOMException で発生。
          3. handle closing the readable stream の手順
    4. a promise resolved with undefined を返す。

    本アルゴリズムで返すPromiseは即時resolveされ、ストリームキャンセルを妨げません。 [STREAMS]仕様ではチャンクenqueueまで再度呼び出されないとしています。

  6. cancelAlgorithm を以下の手順とする:
    1. promise新しい promiseとする。
    2. 並列で以下を実施:
      1. OSにすべての受信バッファ(ソフトウェア/ハードウェア)の中身を破棄するよう指示
      2. グローバルタスクをキュー関連グローバルオブジェクトthis を使い serial port task source で次の処理:
        1. handle closing the readable stream の手順を実行
        2. Resolve promiseundefined で。
    3. promise を返す
  7. Set up with byte reading supportstream をセットアップし pullAlgorithmpullAlgorithmcancelAlgorithmcancelAlgorithmをセット、 highWaterMarkthis.[[bufferSize]] にする。
  8. this.[[readable]]stream に設定。
  9. stream を返す。
To readableストリームのクローズ処理を行う手順は下記:
  1. this.[[readable]]null を設定。
  2. もしthis.[[writable]]null かつ this.[[pendingClosePromise]]null でなければ resolvethis.[[pendingClosePromise]]undefined で完了。

4.7 writable 属性

writable ゲッターの手順は以下の通りです:

  1. もし this.[[writable]]null でなければ this.[[writable]] を返す。
  2. もし this.[[state]]"opened" でなければ null を返す。
  3. もし this.[[writeFatal]]true なら null を返す。
  4. streamnew WritableStream として作成。
  5. signalstreamsignal とする。
  6. writeAlgorithm を、chunk に対し以下の手順とする:
    1. promise新しい promise として用意。
    2. Assert: signalaborted されていない。
    3. もし chunkBufferSource 型IDL値に 変換 できなければ、 TypeErrorpromise を reject、return。それ以外の場合はその結果を source に保存。
    4. BufferSource のコピーを取得bytes に保存。
    5. 並列で次の処理:
      1. OSにbytesを書き込む指示(または将来coalesceのため一時保存)。
        OSはこの操作をbytesを送信バッファに入れ終えたタイミングで返すこともあります(実際の送信完了前)。
        this.[[state]]"forgotten" となった場合は「ポート切断」として扱うこと。
      2. グローバルタスクをキュー関連グローバルオブジェクトthis を使い serial port task source で以下の手順:
        1. チャンクが正常に書き込まれるか蓄積保存に成功したら、resolvepromiseundefined で完了。
          [STREAMS]仕様により writeAlgorithm は前回返した Promise resolve後でないと呼ばれません。 複数チャンクを内部キューでまとめてOSへ送る実装も認められており、 パフォーマンス向上のためこのPromiseは早めにresolveできる場合があります。
        2. OSエラーの場合、 reject promise を "UnknownError" DOMException で返す。
        3. ポート切断時は下記:
          1. this.[[writeFatal]]true
          2. Reject promise を "NetworkError" DOMException で返す。
          3. handle closing the writable stream 手順を呼ぶ。
        4. もし signalaborted なら reject promisesignalabort reason で。
    6. promise を返す。
  7. abortAlgorithm を下記とする:
    1. promise新しい promiseとする。
    2. 並列で以下を実施:
      1. OSに全てのソフトウェア・ハードウェア送信バッファの中身を破棄させる。
      2. グローバルタスクをキュー関連グローバルオブジェクトthis を使い serial port task source で次の処理:
        1. handle closing the writable stream を呼ぶ。
        2. Resolve promiseundefined で。
    3. promise を返す
  8. closeAlgorithm を下記とする:
    1. promise新しい promiseとする。
    2. 並列で処理:
      1. OSにすべての送信バッファをフラッシュさせる。
      2. グローバルタスクをキュー関連グローバルオブジェクトthis を使い serial port task source で次の処理:
        1. handle closing the writable stream を呼ぶ。
        2. もし signalaborted なら reject promisesignalabort reason で。
        3. それ以外は resolve promiseundefined で。
    3. promise を返す。
  9. Set up stream writeAlgorithmwriteAlgorithm を指定し、 abortAlgorithmabortAlgorithm closeAlgorithmcloseAlgorithm highWaterMarkthis.[[bufferSize]] を、それから sizeAlgorithmはバイトカウントするアルゴリズムをセット。
  10. Addsignal に以下のabort手順を追加:
    1. OSへの書込呼び出しをどれだけデータ送信したかに関わらず速やかに返すようにする。
  11. this.[[writable]]stream にセット。
  12. stream を返す。
to writableストリームのクローズ処理は下記手順:
  1. this.[[writable]]null に設定。
  2. もしthis.[[readable]]null かつ this.[[pendingClosePromise]]null でなければ resolvethis.[[pendingClosePromise]]undefined で完了。

4.8 setSignals() メソッド

setSignals() メソッドの手順は以下の通りです:

  1. promise新しい promise として用意する。
  2. this.[[state]]"opened" でなければ、 promise を "InvalidStateError" DOMException で reject し、返す。
  3. signals の指定されたメンバーが一つも存在しなければ TypeErrorpromise を reject し返す。
  4. 並列で次を実行:
    本来は signals で指定された内容をアトミック(一度に)適用すべきですが、これを実現する手段はPOSIXやWindows APIにはないため、実装側はこの順序に依存することになります。
    1. signals["dataTerminalReady"] が存在すれば、OSに「data terminal ready(DTR)」信号をアサート(true)またはディアサート(false)を指示。
    2. signals["requestToSend"] が 存在すれば、OSに「request to send(RTS)」信号をアサートまたはディアサートを指示。
    3. signals["break"] があれば、OSに「break」信号のアサートまたはディアサートを指示。
      「break」信号は一般的に送信線を「mark」電圧で保持する帯域内信号として実装されており、その間はデータ送信が停止します。
    4. 何らかの理由でOSがこれらの信号状態変更に失敗した場合、 グローバルタスクをキューし、 関連グローバルオブジェクトserial port task sourcepromise を "NetworkError" DOMException で reject。
    5. グローバルタスクをキューし、 関連グローバルオブジェクトserial port task sourceresolve promiseundefined で完了。
  5. promise を返す。

4.8.1 SerialOutputSignals 辞書

WebIDLdictionary SerialOutputSignals {
  boolean dataTerminalReady;
  boolean requestToSend;
  boolean break;
};
dataTerminalReady
Data Terminal Ready (DTR)
requestToSend
Request To Send (RTS)
break
ブレーク

4.9 getSignals() メソッド

getSignals() メソッドの手順は以下の通りです:
  1. promise新しい promise とする。
  2. this.[[state]]"opened" でなければ promise を "InvalidStateError" DOMException で reject し返す。
  3. 並列で下記を実行:
    1. シリアルポートに接続されているデバイスがアサートしている制御信号の状態をOSに問い合わせる。
    2. 何らかの理由でOSがこれらの信号の状態取得に失敗した場合は、 グローバルタスクをキューし、 関連グローバルオブジェクトserial port task sourcepromise を "NetworkError" DOMException で reject し、処理を中断。
    3. dataCarrierDetect を「data carrier detect(DCD)」信号がデバイスでアサートされていれば true、それ以外は falseとする。
    4. clearToSend を「clear to send(CTS)」信号がアサートされていれば true、それ以外は false
    5. ringIndicator を「ring indicator(RI)」信号がアサートされていれば true、それ以外は false
    6. dataSetReady を「data set ready(DSR)」信号がアサートされていれば true、それ以外は false
    7. signals順序付きマップ «[ "dataCarrierDetect" → dataCarrierDetect, "clearToSend" → clearToSend, "ringIndicator" → ringIndicator, "dataSetReady" → dataSetReady ]» として用意。
    8. グローバルタスクをキュー関連グローバルオブジェクトserial port task sourceresolve promisesignals を渡す。
  4. promise を返す。

4.9.1 SerialInputSignals 辞書

WebIDLdictionary SerialInputSignals {
  required boolean dataCarrierDetect;
  required boolean clearToSend;
  required boolean ringIndicator;
  required boolean dataSetReady;
};
dataCarrierDetect メンバー
Data Carrier Detect (DCD)
clearToSend メンバー
Clear To Send (CTS)
ringIndicator メンバー
Ring Indicator (RI)
dataSetReady メンバー
Data Set Ready (DSR)

4.10 close() メソッド

close() メソッドの手順は以下の通りです:

  1. promise新しい promise として用意。
  2. this.[[state]]"opened" でなければ promise を "InvalidStateError" DOMException で reject し返す。
  3. cancelPromisecancelthis.[[readable]] に呼び出した結果か、 a promise resolved with undefined(もし this.[[readable]]null の場合)。
  4. abortPromiseabortthis.[[writable]] に呼び出した結果か、 a promise resolved with undefined(もし this.[[writable]]null の場合)。
  5. pendingClosePromise新しい promise として用意。
  6. もし this.[[readable]] および this.[[writable]] がともに null であれば、 resolve pendingClosePromiseundefined で完了。
  7. this.[[pendingClosePromise]]pendingClosePromise をセット。
  8. combinedPromisegetting a promise to wait for all で «cancelPromise, abortPromise, pendingClosePromise» を対象に取得。
  9. this.[[state]]"closing" に。
  10. React to combinedPromise.
  11. promise を返す。

4.11 forget() メソッド

forget() メソッドの手順は以下の通りです:

  1. ユーザーエージェントがこの操作を実施できない場合(例:管理者ポリシーで許可された場合)は、a promise resolved with undefined を返す。
  2. 並列で下記を実行:
    1. this.[[state]]"forgetting" にする。
    2. ユーザーがrequestPort()の結果としてサイトに許可したシリアルポート一覧から this を削除する。
    3. this.[[state]]"forgotten" にする。
    4. グローバルタスクをキュー関連グローバルオブジェクトserial port task sourceresolve promiseundefined で実施。
  3. promise を返す。

5. ブロックリスト

この仕様は https://github.com/WICG/serial リポジトリ内のブロックリストファイルに依存しており、ウェブサイトがアクセスできるポートの集合を制限します。

URL urlBluetoothサービスクラスIDブロックリストのパース の結果は、カスタムサービスIDを表す リスト 型の UUID 値です。

シリアルポートプロファイル サービスクラスID は 値 "00001101-0000-1000-8000-00805f9b34fb" を持った BluetoothServiceUUID です。

{{BluetoothServiceUUID} の serviceUuidブロックされたBluetoothサービスクラスUUID であるとは、以下の手順で true を返す場合です:

  1. uuidBluetoothUUID.getService()serviceUuid を渡して呼び出した結果とします。
  2. blocklistBluetoothサービスクラスIDブロックリストのパースhttps://github.com/WICG/serial/blob/main/blocklist.txt で実施した結果とします。
  3. blocklistcontains uuid の場合、 true を返します。
  4. uuidis シリアルポートプロファイル サービスクラスID なら false を返す。
  5. uuidends with "-0000-1000-8000-00805f9b34fb" であれば true を返す。
  6. それ以外の場合は false を返します。

6. 統合

6.1 パーミッションポリシー

この仕様は、serial 属性で Navigator オブジェクトに公開されたメソッドを利用できるか制御する機能を定義します。

この機能のフィーチャ名は "serial" です。

この機能の デフォルト許可リスト'self' です。

7. セキュリティに関する考慮事項

このセクションは規範的ではありません。

このAPIは [WEB-BLUETOOTH] および [WEBUSB] と類似のセキュリティリスクがあり、それらの教訓がここにも適用されます。主な脅威は次の通りです: これらへの主要な対策は requestPort() パターンであり、これはユーザー操作を要し、かつ一度にひとつのデバイスだけのアクセス許可しか付与できません。このためサイトは接続デバイスを列挙して脆弱性を調べることができず、ユーザーが明示的に許可する必要があります。実装は、現在通信中であることやいつでも権限を取り消せるUIを視覚的に示すこともできます。

この仕様はネットワークベースの攻撃者によるコード注入を防ぐため、セキュアコンテキストから配信されることを要求します。これは、ユーザーがアクセス許可を判断する際、正しいサイトのアイデンティティを見せるためです。また、クロスオリジンのiframeで利用を許可するにはトップレベルドキュメントによる [PERMISSIONS-POLICY] でのopt-inも必要です。[CSP3]と組み合わせることで、これらの仕組みが悪意のあるコード注入攻撃の対策となります。

残る懸念は、ユーザーが悪意あるサイトに騙されてデバイスのアクセスを許可してしまうフィッシング攻撃です。これにより、デバイス本来の機能を用いた攻撃や、デバイスに悪意のあるファームウェアを仕込んでホストコンピュータ自体を攻撃することができます。ホストソフトは接続デバイスからの入力バリデーションが不十分である場合、攻撃されやすくなります。この分野のセキュリティ研究により、多くのソフトウェアベンダは接続デバイスを信頼すべきでないことを認識するようになっています。

この種の攻撃を完全に防ぐ仕組みはありません。ページからデバイスに送信されるデータは「不透明なバイト列」に過ぎないためです。特定のデータタイプを送信不可とする努力は、たいていメーカーが意図的にそれを送らせるための回避策を講じるなどして無効化されます。

ユーザーエージェントは更に機器へのアクセス制御手段を提供できます:

[WEB-BLUETOOTH], [WEBUSB] 各実装はこれらの手法を試みていますが、効果には限界があります。第一に、あるデバイスが exploitable かどうかの判断が難しいためです。たとえばこのAPIでは、教育・ホビー向け開発ボードへファーム書き込みが可能です。これらは一般的にファーム署名検証がないため簡単に悪意のファーム焼きができ、明らかにexploitableだが、利用ケースを阻害すべきではありません。

また、USBやBluetoothはプロトコル上メタデータを取得できるため、脆弱なデバイスリストの維持運用が現実的ですが、DB-25/DE-9/RJ-45等「純粋」なシリアルポートやUSB/Bluetooth-シリアル変換器といった一般的なものには識別可能なメタデータがありません。このため、こうしたデバイスを個別にブロックすることは不可能です。

8. プライバシーに関する考慮事項

このセクションは規範的ではありません。

シリアルポートおよびシリアルデバイスには2種類の機微な情報が含まれます。USB/Bluetoothデバイスの場合はベンダー/プロダクトID(=メーカー・型番)やシリアルナンバーやMACアドレスなどの識別情報、またシリアルコマンドで得られる機器固有ID等があります。加えて、機器自体が独自の個人情報を格納している場合もあります。

デバイス許可管理を行うため、実装はUSBベンダーID・プロダクトID・シリアル番号といった情報をユーザー設定ファイルに保存して、許可済みデバイスを一意に識別するために利用することになります。これら情報はサイトと直接共有されることはなく、許可解除やサイトデータ削除時にクリアされます。

ページがデバイスアクセス権を得た後であれば、ページは機器が保持している他の個人情報を含む多数の情報にアクセスできる可能性があります。7. セキュリティに関する考慮事項 で説明した通り、ページからこうした情報へのアクセスを完全に阻止することは現実的でも望ましくもありません。

実装は利用者がアクセス許可デバイスを完全にコントロールできること、かつ明示的なユーザー操作なしでデバイス権限が与えられないことを保証すべきです。これは requestPort() メソッドの意図です。これによりサイトは接続中全デバイスの列挙や情報収集ができず、ファイル選択UIと同様にユーザーが選択したポートやデバイス・ディレクトリだけをサイトが知ることになります。サイト利用中にユーザーに権限利用中である旨を通知(タブやアドレスバーのアイコン表示等)しても良いでしょう。

「プライベート」または「シークレット」ブラウジングモードのある実装は、通常のプロファイルで設定したデバイス権限が当該セッションに持ち越されず、そのセッション中に付与された権限も終了時には保存されないことを保証すべきです。こうしたセッションでデバイス権限を付与する際は、手動で個人情報を入力する場合と同様、デバイス識別子や個性情報を経由してセッション間ID特定につながる可能性があることを警告しても良いでしょう。

このAPIで許可を与えることが従来のWebセキュリティモデルの分離境界を破る側面を持つ場合があるため、利用者がAPIの力量を十分理解していない場合は驚くことがあります。セキュリティUIやドキュメントでは「サイトにデバイス権限を与える=そのデバイスや中身全てに完全アクセスできる」ことを必ず明示すべきです。

9. 適合性

規範的でない旨が明記されている節以外にも、この仕様で記載されたオーサリングガイド・図・例・注記はすべて規範的なものではありません。それ以外のすべては規範的です。

A. 謝辞

このドキュメントの作成に以下の方々が貢献しました。

B. 参考文献

B.1 規範的な参考文献

[dom]
DOM Standard. Anne van Kesteren. WHATWG. Living Standard. URL: https://dom.spec.whatwg.org/
[html]
HTML Standard. Anne van Kesteren; Domenic Denicola; Dominic Farolino; Ian Hickson; Philip Jägenstedt; Simon Pieters. WHATWG. Living Standard. URL: https://html.spec.whatwg.org/multipage/
[infra]
Infra Standard. Anne van Kesteren; Domenic Denicola. WHATWG. Living Standard. URL: https://infra.spec.whatwg.org/
[PERMISSIONS-POLICY]
Permissions Policy. Ian Clelland. W3C. 18 July 2025. W3C Working Draft. URL: https://www.w3.org/TR/permissions-policy-1/
[STREAMS]
Streams Standard. Adam Rice; Domenic Denicola; Mattias Buelens; 吉野剛史 (Takeshi Yoshino). WHATWG. Living Standard. URL: https://streams.spec.whatwg.org/
[WEB-BLUETOOTH]
Web Bluetooth. Jeffrey Yasskin. W3C Web Bluetooth Community Group. Draft Community Group Report. URL: https://webbluetoothcg.github.io/web-bluetooth/
[WEBIDL]
Web IDL Standard. Edgar Chen; Timothy Gu. WHATWG. Living Standard. URL: https://webidl.spec.whatwg.org/

B.2 参考情報

[CSP3]
Content Security Policy Level 3. Mike West; Antonio Sartori. W3C. 11 July 2025. W3C Working Draft. URL: https://www.w3.org/TR/CSP3/
[WEBUSB]
WebUSB API. W3C. Draft Community Group Report. URL: https://wicg.github.io/webusb/