sesame-kit 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (170) hide show
  1. package/LICENSE +26 -0
  2. package/LICENSE.biz3 +21 -0
  3. package/README.ja.md +225 -0
  4. package/README.md +222 -0
  5. package/bin/sesame.js +8 -0
  6. package/clients/js/sesame-client.mjs +208 -0
  7. package/clients/python/pyproject.toml +5 -0
  8. package/clients/python/sesame_client.py +323 -0
  9. package/clients/python/setup.cfg +11 -0
  10. package/docs/architecture.ja.md +132 -0
  11. package/docs/architecture.md +105 -0
  12. package/docs/commands.ja.md +316 -0
  13. package/docs/commands.md +308 -0
  14. package/docs/library.ja.md +152 -0
  15. package/docs/library.md +152 -0
  16. package/docs/migration.ja.md +13 -0
  17. package/docs/migration.md +13 -0
  18. package/package.json +114 -0
  19. package/src/access.js +375 -0
  20. package/src/account.js +36 -0
  21. package/src/auth.js +248 -0
  22. package/src/ble/devicemodel.js +164 -0
  23. package/src/ble/index.js +185 -0
  24. package/src/ble/protocol.js +319 -0
  25. package/src/ble/session.js +235 -0
  26. package/src/ble/transport.js +279 -0
  27. package/src/cli/access.js +373 -0
  28. package/src/cli/company.js +104 -0
  29. package/src/cli/iot.js +400 -0
  30. package/src/cli/org.js +788 -0
  31. package/src/cli/presetir.js +188 -0
  32. package/src/cli/schedule.js +83 -0
  33. package/src/cli/serve.js +308 -0
  34. package/src/cli.js +1815 -0
  35. package/src/client.js +957 -0
  36. package/src/company.js +147 -0
  37. package/src/config.js +575 -0
  38. package/src/crypto.js +162 -0
  39. package/src/devices.js +228 -0
  40. package/src/index.js +55 -0
  41. package/src/iot.js +513 -0
  42. package/src/ir.js +341 -0
  43. package/src/itemcodes.js +29 -0
  44. package/src/lock.js +194 -0
  45. package/src/org.js +803 -0
  46. package/src/paths.js +30 -0
  47. package/src/presetir.js +525 -0
  48. package/src/prompts.js +74 -0
  49. package/src/schedule.js +108 -0
  50. package/src/serve/daemon.js +251 -0
  51. package/src/serve/framing/grpc.js +145 -0
  52. package/src/serve/framing/http.js +144 -0
  53. package/src/serve/framing/ndjson.js +75 -0
  54. package/src/serve/framing/socket.js +73 -0
  55. package/src/serve/framing/stdio.js +28 -0
  56. package/src/serve/framing/token.js +36 -0
  57. package/src/serve/framing/ws.js +56 -0
  58. package/src/serve/grpc-methods.generated.json +378 -0
  59. package/src/serve/jsonrpc.js +164 -0
  60. package/src/serve/registry.js +226 -0
  61. package/src/serve/rpc-params.generated.json +1746 -0
  62. package/src/serve/sesame.proto +470 -0
  63. package/src/session-ui.js +181 -0
  64. package/src/sharekey.js +130 -0
  65. package/src/tokens.js +53 -0
  66. package/src/transport.js +634 -0
  67. package/src/util.js +26 -0
  68. package/types/access.d.ts +193 -0
  69. package/types/access.d.ts.map +1 -0
  70. package/types/account.d.ts +13 -0
  71. package/types/account.d.ts.map +1 -0
  72. package/types/auth.d.ts +80 -0
  73. package/types/auth.d.ts.map +1 -0
  74. package/types/ble/devicemodel.d.ts +212 -0
  75. package/types/ble/devicemodel.d.ts.map +1 -0
  76. package/types/ble/index.d.ts +160 -0
  77. package/types/ble/index.d.ts.map +1 -0
  78. package/types/ble/protocol.d.ts +201 -0
  79. package/types/ble/protocol.d.ts.map +1 -0
  80. package/types/ble/session.d.ts +129 -0
  81. package/types/ble/session.d.ts.map +1 -0
  82. package/types/ble/transport.d.ts +67 -0
  83. package/types/ble/transport.d.ts.map +1 -0
  84. package/types/cli/access.d.ts +6 -0
  85. package/types/cli/access.d.ts.map +1 -0
  86. package/types/cli/company.d.ts +6 -0
  87. package/types/cli/company.d.ts.map +1 -0
  88. package/types/cli/iot.d.ts +6 -0
  89. package/types/cli/iot.d.ts.map +1 -0
  90. package/types/cli/org.d.ts +6 -0
  91. package/types/cli/org.d.ts.map +1 -0
  92. package/types/cli/presetir.d.ts +6 -0
  93. package/types/cli/presetir.d.ts.map +1 -0
  94. package/types/cli/schedule.d.ts +6 -0
  95. package/types/cli/schedule.d.ts.map +1 -0
  96. package/types/cli/serve.d.ts +2 -0
  97. package/types/cli/serve.d.ts.map +1 -0
  98. package/types/cli.d.ts +2 -0
  99. package/types/cli.d.ts.map +1 -0
  100. package/types/client.d.ts +463 -0
  101. package/types/client.d.ts.map +1 -0
  102. package/types/company.d.ts +94 -0
  103. package/types/company.d.ts.map +1 -0
  104. package/types/config.d.ts +111 -0
  105. package/types/config.d.ts.map +1 -0
  106. package/types/crypto.d.ts +61 -0
  107. package/types/crypto.d.ts.map +1 -0
  108. package/types/devices.d.ts +116 -0
  109. package/types/devices.d.ts.map +1 -0
  110. package/types/index.d.ts +23 -0
  111. package/types/index.d.ts.map +1 -0
  112. package/types/iot.d.ts +312 -0
  113. package/types/iot.d.ts.map +1 -0
  114. package/types/ir.d.ts +147 -0
  115. package/types/ir.d.ts.map +1 -0
  116. package/types/itemcodes.d.ts +21 -0
  117. package/types/itemcodes.d.ts.map +1 -0
  118. package/types/lock.d.ts +89 -0
  119. package/types/lock.d.ts.map +1 -0
  120. package/types/org.d.ts +468 -0
  121. package/types/org.d.ts.map +1 -0
  122. package/types/paths.d.ts +10 -0
  123. package/types/paths.d.ts.map +1 -0
  124. package/types/presetir.d.ts +286 -0
  125. package/types/presetir.d.ts.map +1 -0
  126. package/types/prompts.d.ts +39 -0
  127. package/types/prompts.d.ts.map +1 -0
  128. package/types/schedule.d.ts +71 -0
  129. package/types/schedule.d.ts.map +1 -0
  130. package/types/serve/daemon.d.ts +133 -0
  131. package/types/serve/daemon.d.ts.map +1 -0
  132. package/types/serve/framing/grpc.d.ts +14 -0
  133. package/types/serve/framing/grpc.d.ts.map +1 -0
  134. package/types/serve/framing/http.d.ts +14 -0
  135. package/types/serve/framing/http.d.ts.map +1 -0
  136. package/types/serve/framing/ndjson.d.ts +19 -0
  137. package/types/serve/framing/ndjson.d.ts.map +1 -0
  138. package/types/serve/framing/socket.d.ts +14 -0
  139. package/types/serve/framing/socket.d.ts.map +1 -0
  140. package/types/serve/framing/stdio.d.ts +11 -0
  141. package/types/serve/framing/stdio.d.ts.map +1 -0
  142. package/types/serve/framing/token.d.ts +11 -0
  143. package/types/serve/framing/token.d.ts.map +1 -0
  144. package/types/serve/framing/ws.d.ts +13 -0
  145. package/types/serve/framing/ws.d.ts.map +1 -0
  146. package/types/serve/jsonrpc.d.ts +118 -0
  147. package/types/serve/jsonrpc.d.ts.map +1 -0
  148. package/types/serve/registry.d.ts +41 -0
  149. package/types/serve/registry.d.ts.map +1 -0
  150. package/types/session-ui.d.ts +36 -0
  151. package/types/session-ui.d.ts.map +1 -0
  152. package/types/sharekey.d.ts +35 -0
  153. package/types/sharekey.d.ts.map +1 -0
  154. package/types/tokens.d.ts +20 -0
  155. package/types/tokens.d.ts.map +1 -0
  156. package/types/transport.d.ts +138 -0
  157. package/types/transport.d.ts.map +1 -0
  158. package/types/util.d.ts +20 -0
  159. package/types/util.d.ts.map +1 -0
  160. package/vendor/biz3/README.md +37 -0
  161. package/vendor/biz3/constants/cmdCode.d.ts +48 -0
  162. package/vendor/biz3/constants/cmdCode.d.ts.map +1 -0
  163. package/vendor/biz3/constants/cmdCode.js +92 -0
  164. package/vendor/biz3/constants/messageConstants.d.ts +28 -0
  165. package/vendor/biz3/constants/messageConstants.d.ts.map +1 -0
  166. package/vendor/biz3/constants/messageConstants.js +30 -0
  167. package/vendor/biz3/constants/sesameDeviceModel.d.ts +75 -0
  168. package/vendor/biz3/constants/sesameDeviceModel.d.ts.map +1 -0
  169. package/vendor/biz3/constants/sesameDeviceModel.js +77 -0
  170. package/vendor/biz3/package.json +5 -0
@@ -0,0 +1,132 @@
1
+ <!-- [English](./architecture.md) | 日本語 -->
2
+
3
+ # アーキテクチャ / 設計ノート
4
+
5
+ > English: [architecture.md](./architecture.md)
6
+
7
+ 実装の出自、設計判断、ファイル構成をまとめる。README は使い方を、ここは「なぜそうなっているか」を扱う。
8
+
9
+ ## 出自 (Lineage)
10
+
11
+ 本実装は **公式 biz3 管理 Web (https://github.com/CANDY-HOUSE/biz.candyhouse.co, MIT)** を Node.js に port したもの。主要部の port 関係:
12
+
13
+ | この実装 | biz3 vendor 元 |
14
+ |---|---|
15
+ | `src/transport.js` | `references_web/src/websocket/WebSocketManager.ts` (window 依存除去、Node `ws` 化、reconnect/keepalive/idle/sleep 検知は biz3 と同値、callback registry は FIFO 化) |
16
+ | `src/auth.js` | `references_web/src/api/useAuthState.js` (Amplify → AWS SDK 直叩きに置換) |
17
+ | `src/lock.js` | `references_web/src/api/useIotCtrl.js` の `sendCommandToWM2` |
18
+ | `src/ir.js` | `references_web/src/api/useRemoteCtrl.js` (hook 内 useCallback から JSON 構築部だけ抽出) |
19
+ | `src/devices.js` | `references_web/src/api/useManageDevice.js` / `useManageGroup.js` / `useDeveloper.js` / `MobileBatteryChart.js` |
20
+ | `src/crypto.js` | `references_web/src/utils/Cmac.js` + `biz3utils.js` + `constants/cmdCode.js` (CMAC は `node-aes-cmac` で実装) |
21
+
22
+ **biz3 との唯一の機能的相違**: Cognito Client ID を biz3 の `21u50hboia4s5q0sbk6pbdfmss` から、公式
23
+ iOS/Android アプリと同じ Consumer Client `6ialca0p8u0lsgvbmvsljfm305` に差し替え。これにより
24
+ refreshToken が事実上失効しなくなる。biz3 の MIT ライセンス本文は [LICENSE.biz3](../LICENSE.biz3) として同梱。
25
+
26
+ ## クラウド / BLE の統合設計(経路は葉)
27
+
28
+ クラウドと BLE は公式 SesameSDK と同様、**命令の正体 (itemCode) とデバイス能力モデルを共有**し、
29
+ 最後の送信経路 (transport) だけが葉として差し替わる単一設計。
30
+
31
+ - itemCode は `src/itemcodes.js` の 1 ソース(クラウドは `crypto.js` の `CMD`、BLE は `protocol.js` の
32
+ `ITEM` という別名で同じものを参照)。
33
+ - 能力は `devicemodel.js` が **型 × 経路** で持つ(各 kind に `cloud:[...]` と `ble:[...]` の op 集合)。
34
+ **操作できる op = 両者の和集合**で、session の対象・操作メニュー・`pickTransport` の経路選択はすべて
35
+ この和集合から導く。
36
+ - 例: ロックは `ble` に autolock があり `cloud` に無い → autolock は BLE 専用。
37
+ - OS2 ロックは `ble` 空・`cloud` に lock/unlock/toggle → クラウドのみで操作可。
38
+ - Hub3 は `cloud` に ir/relay/led。
39
+ - 既定は経路を意識しない**全部モード**で、固定したいときだけ `--ble-only` / `--cloud-only`。
40
+
41
+ ## irType の非対称トラップ(自己学習リモコン)
42
+
43
+ リモコンの種別は整数コード (= 実デバイスの `remote.type`)。主な値: `49152`(0xc000)=エアコン /
44
+ `8192`(0x2000)=テレビ / `57344`=照明 / `32768`=扇風機 / **`65024`(0xFE00)=自己学習**。
45
+
46
+ ⚠️ **学習だけ非対称**: 公式 biz3 のメニューでは各項目に id が振られ、エアコン/テレビ等のプリセットは
47
+ 「メニュー id = 実デバイスの type」で一致する。ところが「学習」のメニュー id は `0xFEFF` なのに、学習して
48
+ 実際に作られるリモコンの type は **`0xFE00`(65024)**。`0xFEFF` は「学習メニューを押した」という UI 上の印に
49
+ すぎず、デバイスや通信には現れない。**自己学習リモコンを指すときは必ず実 type `0xFE00` を使うこと**
50
+ (`0xFEFF` を渡すとサーバ照合が一致せずリモコンが見つからない)。当ツールは `0xFE00` を採用。
51
+
52
+ ## autolock はクラウド経由では設定できない
53
+
54
+ autolock (= `SesameItemCode` 11) の設定はクラウド経由では実機に反映されない。`biz3TriggerLocker` は cmd=11 に
55
+ `success:true` を返すが、ロック本体の autolock 秒数は変化しない。biz3 web/SDK にも設定系のクラウド送信経路は無く
56
+ (`useIotCtrl.js` の IoT cmd は ADD/REMOVE_SESAME・LED・RELAY 等のみで autolock は "Unsupported")、公式アプリは
57
+ autolock を BLE 直送する。よって autolock は BLE の `sesame autolock` のみで提供する。ライブラリには汎用レール
58
+ `lock.triggerItemCommand` / `lock.setAutolock` があるが、クラウドでは lock/unlock/toggle/bot 以外は実機に効かない。
59
+
60
+ `biz3TriggerLocker` は同期 ack (`{code:200, success:true}`) を返す。`unlock`/`lock`/`toggle`/`bot` は
61
+ この ack で完了判定する (push 待ちのみだと「サーバ受理済みなのに timeout」と誤判定するため)。
62
+
63
+ ## BLE 直接制御の設計
64
+
65
+ プロトコル層 (`src/ble/protocol.js`: CMAC セッション鍵 / AES-CCM / セグメント / フレーム) と
66
+ セッション層 (`src/ble/session.js`) は **OS 非依存の純 JS**。無線 I/O だけを差し替え可能なアダプタ
67
+ (`src/ble/transport.js`、既定 noble) に閉じ込めてあり、Web Bluetooth 等の別アダプタも注入できる。
68
+ デバイス型モデル (`src/ble/devicemodel.js`) は公式 SesameSDK の `CHProductModel` と能力定義を移植したもので、
69
+ `productType`/`model` → 種別 (lock5/bot2/bike2/…) → 対応操作・mechStatus 解釈を引く。`SesameBle` はこの能力に
70
+ 従って操作を許可/拒否する。プロトコルは Android SesameSDK / ESP32 リファレンス実装から移植。
71
+
72
+ ## config の単一 `devices{}` 設計
73
+
74
+ **デバイスは単一の `devices{}` に丸ごと保存する** — ロック / Bot / Bike / Hub3 を型ごとに分けず、
75
+ サーバの device レコードを (巨大な `stateInfo` を除き) そのまま格納する。型は `deviceModel` から導出し、
76
+ どの操作 view (lock / hub3) に出すかは `category` で分類する。`model`/`secretKey` の取りこぼし
77
+ (Hub3 が「解錠」と誤表示される等) を構造的に防ぐための設計。`remotes` は device ではない子エンティティ
78
+ (親 Hub3 + irType + 学習 keys) なので独立コレクションのまま。
79
+
80
+ ## `sesame serve` 言語非依存バックエンド
81
+
82
+ 1 コア + 5 フレーミングで、単一常駐 `SesameHub3` に全機能を一様公開する。詳細は README の
83
+ [言語非依存バックエンド](../README.ja.md#言語非依存バックエンド-sesame-serve) を参照。
84
+
85
+ - **コア**: `src/serve/jsonrpc.js`(JSON-RPC 2.0、transport 非依存)+ `registry.js`(`NAMESPACE_OPS` から
86
+ メソッドを自動公開 + OpenRPC)+ `daemon.js`(直列化 / 購読一元 / 背圧 / shutdown)。
87
+ - **フレーミング**: `framing/` 配下に stdio / socket(UDS) / http(+SSE) / ws / grpc + token。
88
+ - **型抽出**: `scripts/gen-rpc-schema.mjs` が `.d.ts` から param 型を抽出 (`rpc-params.generated.json`)、
89
+ `scripts/gen-grpc-proto.mjs` が型付き `sesame.proto` を生成。両者は drift-guard テストで保護。
90
+
91
+ ## ファイル構成
92
+
93
+ ```
94
+ sesame-kit/
95
+ ├── package.json
96
+ ├── README.md
97
+ ├── docs/ # commands / architecture / library / migration
98
+ ├── LICENSE
99
+ ├── LICENSE.biz3
100
+ ├── bin/
101
+ │ └── sesame.js # CLI 実行エントリ
102
+ ├── clients/ # sesame serve に繋ぐ薄い公式クライアント (依存ゼロ)
103
+ │ ├── python/sesame_client.py # UDS/stdio/HTTP + イベント購読
104
+ │ └── js/sesame-client.mjs # 同等 (Node 18+)
105
+ ├── vendor/
106
+ │ └── biz3/constants/ # biz3 の import-zero 定数を逐語コピー (single source of truth)
107
+ └── src/
108
+ ├── index.js # 公開ライブラリエントリ
109
+ ├── cli.js # commander 実装 (基本コマンド + makeCtx)
110
+ ├── cli/ # 機能別コマンド配線 (registerXxxCommands)
111
+ │ └── serve.js # sesame serve … (常駐 JSON-RPC バックエンド配線)
112
+ ├── serve/ # 言語非依存バックエンド (1 コア + 5 フレーミング)
113
+ │ ├── jsonrpc.js # JSON-RPC 2.0 プロトコルコア (transport 非依存)
114
+ │ ├── registry.js # メソッドカタログ (NAMESPACE_OPS から自動公開) + OpenRPC
115
+ │ ├── daemon.js # 単一常駐 hub への多重化 (直列化/購読/背圧/shutdown)
116
+ │ ├── sesame.proto # gRPC 型付き定義 (生成物)
117
+ │ └── framing/ # stdio / socket(UDS) / http(+SSE) / ws / grpc + token
118
+ ├── client.js # SesameHub3 高レベルクラス (namespace getter で op を自動注入)
119
+ ├── transport.js # Hub3WsClient (reconnect/keepalive/queue/sleep)
120
+ ├── auth.js # Cognito CUSTOM_AUTH + REFRESH_TOKEN_AUTH + jwtSub
121
+ ├── crypto.js # AES-CMAC + uuid→base64 + cmd code 定数
122
+ ├── lock.js / ir.js / presetir.js / sharekey.js # ドメイン op
123
+ ├── ble/ # BLE 直接制御 (OS非依存コア + 差し替え可能トランスポート)
124
+ │ ├── protocol.js # 純JS: CMAC鍵/AES-CCM/セグメント/フレーム/mechStatus
125
+ │ ├── session.js # 状態機械 (initial→login→コマンド応答)
126
+ │ ├── transport.js # noble アダプタ (optionalDependency, 遅延require)
127
+ │ └── index.js # SesameBle ファサード
128
+ ├── iot.js / account.js / schedule.js / org.js / company.js / access.js / devices.js
129
+ ├── config.js # ConfigStore (~/.config/sesame-hub3/config.json)
130
+ ├── tokens.js # FileTokenStore
131
+ └── paths.js # 設定ディレクトリ解決
132
+ ```
@@ -0,0 +1,105 @@
1
+ <!-- English | [日本語](./architecture.ja.md) -->
2
+
3
+ # Architecture / Design Notes
4
+
5
+ > 日本語: [architecture.ja.md](./architecture.ja.md)
6
+
7
+ This document covers the lineage of the implementation, the design decisions, and the file layout. The README covers usage; this covers why things are the way they are.
8
+
9
+ ## Lineage
10
+
11
+ This implementation is a Node.js port of the **official biz3 admin web app (https://github.com/CANDY-HOUSE/biz.candyhouse.co, MIT)**. The port mapping for the main parts:
12
+
13
+ | This implementation | biz3 vendor source |
14
+ |---|---|
15
+ | `src/transport.js` | `references_web/src/websocket/WebSocketManager.ts` (window dependency removed, switched to Node `ws`; reconnect/keepalive/idle/sleep detection identical to biz3; callback registry made FIFO) |
16
+ | `src/auth.js` | `references_web/src/api/useAuthState.js` (Amplify replaced with direct AWS SDK calls) |
17
+ | `src/lock.js` | `sendCommandToWM2` in `references_web/src/api/useIotCtrl.js` |
18
+ | `src/ir.js` | `references_web/src/api/useRemoteCtrl.js` (only the JSON-building part extracted from the hook's useCallback) |
19
+ | `src/devices.js` | `references_web/src/api/useManageDevice.js` / `useManageGroup.js` / `useDeveloper.js` / `MobileBatteryChart.js` |
20
+ | `src/crypto.js` | `references_web/src/utils/Cmac.js` + `biz3utils.js` + `constants/cmdCode.js` (CMAC implemented with `node-aes-cmac`) |
21
+
22
+ **The only functional difference from biz3**: the Cognito Client ID is swapped from biz3's `21u50hboia4s5q0sbk6pbdfmss` to the same Consumer Client as the official iOS/Android apps, `6ialca0p8u0lsgvbmvsljfm305`. This keeps the refreshToken from effectively expiring. The biz3 MIT license text is bundled as [LICENSE.biz3](../LICENSE.biz3).
23
+
24
+ ## Unified cloud / BLE design (the route is the leaf)
25
+
26
+ Like the official SesameSDK, cloud and BLE **share the underlying command (itemCode) and the device capability model**; only the final send route (transport) is swapped as a leaf. This is a single design.
27
+
28
+ - itemCode has one source in `src/itemcodes.js` (the cloud refers to it as `CMD` in `crypto.js`, BLE as `ITEM` in `protocol.js` — different aliases for the same thing).
29
+ - Capability is held by `devicemodel.js` as **type × route** (each kind has a `cloud:[...]` and a `ble:[...]` op set).
30
+ The **operable ops = the union of the two**, and the session's targets, operation menu, and `pickTransport` route selection are all derived from this union.
31
+ - Example: a lock has autolock under `ble` but not `cloud` → autolock is BLE-only.
32
+ - An OS2 lock has an empty `ble` set and lock/unlock/toggle under `cloud` → operable via cloud only.
33
+ - Hub3 has ir/relay/led under `cloud`.
34
+ - The default is a **full mode** that is unaware of the route; pin it with `--ble-only` / `--cloud-only` only when desired.
35
+
36
+ ## The irType asymmetry trap (self-learned remote)
37
+
38
+ A remote's kind is an integer code (= the device's `remote.type`). Main values: `49152` (0xc000) = air conditioner / `8192` (0x2000) = TV / `57344` = light / `32768` = fan / **`65024` (0xFE00) = self-learned**.
39
+
40
+ ⚠️ **Only learning is asymmetric**: in the official biz3 menu, each item has an id, and presets such as air conditioner / TV match by "menu id = device type." However, the "learn" menu id is `0xFEFF`, while the type of the remote actually created by learning is **`0xFE00` (65024)**. `0xFEFF` is only a UI-side marker for "the learn menu was pressed"; it never appears on the device or in communication. **Always use the real type `0xFE00` when referring to a self-learned remote** (passing `0xFEFF` fails the server-side match and the remote is not found). This tool uses `0xFE00`.
41
+
42
+ ## autolock cannot be set over the cloud
43
+
44
+ Setting autolock (= `SesameItemCode` 11) over the cloud is not reflected on the physical device. `biz3TriggerLocker` returns `success:true` for cmd=11, but the lock's actual autolock duration does not change. biz3 web/SDK has no cloud send route for settings either (the IoT cmds in `useIotCtrl.js` are only ADD/REMOVE_SESAME, LED, RELAY, etc., and autolock is "Unsupported"), and the official app sends autolock directly over BLE. autolock is therefore provided only via BLE's `sesame autolock`. The library has the generic rails `lock.triggerItemCommand` / `lock.setAutolock`, but over the cloud only lock/unlock/toggle/bot take effect on the device.
45
+
46
+ `biz3TriggerLocker` returns a synchronous ack (`{code:200, success:true}`). `unlock`/`lock`/`toggle`/`bot` use this ack to determine completion (waiting on the push alone would wrongly report a timeout even though the server already accepted the command).
47
+
48
+ ## BLE direct control design
49
+
50
+ The protocol layer (`src/ble/protocol.js`: CMAC session key / AES-CCM / segments / frames) and the session layer (`src/ble/session.js`) are **OS-independent pure JS**. Only the radio I/O is confined to a swappable adapter (`src/ble/transport.js`, noble by default); an alternate adapter such as Web Bluetooth can also be injected. The device type model (`src/ble/devicemodel.js`) ports the capability definitions of the official SesameSDK's `CHProductModel`, mapping `productType`/`model` → kind (lock5/bot2/bike2/…) → supported operations and mechStatus interpretation. `SesameBle` allows or rejects operations according to this capability. The protocol is ported from the Android SesameSDK / ESP32 reference implementation.
51
+
52
+ ## The single `devices{}` config design
53
+
54
+ **Devices are stored whole in a single `devices{}`** — locks / Bots / Bikes / Hub3 are not split by type; the server's device record is stored as-is (minus the huge `stateInfo`). The type is derived from `deviceModel`, and which operation view (lock / hub3) it appears in is classified by `category`. This design structurally prevents dropped `model`/`secretKey` (e.g., a Hub3 being mislabeled as "unlocked"). `remotes` is a child entity, not a device (parent Hub3 + irType + learned keys), so it stays an independent collection.
55
+
56
+ ## `sesame serve` language-agnostic backend
57
+
58
+ With 1 core + 5 framings, the full feature set is uniformly exposed on a single resident `SesameHub3`. See the README's [language-agnostic backend](../README.md#language-agnostic-backend-sesame-serve) for details.
59
+
60
+ - **Core**: `src/serve/jsonrpc.js` (JSON-RPC 2.0, transport-independent) + `registry.js` (auto-exposes methods from `NAMESPACE_OPS` + OpenRPC) + `daemon.js` (serialization / unified subscription / backpressure / shutdown).
61
+ - **Framing**: stdio / socket(UDS) / http(+SSE) / ws / grpc + token under `framing/`.
62
+ - **Type extraction**: `scripts/gen-rpc-schema.mjs` extracts param types from `.d.ts` (`rpc-params.generated.json`), and `scripts/gen-grpc-proto.mjs` generates a typed `sesame.proto`. Both are protected by drift-guard tests.
63
+
64
+ ## File layout
65
+
66
+ ```
67
+ sesame-kit/
68
+ ├── package.json
69
+ ├── README.md
70
+ ├── docs/ # commands / architecture / library / migration
71
+ ├── LICENSE
72
+ ├── LICENSE.biz3
73
+ ├── bin/
74
+ │ └── sesame.js # CLI entry point
75
+ ├── clients/ # thin official clients that connect to sesame serve (zero dependencies)
76
+ │ ├── python/sesame_client.py # UDS/stdio/HTTP + event subscription
77
+ │ └── js/sesame-client.mjs # equivalent (Node 18+)
78
+ ├── vendor/
79
+ │ └── biz3/constants/ # verbatim copy of biz3's import-zero constants (single source of truth)
80
+ └── src/
81
+ ├── index.js # public library entry
82
+ ├── cli.js # commander implementation (basic commands + makeCtx)
83
+ ├── cli/ # per-feature command wiring (registerXxxCommands)
84
+ │ └── serve.js # sesame serve … (resident JSON-RPC backend wiring)
85
+ ├── serve/ # language-agnostic backend (1 core + 5 framings)
86
+ │ ├── jsonrpc.js # JSON-RPC 2.0 protocol core (transport-independent)
87
+ │ ├── registry.js # method catalog (auto-exposed from NAMESPACE_OPS) + OpenRPC
88
+ │ ├── daemon.js # multiplexing onto a single resident hub (serialization/subscription/backpressure/shutdown)
89
+ │ ├── sesame.proto # gRPC typed definition (generated)
90
+ │ └── framing/ # stdio / socket(UDS) / http(+SSE) / ws / grpc + token
91
+ ├── client.js # SesameHub3 high-level class (auto-injects ops via namespace getters)
92
+ ├── transport.js # Hub3WsClient (reconnect/keepalive/queue/sleep)
93
+ ├── auth.js # Cognito CUSTOM_AUTH + REFRESH_TOKEN_AUTH + jwtSub
94
+ ├── crypto.js # AES-CMAC + uuid→base64 + cmd code constants
95
+ ├── lock.js / ir.js / presetir.js / sharekey.js # domain ops
96
+ ├── ble/ # BLE direct control (OS-independent core + swappable transport)
97
+ │ ├── protocol.js # pure JS: CMAC key/AES-CCM/segment/frame/mechStatus
98
+ │ ├── session.js # state machine (initial→login→command response)
99
+ │ ├── transport.js # noble adapter (optionalDependency, lazy require)
100
+ │ └── index.js # SesameBle facade
101
+ ├── iot.js / account.js / schedule.js / org.js / company.js / access.js / devices.js
102
+ ├── config.js # ConfigStore (~/.config/sesame-hub3/config.json)
103
+ ├── tokens.js # FileTokenStore
104
+ └── paths.js # config directory resolution
105
+ ```
@@ -0,0 +1,316 @@
1
+ <!-- [English](./commands.md) | 日本語 -->
2
+
3
+ # コマンドリファレンス
4
+
5
+ > English: [commands.md](./commands.md)
6
+
7
+ > CLI の全コマンド。各サブコマンドは `sesame <cmd> --help` でも引けます。
8
+ > `sesame serve` 経由で他言語から叩く場合は `sesame rpc`(または `rpc.discover`)が機械可読な真実の源です。
9
+
10
+ ## デバイス操作(デバイス主語)
11
+
12
+ 主語は**デバイス**です。`sesame <device> <action>` は SDK の `device.action()` と同じ並び。
13
+ device は名前(部分一致可)。action 省略でそのデバイスの対話メニュー、device も省略で全デバイスの
14
+ 対話メニュー(= `session`)。
15
+
16
+ ```bash
17
+ sesame front unlock # front.unlock() (部分一致可: sesame 玄関 unlock)
18
+ sesame front lock # 施錠
19
+ sesame front toggle # 現在状態で反転
20
+ sesame front status # 状態 (施錠/解錠・位置)
21
+ sesame front autolock 30 # オートロック (BLE 必須。0=無効)
22
+ sesame kitchen click # SESAME Bot クリック (Bot2/Bot3)
23
+
24
+ sesame front # front の対話メニュー
25
+ sesame # 全デバイスの対話メニュー (session)
26
+ ```
27
+
28
+ action: `unlock` / `lock` / `toggle` / `click` / `status` / `autolock <秒>`(**使える操作は型で変わる** — 後述)。
29
+
30
+ ### 経路 (transport) は「全部モード」が既定
31
+
32
+ - 既定は全部モード。経路は自動で選ばれる。cloud で運べる op は cloud、`autolock` のような BLE 必須の op だけ BLE 接続する (BLE のスキャン/接続コストを毎回は払わない)。
33
+ - `--ble-only` / `--cloud-only` で経路を固定する。`--ble-only` は接続に数秒かかる。`--cloud-only` は一部操作が制限される。
34
+ - BLE 接続を保持して連続操作するモードは `sesame session` (= `sesame <device>` の複数版)。
35
+
36
+ ```bash
37
+ sesame front unlock # 全部モード (ツールが経路を選ぶ)
38
+ sesame front autolock 30 # BLE 必須の op → 自動で BLE 接続
39
+ sesame front lock --ble-only # BLE に固定 (接続に数秒)
40
+ sesame front lock --cloud-only # クラウドに固定
41
+ ```
42
+
43
+ > 設計の詳細(クラウド/BLE の能力モデル統合)は [architecture.md](./architecture.ja.md) を参照。
44
+
45
+ ロック定義の管理は `locks` グループ:
46
+
47
+ ```bash
48
+ sesame locks ls # 登録ロック一覧
49
+ sesame locks set-default front
50
+ sesame locks add # 対話で追加 (deviceUUID + secretKey)
51
+ sesame locks add --name front --uuid <UUID> --secret <32hex> --model sesame_5_pro # 非対話/フラグ追加
52
+ sesame locks sync-from-devices # devices の結果から自動取り込み
53
+ sesame locks rm front
54
+ ```
55
+
56
+ クラウド操作の応答は同期 ack (`biz3TriggerLocker`, `success:true`) を待ってから戻ります (timeout 10s)。
57
+
58
+ > autolock はクラウド経由では設定できません (BLE のみ)。`sesame autolock` を使ってください。背景は [architecture.md](./architecture.ja.md)。
59
+
60
+ ---
61
+
62
+ ## Hub3 IR
63
+
64
+ ### 既存キーの発射
65
+
66
+ ```bash
67
+ sesame send 停止 # デフォルトリモコンで発射
68
+ sesame send 停止 --remote ac
69
+ sesame list # リモコンに登録されているキー一覧
70
+ ```
71
+
72
+ ### 高度な操作
73
+
74
+ ```bash
75
+ # 学習: 物理リモコンを Hub3 に向けてボタンを押す
76
+ sesame ir learn ac 強風 # remote=ac に "強風" キーを学習登録
77
+ # → Hub3 を REGISTER モード → 波形捕捉 → CONTROL に戻し → addIRCode
78
+
79
+ # モード制御
80
+ sesame ir mode get [hub3] # 現在モード取得 (0=CONTROL / 1=REGISTER)
81
+ sesame ir mode set 1 [hub3] # 強制 REGISTER 切替 (デバッグ用)
82
+
83
+ # キー CRUD
84
+ sesame ir key rename ac 強風 強運転 # キー名変更 (server + config)
85
+ sesame ir key rm ac 試運転 # キー削除
86
+
87
+ # リモコン CRUD (server 側)
88
+ sesame ir remote-list ac # 登録済みリモコン (irType 指定)
89
+ sesame ir remote-rm ac # server から削除
90
+ sesame ir remote-rename "リビング" ac # server alias 変更
91
+
92
+ # プリセット DB
93
+ sesame ir search ac ダイキン # メーカー DB 検索 (max 1000)
94
+ sesame ir match ac <hex波形> # 学習波形 → 既知リモコン照合
95
+ ```
96
+
97
+ > 自己学習リモコンを指すときは `irType` に実 type `0xFE00`(65024) を使う。メニュー id の `0xFEFF` を渡すと
98
+ > サーバ照合が一致せずリモコンが見つからない。詳細は [architecture.md](./architecture.ja.md)。
99
+
100
+ ---
101
+
102
+ ## デバイス管理
103
+
104
+ ```bash
105
+ sesame device user-ls # 個人デバイス一覧
106
+ sesame device status <uuid> # 現在状態
107
+ sesame device rename <uuid> "玄関 SESAME" # 名前変更
108
+ sesame device rm <uuid> # company から削除
109
+
110
+ sesame history <uuid> # ロック開閉履歴
111
+ sesame history # 全デバイス
112
+ sesame battery <uuid> # 電池履歴 (light/heavy 電圧 + 割合)
113
+ sesame firmware # 配信中ファームウェア一覧
114
+ ```
115
+
116
+ ---
117
+
118
+ ## WebAPI proxy
119
+
120
+ biz3 dev console で発行する REST API key (apiKeyId) を `config.apiKeyId` に設定すると、任意の REST WebAPI を WebSocket 経由で proxy 呼び出しできる:
121
+
122
+ ```bash
123
+ # config.json に "apiKeyId": "..." を入れた状態で:
124
+ sesame webapi webapi_ssm_shadow_get --query '{"device_id":"..."}'
125
+ sesame webapi webapi_history_get --query '{"device_id":"...","page":0,"lg":"ja","isBiz":true}'
126
+ sesame webapi webapi_cmd_send --body '{"device_id":"...","cmd":83,"sign":"...","history":"..."}'
127
+ ```
128
+
129
+ ---
130
+
131
+ ## 予約スケジュール (biz3Schedule)
132
+
133
+ ```bash
134
+ sesame schedule ls # 登録済み予約 (lock/unlock/upgrade_firmware) 一覧
135
+ sesame schedule cancel <id> # 予約を取消 (id 省略時は一覧から対話選択)
136
+ ```
137
+
138
+ > 予約の **新規作成 op は biz3 web に存在しない** ため、CLI も list / cancel のみ。
139
+
140
+ ---
141
+
142
+ ## アクセス制御 (NFC カード / 暗証番号)
143
+
144
+ SESAME Touch (Pro) の NFC カード・キーパッド暗証番号の **サーバ DB 同期** op 群。
145
+ 実機ファームウェアへの書き込みは別系統 (BLE) で、ここは DB 側の同期のみを扱う 2 層構造。
146
+
147
+ ```bash
148
+ sesame access cards ls --device <uuid> [--device <uuid2> ...] # カード一覧
149
+ sesame access cards clear --device <uuid> # 指定デバイスのカード全削除
150
+ sesame access cards rm --json '[{"deviceID":"...","cardID":"..."}]' # 個別削除 (応答なし)
151
+ sesame access cards owner <cardID> [ownerSubUUID] # 所有者割当 ('' で解除)
152
+ sesame access passcodes ls --device <uuid> # 暗証番号一覧
153
+ ```
154
+
155
+ > `rm` (delCards/delPasscodes) は biz3 に応答ハンドラが無く **fire-and-forget**。完了応答は返らない。
156
+
157
+ ---
158
+
159
+ ## 会社 / 組織管理 (biz3 enterprise)
160
+
161
+ 複数会社・社員・役割・デバイスグループを扱う法人向け機能。`companyID` はログイン情報から自動補完される。
162
+
163
+ ```bash
164
+ # 会社
165
+ sesame company ls # 所属会社一覧
166
+ sesame company rename "新社名" # 優先会社の改名
167
+ sesame company add "新会社" # 会社を新規登録
168
+ sesame company payment # 課金設定取得
169
+
170
+ # 組織 (org)
171
+ sesame org employee ls # 社員一覧
172
+ sesame org employee search <kw> # CS 横断のユーザー検索
173
+ sesame org role ls # 役割タグ一覧
174
+ sesame org group ls # 社員グループ一覧
175
+ sesame org device-group ls # デバイスグループ一覧
176
+ sesame org keys device <deviceUUID> # デバイス側の鍵保有従業員を列挙
177
+ ```
178
+
179
+ ### ゲスト共有 (鍵共有 URL / QR)
180
+
181
+ SESAME アプリが読む共有 QR と同じ `ssm://UI?t=sk&sk=…&l=…&n=…` URL を生成する。
182
+ `--level 2` (ゲスト) のときだけ使い捨て `guestKeyId` を発行して埋め込む (biz3 と同じ挙動)。
183
+
184
+ ```bash
185
+ sesame org keys share-url --device <uuid> --level 2 --name "来客用" # ゲスト共有 URL
186
+ sesame org keys share-url --device <uuid> --level 1 # マネージャ鍵共有
187
+ sesame org keys share-url --device <uuid> --qr # 端末に QR 表示 (要 qrcode-terminal)
188
+ ```
189
+
190
+ > 共有 URL の組み立て・解析は biz3 `generateInviteGuestQRCodeByInfo` / `readQrcode` を 1:1 移植。
191
+ > **画像化ライブラリ非依存**で、出力 URL を任意の QR 生成器に貼っても共有できる。
192
+ > 作成/更新系の多くは構造体を `--json '<…>'` で受ける(各サブコマンドの `--help` に例あり)。
193
+ > `org employee confirm <email>` は biz3 仕様上、成功時に現セッションを signout する点に注意。
194
+
195
+ ---
196
+
197
+ ## Hub3 IoT 制御 (biz3OperateIoT)
198
+
199
+ Hub3 本体への直接コマンド (LED 調光・LTE リレー・ファーム更新・Matter ペアリング等)。
200
+ `--device <hub3UUID> --secret <hex>` を渡すか、対話時は接続デバイスから選択。
201
+
202
+ ```bash
203
+ sesame iot led 80 --device <uuid> --secret <hex> # LED 調光 (0-100)
204
+ sesame iot led --get --device <uuid> --secret <hex># 現在の調光取得
205
+ sesame iot relay on --device <uuid> --secret <hex># LTE リレー開閉
206
+ sesame iot firmware-update --device <uuid> --secret <hex> --wait 60
207
+ sesame iot matter-code --device <uuid> --secret <hex> # Matter ペアリングコード
208
+ ```
209
+
210
+ ---
211
+
212
+ ## プリセット IR リモコン (HXD command)
213
+
214
+ エアコン等を「学習」ではなく **プリセット DB の命令で** 発射する。Hub3 を `--device` に指定:
215
+
216
+ ```bash
217
+ sesame preset-ir air --device <hub3uuid> --code <n> --power --temp 26 --mode 1 --fan 2
218
+ sesame preset-ir button --device <hub3uuid> --code <n> --button power --irtype 8192
219
+ sesame preset-ir send --device <hub3uuid> --command <hex> --irtype 49152 # 生 hex 発射
220
+ ```
221
+
222
+ > プリセットの command 生成 (biz3 の HXDCommandProcessor) は未移植のため、プリセット発射は現状機能しません。
223
+ > 自己学習リモコン (`sesame ir learn`) を使ってください([既知の制限](../README.ja.md#健全性--既知の制限))。
224
+
225
+ ---
226
+
227
+ ## BLE 直接制御 (クラウド非経由)
228
+
229
+ PC の Bluetooth から登録済み SESAME を**直接**操作する。クラウド (WS) を介さないので
230
+ オフラインでも動き、**クラウドでは不可だった `autolock` 等の設定系が実機に反映される**。
231
+
232
+ BLE 操作は専用コマンドではなく、デバイス主語の操作に **`--ble-only` を付ける**だけ
233
+ (`autolock` は BLE 必須なので無指定でも自動で BLE):
234
+
235
+ ```bash
236
+ sesame front status --ble-only # 現在状態 (施錠/解錠, 位置)
237
+ sesame front unlock --ble-only # 解錠 (ロック/Bike)
238
+ sesame front lock --ble-only # 施錠 (ロック)
239
+ sesame front toggle --ble-only # 状態を見て反転 (ロック)
240
+ sesame kitchen click --ble-only # SESAME Bot のクリック (Bot2/Bot3)
241
+ sesame front autolock 30 # オートロック (BLE 必須。本当に効く)
242
+ sesame front autolock 0 # 無効化
243
+ ```
244
+
245
+ > **BLE エラーは `SesameResultCode` で意味づけ済み** — デバイスが非 0 の結果を返すと、ライブラリは
246
+ > `BleResultError`(`.resultCode` / `.resultName`)を投げる。`resultName` は公式 SesameSDK の
247
+ > `SesameResultCode`(`success`/`invalidFormat`/`notSupported`/`invalidSig`/`notFound`/`unknown`/
248
+ > `busy`/`invalidParam`/`invalidAction`)に一致し、機械的に分岐できる。
249
+ > 注: これは**デバイス層 (SesameOS3) の taxonomy** で、BLE 直接経路でのみ取得できる
250
+ > (クラウド経路はこの code を surface しないため `sesame serve` の `kind` には乗らない)。
251
+
252
+ ### デバイス型ごとの操作 (公式 SesameSDK 準拠)
253
+
254
+ 操作セットはデバイスの種別で異なる。SDK では能力が型ごとに非対称に定義されており、本 CLI もそれを `config` の
255
+ `model` から判定して同じ非対称性を再現する。対応外の操作はコマンドが拒否される(例: Bot に `lock` → 「click を使え」)。
256
+
257
+ | 種別 (model 例) | BLE 操作 | mechStatus |
258
+ |---|---|---|
259
+ | ロック `sesame_5`/`_pro`/`sesame_6`/`_pro`/`_us`/`miwa` | `lock` `unlock` `toggle` `autolock` `status` | 施錠/解錠 + 位置 |
260
+ | Bot `bot_2`/`bot_3` | `click` `status` | 施錠/解錠 (位置なし) |
261
+ | Bike `bike_2`/`bike_3` | `unlock` `status` | 施錠/解錠 (位置なし) |
262
+ | Touch/Face/Sensor/Remote, Hub3, WiFiModule2 | (BLE 施錠操作なし) | — |
263
+ | OS2 `sesame_2`/`_4`, `ssmbot_1`, `bike_1` | BLE 未実装 (鍵導出/暗号が別系統)。クラウド経由で操作 | — |
264
+
265
+ > 「施錠/解錠」は OS3 では `isInLockRange` の有無による **2 値**のみ。OS3 に中間状態 (moved) は無い
266
+ > (Sesame2 等 OS2 系のみ moved を持つ)。BLE 実装の設計は [architecture.md](./architecture.ja.md) を参照。
267
+
268
+ ライブラリとしても利用可:
269
+
270
+ ```js
271
+ import { SesameBle } from "sesame-kit"; // or: import { ble } from "sesame-kit"
272
+ await SesameBle.use({ deviceUUID, secretKey }, async (lock) => {
273
+ await lock.unlock();
274
+ await lock.autolock(30);
275
+ console.log(lock.lastStatus); // { state, batteryMv, position, ... }
276
+ });
277
+ ```
278
+
279
+ > 対象は **SesameOS3** (SESAME 5 / 5 Pro / Touch 等)。新規ペアリング (未登録デバイスの登録) は別フェーズ。
280
+
281
+ ---
282
+
283
+ ## 対話セッション
284
+
285
+ 対話セッション(`sesame` / `sesame <device>` / `sesame session`)は**アプリ的な全部モード**です。
286
+ **操作できるデバイスを全部**載せます: ロック/Bot/Bike(BLE+クラウド)と、ログイン済みなら **Hub3**(クラウド: IR 送信 / リレー / LED)。
287
+ BLE を best-effort で張りつつ、**BLE が 0 でも終了しません**: 圏外/権限なしのデバイスはログイン済みなら
288
+ **クラウドで操作**します(BLE が張れたデバイスは BLE を優先=低遅延+autolock 可)。
289
+
290
+ ```text
291
+ $ sesame # 全デバイス (alias: sesame session / watch)
292
+ [ble] バックグラウンドで接続中... (クラウドで操作可能)
293
+ ─── SESAME セッション ── 矢印キーで選択 ───
294
+ front [sesame_5·BLE]: state=locked pos=-176
295
+ kitchen [bot_2·cloud]: (BLE未接続)
296
+ hub3-居間 [hub3·hub3]: (Hub3: IR / リレー / LED)
297
+
298
+ ? 操作するデバイス ← ① デバイスを選ぶ
299
+ ? front の操作 ← ② 操作を選ぶ (型で変わる)
300
+ ロック : 🔓 解錠 / 🔒 施錠 / ↕ トグル / ⏱ オートロック / ℹ 状態
301
+ Bot : 👆 クリック / ℹ 状態
302
+ Hub3 : 📡 IR 送信 (リモコン→キー選択) / 🔌 リレー ON/OFF / 💡 LED 調光
303
+ ```
304
+
305
+ 各デバイスの末尾タグ `·BLE` / `·cloud` が経路。**`autolock` は BLE 必須**なので、cloud のデバイスでは
306
+ 「近づいて再試行」と案内します。接続が 1 個だけならデバイス選択を省略。
307
+
308
+ **ライブ更新**: 画面は **Ink (React for CLI)** 製のライブダッシュボードで、BLE の状態変化や
309
+ バックグラウンド接続の完了を受けて**その場で再描画**します(cloud→BLE への昇格もリアルタイム)。
310
+ 起動はクラウドで即メニュー表示し、BLE は裏で接続するので 8 秒のスキャンを待ちません。終了は `q` / Esc。
311
+
312
+ **前提**:
313
+ - 鍵は既存の `config.locks`(`sesame locks sync-from-devices` で取り込んだ deviceUUID/secretKey)を再利用。新規登録は不要。
314
+ - BLE アダプタ `@abandonware/noble` が必要。`optionalDependency` なので `npm install` で**自動導入**を試み、未対応環境でもインストール自体は壊れない (BLE だけ無効)。手動で入れるなら `npm i @abandonware/noble`。
315
+ - **macOS は Terminal/iTerm に Bluetooth 権限が必要**(システム設定 → プライバシーとセキュリティ → Bluetooth)。
316
+ - ロックの BLE 圏内(近接)にいること。