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,308 @@
1
+ <!-- English | [日本語](./commands.ja.md) -->
2
+
3
+ # Command Reference
4
+
5
+ > 日本語: [commands.ja.md](./commands.ja.md)
6
+
7
+ > Every CLI command. Each subcommand also accepts `sesame <cmd> --help`.
8
+ > When calling from another language via `sesame serve`, `sesame rpc` (or `rpc.discover`) is the machine-readable source of truth.
9
+
10
+ ## Device operations (device as the subject)
11
+
12
+ The subject is the **device**. `sesame <device> <action>` mirrors the SDK's `device.action()` ordering.
13
+ `device` is a name (substring match allowed). Omit `action` for that device's interactive menu; omit `device` too for the interactive menu over all devices (= `session`).
14
+
15
+ ```bash
16
+ sesame front unlock # front.unlock() (substring match: sesame 玄関 unlock)
17
+ sesame front lock # lock
18
+ sesame front toggle # invert from current state
19
+ sesame front status # status (locked / unlocked, position)
20
+ sesame front autolock 30 # autolock (BLE only. 0 = off)
21
+ sesame kitchen click # SESAME Bot click (Bot2/Bot3)
22
+
23
+ sesame front # interactive menu for front
24
+ sesame # interactive menu for all devices (session)
25
+ ```
26
+
27
+ action: `unlock` / `lock` / `toggle` / `click` / `status` / `autolock <seconds>` (**which operations apply depends on the type** — see below).
28
+
29
+ ### The route (transport) defaults to all-routes mode
30
+
31
+ - The default is all-routes mode; the route is chosen automatically. Ops that the cloud can carry go over cloud, and only BLE-required ops such as `autolock` open a BLE connection (so you don't pay the BLE scan/connect cost every time).
32
+ - Pin the route with `--ble-only` / `--cloud-only`. `--ble-only` takes a few seconds to connect. `--cloud-only` restricts some operations.
33
+ - To hold a BLE connection open across a run of operations, use `sesame session` (the multi-device form of `sesame <device>`).
34
+
35
+ ```bash
36
+ sesame front unlock # all-routes mode (the tool picks the route)
37
+ sesame front autolock 30 # BLE-required op → connects over BLE automatically
38
+ sesame front lock --ble-only # pinned to BLE (a few seconds to connect)
39
+ sesame front lock --cloud-only # pinned to cloud
40
+ ```
41
+
42
+ > For the design details (the unified cloud/BLE capability model), see [architecture.md](./architecture.md).
43
+
44
+ Manage lock definitions with the `locks` group:
45
+
46
+ ```bash
47
+ sesame locks ls # list registered locks
48
+ sesame locks set-default front
49
+ sesame locks add # add interactively (deviceUUID + secretKey)
50
+ sesame locks add --name front --uuid <UUID> --secret <32hex> --model sesame_5_pro # non-interactive / flag-based add
51
+ sesame locks sync-from-devices # auto-import from the result of devices
52
+ sesame locks rm front
53
+ ```
54
+
55
+ A cloud operation returns only after the synchronous ack (`biz3TriggerLocker`, `success:true`) arrives (timeout 10s).
56
+
57
+ > autolock cannot be set over the cloud (BLE only). Use `sesame autolock`. Background in [architecture.md](./architecture.md).
58
+
59
+ ---
60
+
61
+ ## Hub3 IR
62
+
63
+ ### Emit an existing key
64
+
65
+ ```bash
66
+ sesame send 停止 # emit on the default remote
67
+ sesame send 停止 --remote ac
68
+ sesame list # list the keys registered on a remote
69
+ ```
70
+
71
+ ### Advanced operations
72
+
73
+ ```bash
74
+ # Learn: aim a physical remote at the Hub3 and press a button
75
+ sesame ir learn ac 強風 # learn the "強風" key onto remote=ac
76
+ # → Hub3 into REGISTER mode → capture waveform → back to CONTROL → addIRCode
77
+
78
+ # Mode control
79
+ sesame ir mode get [hub3] # get the current mode (0=CONTROL / 1=REGISTER)
80
+ sesame ir mode set 1 [hub3] # force a switch to REGISTER (for debugging)
81
+
82
+ # Key CRUD
83
+ sesame ir key rename ac 強風 強運転 # rename a key (server + config)
84
+ sesame ir key rm ac 試運転 # delete a key
85
+
86
+ # Remote CRUD (server side)
87
+ sesame ir remote-list ac # registered remotes (by irType)
88
+ sesame ir remote-rm ac # delete from server
89
+ sesame ir remote-rename "リビング" ac # change the server alias
90
+
91
+ # Preset DB
92
+ sesame ir search ac ダイキン # manufacturer DB search (max 1000)
93
+ sesame ir match ac <hex波形> # match a learned waveform against known remotes
94
+ ```
95
+
96
+ > To refer to a self-learned remote, use the real type `0xFE00` (65024) for `irType`. Passing the menu id `0xFEFF` makes the server match fail and the remote is not found. See [architecture.md](./architecture.md) for details.
97
+
98
+ ---
99
+
100
+ ## Device management
101
+
102
+ ```bash
103
+ sesame device user-ls # list personal devices
104
+ sesame device status <uuid> # current state
105
+ sesame device rename <uuid> "玄関 SESAME" # rename
106
+ sesame device rm <uuid> # remove from the company
107
+
108
+ sesame history <uuid> # lock open/close history
109
+ sesame history # all devices
110
+ sesame battery <uuid> # battery history (light/heavy voltage + percentage)
111
+ sesame firmware # list firmware currently being distributed
112
+ ```
113
+
114
+ ---
115
+
116
+ ## WebAPI proxy
117
+
118
+ Set the REST API key (apiKeyId) issued in the biz3 dev console as `config.apiKeyId`, and you can proxy any REST WebAPI call over the WebSocket:
119
+
120
+ ```bash
121
+ # with "apiKeyId": "..." in config.json:
122
+ sesame webapi webapi_ssm_shadow_get --query '{"device_id":"..."}'
123
+ sesame webapi webapi_history_get --query '{"device_id":"...","page":0,"lg":"ja","isBiz":true}'
124
+ sesame webapi webapi_cmd_send --body '{"device_id":"...","cmd":83,"sign":"...","history":"..."}'
125
+ ```
126
+
127
+ ---
128
+
129
+ ## Scheduling (biz3Schedule)
130
+
131
+ ```bash
132
+ sesame schedule ls # list registered schedules (lock/unlock/upgrade_firmware)
133
+ sesame schedule cancel <id> # cancel a schedule (omit id to pick interactively from the list)
134
+ ```
135
+
136
+ > Since **biz3 web has no op to create a schedule**, the CLI offers only list / cancel.
137
+
138
+ ---
139
+
140
+ ## Access control (NFC cards / passcodes)
141
+
142
+ The **server-DB sync** ops for SESAME Touch (Pro) NFC cards and keypad passcodes.
143
+ Writing to the device firmware itself goes through a separate path (BLE); this layer handles only the DB-side sync — a two-layer structure.
144
+
145
+ ```bash
146
+ sesame access cards ls --device <uuid> [--device <uuid2> ...] # list cards
147
+ sesame access cards clear --device <uuid> # delete all cards on the given device
148
+ sesame access cards rm --json '[{"deviceID":"...","cardID":"..."}]' # delete individually (no response)
149
+ sesame access cards owner <cardID> [ownerSubUUID] # assign an owner ('' to clear)
150
+ sesame access passcodes ls --device <uuid> # list passcodes
151
+ ```
152
+
153
+ > `rm` (delCards/delPasscodes) has no response handler in biz3 and is **fire-and-forget**. No completion response is returned.
154
+
155
+ ---
156
+
157
+ ## Company / org management (biz3 enterprise)
158
+
159
+ Enterprise features for handling multiple companies, employees, roles, and device groups. `companyID` is filled in automatically from your login.
160
+
161
+ ```bash
162
+ # Company
163
+ sesame company ls # list the companies you belong to
164
+ sesame company rename "新社名" # rename the preferred company
165
+ sesame company add "新会社" # register a new company
166
+ sesame company payment # get billing settings
167
+
168
+ # Org
169
+ sesame org employee ls # list employees
170
+ sesame org employee search <kw> # cross-CS user search
171
+ sesame org role ls # list role tags
172
+ sesame org group ls # list employee groups
173
+ sesame org device-group ls # list device groups
174
+ sesame org keys device <deviceUUID> # enumerate employees holding a key for the device
175
+ ```
176
+
177
+ ### Guest sharing (key-sharing URL / QR)
178
+
179
+ Generates the same `ssm://UI?t=sk&sk=…&l=…&n=…` URL that the SESAME app reads as a sharing QR.
180
+ Only with `--level 2` (guest) is a single-use `guestKeyId` issued and embedded (same behavior as biz3).
181
+
182
+ ```bash
183
+ sesame org keys share-url --device <uuid> --level 2 --name "来客用" # guest sharing URL
184
+ sesame org keys share-url --device <uuid> --level 1 # manager key sharing
185
+ sesame org keys share-url --device <uuid> --qr # show a QR in the terminal (requires qrcode-terminal)
186
+ ```
187
+
188
+ > Building and parsing the sharing URL is a 1:1 port of biz3 `generateInviteGuestQRCodeByInfo` / `readQrcode`.
189
+ > It is **independent of any image library**, so you can paste the output URL into any QR generator to share.
190
+ > Many create/update ops take a struct via `--json '<…>'` (each subcommand's `--help` has examples).
191
+ > Note that `org employee confirm <email>` signs out the current session on success, per the biz3 spec.
192
+
193
+ ---
194
+
195
+ ## Hub3 IoT control (biz3OperateIoT)
196
+
197
+ Direct commands to the Hub3 itself (LED dimming, LTE relay, firmware update, Matter pairing, etc.).
198
+ Pass `--device <hub3UUID> --secret <hex>`, or select from connected devices when interactive.
199
+
200
+ ```bash
201
+ sesame iot led 80 --device <uuid> --secret <hex> # LED dimming (0-100)
202
+ sesame iot led --get --device <uuid> --secret <hex># get the current dimming level
203
+ sesame iot relay on --device <uuid> --secret <hex># LTE relay open/close
204
+ sesame iot firmware-update --device <uuid> --secret <hex> --wait 60
205
+ sesame iot matter-code --device <uuid> --secret <hex> # Matter pairing code
206
+ ```
207
+
208
+ ---
209
+
210
+ ## Preset IR remotes (HXD command)
211
+
212
+ Emit air conditioners and the like **from preset DB commands** rather than by "learning". Specify the Hub3 as `--device`:
213
+
214
+ ```bash
215
+ sesame preset-ir air --device <hub3uuid> --code <n> --power --temp 26 --mode 1 --fan 2
216
+ sesame preset-ir button --device <hub3uuid> --code <n> --button power --irtype 8192
217
+ sesame preset-ir send --device <hub3uuid> --command <hex> --irtype 49152 # emit raw hex
218
+ ```
219
+
220
+ > Preset command generation (biz3's HXDCommandProcessor) is not yet ported, so preset emit does not currently work.
221
+ > Use a self-learned remote (`sesame ir learn`) instead ([known limitations](../README.md#known-limitations)).
222
+
223
+ ---
224
+
225
+ ## BLE direct control (without the cloud)
226
+
227
+ Operate registered SESAME devices **directly** over the PC's Bluetooth. Since it does not go through the cloud (WS), it works offline, and **settings such as `autolock` that the cloud could not apply do take effect on the device**.
228
+
229
+ BLE operation is not a dedicated command — just **add `--ble-only`** to a device-subject operation
230
+ (`autolock` is BLE-required, so it goes over BLE automatically even without the flag):
231
+
232
+ ```bash
233
+ sesame front status --ble-only # current state (locked / unlocked, position)
234
+ sesame front unlock --ble-only # unlock (Lock / Bike)
235
+ sesame front lock --ble-only # lock (Lock)
236
+ sesame front toggle --ble-only # invert based on current state (Lock)
237
+ sesame kitchen click --ble-only # SESAME Bot click (Bot2/Bot3)
238
+ sesame front autolock 30 # autolock (BLE required. Actually takes effect)
239
+ sesame front autolock 0 # disable
240
+ ```
241
+
242
+ > **BLE errors are given meaning via `SesameResultCode`** — when a device returns a non-zero result, the library throws
243
+ > `BleResultError` (`.resultCode` / `.resultName`). `resultName` matches the official SesameSDK's
244
+ > `SesameResultCode` (`success`/`invalidFormat`/`notSupported`/`invalidSig`/`notFound`/`unknown`/
245
+ > `busy`/`invalidParam`/`invalidAction`), so you can branch on it programmatically.
246
+ > Note: this is the **device-layer (SesameOS3) taxonomy** and is available only over the BLE direct route
247
+ > (the cloud route does not surface this code, so it does not appear in `sesame serve`'s `kind`).
248
+
249
+ ### Operations per device type (per the official SesameSDK)
250
+
251
+ The operation set differs by device type. The SDK defines capabilities asymmetrically per type, and this CLI reproduces the same asymmetry by determining the type from the `model` in `config`. Unsupported operations are rejected by the command (e.g. `lock` on a Bot → "use click").
252
+
253
+ | Type (model examples) | BLE operations | mechStatus |
254
+ |---|---|---|
255
+ | Lock `sesame_5`/`_pro`/`sesame_6`/`_pro`/`_us`/`miwa` | `lock` `unlock` `toggle` `autolock` `status` | locked/unlocked + position |
256
+ | Bot `bot_2`/`bot_3` | `click` `status` | locked/unlocked (no position) |
257
+ | Bike `bike_2`/`bike_3` | `unlock` `status` | locked/unlocked (no position) |
258
+ | Touch/Face/Sensor/Remote, Hub3, WiFiModule2 | (no BLE lock operations) | — |
259
+ | OS2 `sesame_2`/`_4`, `ssmbot_1`, `bike_1` | BLE not implemented (key derivation/crypto is a separate path). Operate over cloud | — |
260
+
261
+ > "locked/unlocked" is only the **two values** based on the presence of `isInLockRange` in OS3. OS3 has no intermediate (moved) state
262
+ > (only OS2 devices such as Sesame2 have moved). For the BLE implementation design, see [architecture.md](./architecture.md).
263
+
264
+ Usable as a library too:
265
+
266
+ ```js
267
+ import { SesameBle } from "sesame-kit"; // or: import { ble } from "sesame-kit"
268
+ await SesameBle.use({ deviceUUID, secretKey }, async (lock) => {
269
+ await lock.unlock();
270
+ await lock.autolock(30);
271
+ console.log(lock.lastStatus); // { state, batteryMv, position, ... }
272
+ });
273
+ ```
274
+
275
+ > The target is **SesameOS3** (SESAME 5 / 5 Pro / Touch, etc.). New pairing (registering an unregistered device) is a separate phase.
276
+
277
+ ---
278
+
279
+ ## Interactive session
280
+
281
+ The interactive session (`sesame` / `sesame <device>` / `sesame session`) is an **app-like all-routes mode**.
282
+ It lists **every device you can operate**: Locks/Bots/Bikes (BLE + cloud) and, if you are logged in, **Hub3** (cloud: IR send / relay / LED).
283
+ It attaches BLE best-effort but **does not exit even when BLE is zero**: devices out of range or without permission are **operated over cloud** when you are logged in (devices with a BLE connection prefer BLE = lower latency + autolock available).
284
+
285
+ ```text
286
+ $ sesame # all devices (alias: sesame session / watch)
287
+ [ble] バックグラウンドで接続中... (クラウドで操作可能)
288
+ ─── SESAME セッション ── 矢印キーで選択 ───
289
+ front [sesame_5·BLE]: state=locked pos=-176
290
+ kitchen [bot_2·cloud]: (BLE未接続)
291
+ hub3-居間 [hub3·hub3]: (Hub3: IR / リレー / LED)
292
+
293
+ ? 操作するデバイス ← ① pick a device
294
+ ? front の操作 ← ② pick an operation (varies by type)
295
+ ロック : 🔓 解錠 / 🔒 施錠 / ↕ トグル / ⏱ オートロック / ℹ 状態
296
+ Bot : 👆 クリック / ℹ 状態
297
+ Hub3 : 📡 IR 送信 (リモコン→キー選択) / 🔌 リレー ON/OFF / 💡 LED 調光
298
+ ```
299
+
300
+ The trailing tag on each device, `·BLE` / `·cloud`, is the route. Because **`autolock` is BLE-required**, cloud devices are prompted to "move closer and retry". If only one connection exists, device selection is skipped.
301
+
302
+ **Live updates**: the screen is a live dashboard built with **Ink (React for CLI)** and **re-renders in place** as BLE state changes or background connections complete (cloud→BLE promotion is real-time too). Startup shows the menu immediately over cloud and connects BLE in the background, so you don't wait the 8-second scan. Quit with `q` / Esc.
303
+
304
+ **Prerequisites**:
305
+ - Keys reuse the existing `config.locks` (deviceUUID/secretKey imported via `sesame locks sync-from-devices`). No new registration needed.
306
+ - The BLE adapter `@abandonware/noble` is required. As an `optionalDependency`, `npm install` tries to **install it automatically**, and on unsupported environments the install itself still succeeds (only BLE is disabled). To install it manually, `npm i @abandonware/noble`.
307
+ - **macOS requires Bluetooth permission for Terminal/iTerm** (System Settings → Privacy & Security → Bluetooth).
308
+ - Be within BLE range (close proximity) of the lock.
@@ -0,0 +1,152 @@
1
+ <!-- [English](./library.md) | 日本語 -->
2
+
3
+ # ライブラリとして使う
4
+
5
+ > English: [library.md](./library.md)
6
+
7
+ `sesame` CLI と同じ機能を Node.js から直接呼べる。他言語から使うなら [`sesame serve`](../README.ja.md#言語非依存バックエンド-sesame-serve) を、Node 内で使うならこちら。
8
+
9
+ ## 一番楽な形: `use()` ヘルパ (auto connect/close)
10
+
11
+ ```js
12
+ import { SesameHub3 } from "sesame-kit";
13
+
14
+ await SesameHub3.use(async (hub) => {
15
+ await hub.unlock("front");
16
+ await hub.send("ac", "停止");
17
+ });
18
+ // connect / close は自動。例外時も close される。
19
+ ```
20
+
21
+ 設定ディレクトリを変えたい:
22
+
23
+ ```js
24
+ await SesameHub3.use({ configDir: "/tmp/cfg" }, async (hub) => {...});
25
+ ```
26
+
27
+ config ファイル不要で in-memory token を使いたい (他プロジェクト埋込み等):
28
+
29
+ ```js
30
+ await SesameHub3.use({
31
+ tokenStore: {
32
+ // load() が返す idToken は実際の Cognito 由来の JWT である必要があります:
33
+ // - exp クレーム (UNIX秒) が「現在時刻 + 60秒」より先 でないと毎回 refresh が走る
34
+ // - sub クレーム が UUID 形式。ロック操作の history (誰が操作したか) に使われるため必須。
35
+ // → 通常は `sesame login` で取得し FileTokenStore に保存された値をそのまま使う。
36
+ // 独自 store は「その値を別の場所から load/save する」だけで、idToken を自作しない。
37
+ load() { return { idToken, refreshToken, clientId: "6ialca0p8u0lsgvbmvsljfm305" }; },
38
+ save(t) { /* persist however */ },
39
+ clear() {}, loadPending() { return null; }, savePending() {}, clearPending() {},
40
+ },
41
+ config: { companyID: "ch_X", wsUrl: "wss://..." }, // companyID/wsUrl は省略可 (DEFAULT_CONFIG が補完)
42
+ }, async (hub) => {
43
+ await hub.unlockDevice({ deviceUUID: "...", secretKey: "..." });
44
+ });
45
+ ```
46
+
47
+ ## Config を介さない直接 API (name lookup なし)
48
+
49
+ ```js
50
+ await SesameHub3.use(async (hub) => {
51
+ // ロック (config の locks 定義に頼らず deviceUUID + secretKey 直指定)
52
+ await hub.unlockDevice({ deviceUUID, secretKey });
53
+ await hub.lockDevice({ deviceUUID, secretKey });
54
+ await hub.toggleDevice({ deviceUUID, secretKey });
55
+ await hub.botClickDevice({ deviceUUID, secretKey });
56
+ await hub.triggerLockDevice({ deviceUUID, secretKey, cmd: 83 }); // 任意 cmd
57
+
58
+ // IR
59
+ await hub.sendIRDirect({
60
+ hub3DeviceId, irDeviceUUID, irType: 49152, command: keyUUID, operation: "learnEmit",
61
+ });
62
+ const keys = await hub.getIRCodesDirect({ hub3DeviceId, irDeviceUUID });
63
+ });
64
+ ```
65
+
66
+ ## イベント購読 (state push)
67
+
68
+ ```js
69
+ await SesameHub3.use(async (hub) => {
70
+ // 設定名でロック状態の push を購読
71
+ const off1 = hub.onLockStateChange("front", (msg) => {
72
+ console.log("front state:", msg.data?.state);
73
+ });
74
+
75
+ // UUID 直指定でも OK
76
+ const off2 = hub.onLockStateChangeDevice(deviceUUID, (msg) => { ... });
77
+
78
+ // IR 学習データを受信 (内部で setIRMode + subscribeIRData を発行、unsubscribe で元に戻す)
79
+ const offLearn = await hub.onIRLearned("livinghub3", (irData) => {
80
+ console.log("captured:", irData);
81
+ });
82
+
83
+ // デバイス state 一括購読 (subscribeDevicesUpdate)
84
+ const off3 = hub.onDeviceUpdate(
85
+ [{ deviceUUID, deviceModel: "sesame_5_pro" }],
86
+ (msg) => console.log(msg),
87
+ );
88
+
89
+ await new Promise((r) => setTimeout(r, 30_000));
90
+ off1(); off2(); off3();
91
+ await offLearn();
92
+ });
93
+ ```
94
+
95
+ ## 名前ベースの古い API (config 必須)
96
+
97
+ ```js
98
+ import { SesameHub3 } from "sesame-kit";
99
+
100
+ const hub = await SesameHub3.fromConfig();
101
+ await hub.connect();
102
+ try {
103
+ await hub.unlock("front");
104
+ await hub.send("ac", "停止");
105
+ await hub.learnIR("ac", "強風", { onPrompt: () => console.log("ボタン押して") });
106
+ const devs = await hub.listDevices();
107
+ const hist = await hub.getDeviceHistory([{ deviceUUID: devs[0].deviceUUID }]);
108
+ } finally {
109
+ await hub.close();
110
+ }
111
+ ```
112
+
113
+ ## 低レベル import (transport / op 関数 / crypto を直接)
114
+
115
+ メインエントリ (`"sesame-kit"`) から取れるもの:
116
+
117
+ ```js
118
+ import {
119
+ Hub3WsClient, // WebSocket + reconnect/keepalive/queue/sleep 検知
120
+ sendIR, getIRCodes, // IR 基本 op (named export)
121
+ triggerLock, lockLock, lockUnlock, lockToggle, botClick, // lock 個別関数 (named export)
122
+ ir, devices, crypto, lock, auth, // ← これらは namespace export (オブジェクト)
123
+ FileTokenStore, ConfigStore, configPaths,
124
+ } from "sesame-kit";
125
+
126
+ // namespace は メソッドをドット経由で呼ぶ:
127
+ crypto.cmacTime("..."); // ✅ メインから取れるのは namespace の crypto
128
+ auth.getValidIdToken(store); // ✅ 同上
129
+ // ⚠️ import { cmacTime } from "sesame-kit" は不可 (cmacTime は crypto namespace の中)
130
+ ```
131
+
132
+ 個別関数を named import したい場合はサブパス (`package.json` の exports map) から:
133
+
134
+ ```js
135
+ import { cmacTime } from "sesame-kit/crypto"; // ✅ サブパスなら named でOK
136
+ import { learnIRKey } from "sesame-kit/ir";
137
+ import { lockLock } from "sesame-kit/lock";
138
+ ```
139
+
140
+ ## TypeScript
141
+
142
+ `.d.ts` 型定義を同梱しています (`types/`、JSDoc から `tsc` で生成)。`moduleResolution: "node16" / "nodenext" / "bundler"` で
143
+ パッケージ名 import (`from "sesame-kit"` / `"sesame-kit/crypto"` 等) すれば型が効きます:
144
+
145
+ ```ts
146
+ import { SesameHub3 } from "sesame-kit";
147
+ await SesameHub3.use(async (hub) => {
148
+ await hub.unlockDevice({ deviceUUID: "...", secretKey: "..." }); // 引数が型チェックされる
149
+ });
150
+ ```
151
+
152
+ 型は `npm run build:types` で再生成できます (ソースの JSDoc を編集したら実行)。
@@ -0,0 +1,152 @@
1
+ <!-- English | [日本語](./library.ja.md) -->
2
+
3
+ # Using sesame-kit as a library
4
+
5
+ > 日本語: [library.ja.md](./library.ja.md)
6
+
7
+ The same features as the `sesame` CLI can be called directly from Node.js. To use it from other languages, use [`sesame serve`](../README.md#language-agnostic-backend-sesame-serve); to use it inside Node, use this.
8
+
9
+ ## The simplest form: the `use()` helper (auto connect/close)
10
+
11
+ ```js
12
+ import { SesameHub3 } from "sesame-kit";
13
+
14
+ await SesameHub3.use(async (hub) => {
15
+ await hub.unlock("front");
16
+ await hub.send("ac", "停止");
17
+ });
18
+ // connect / close are automatic, including close on exceptions.
19
+ ```
20
+
21
+ To change the config directory:
22
+
23
+ ```js
24
+ await SesameHub3.use({ configDir: "/tmp/cfg" }, async (hub) => {...});
25
+ ```
26
+
27
+ To use an in-memory token without a config file (e.g. embedding in another project):
28
+
29
+ ```js
30
+ await SesameHub3.use({
31
+ tokenStore: {
32
+ // The idToken returned by load() must be a real Cognito-issued JWT:
33
+ // - the exp claim (UNIX seconds) must be later than "now + 60s", or a refresh runs every time.
34
+ // - the sub claim must be in UUID format. It is used for lock-operation history (who operated it), so it is required.
35
+ // → Normally use the value obtained via `sesame login` and saved by FileTokenStore as-is.
36
+ // A custom store only "loads/saves that value from/to a different place"; it does not fabricate the idToken.
37
+ load() { return { idToken, refreshToken, clientId: "6ialca0p8u0lsgvbmvsljfm305" }; },
38
+ save(t) { /* persist however */ },
39
+ clear() {}, loadPending() { return null; }, savePending() {}, clearPending() {},
40
+ },
41
+ config: { companyID: "ch_X", wsUrl: "wss://..." }, // companyID/wsUrl are optional (DEFAULT_CONFIG fills them in)
42
+ }, async (hub) => {
43
+ await hub.unlockDevice({ deviceUUID: "...", secretKey: "..." });
44
+ });
45
+ ```
46
+
47
+ ## Direct API without config (no name lookup)
48
+
49
+ ```js
50
+ await SesameHub3.use(async (hub) => {
51
+ // Lock (pass deviceUUID + secretKey directly, without relying on the config locks definitions)
52
+ await hub.unlockDevice({ deviceUUID, secretKey });
53
+ await hub.lockDevice({ deviceUUID, secretKey });
54
+ await hub.toggleDevice({ deviceUUID, secretKey });
55
+ await hub.botClickDevice({ deviceUUID, secretKey });
56
+ await hub.triggerLockDevice({ deviceUUID, secretKey, cmd: 83 }); // arbitrary cmd
57
+
58
+ // IR
59
+ await hub.sendIRDirect({
60
+ hub3DeviceId, irDeviceUUID, irType: 49152, command: keyUUID, operation: "learnEmit",
61
+ });
62
+ const keys = await hub.getIRCodesDirect({ hub3DeviceId, irDeviceUUID });
63
+ });
64
+ ```
65
+
66
+ ## Event subscription (state push)
67
+
68
+ ```js
69
+ await SesameHub3.use(async (hub) => {
70
+ // Subscribe to lock-state push by config name
71
+ const off1 = hub.onLockStateChange("front", (msg) => {
72
+ console.log("front state:", msg.data?.state);
73
+ });
74
+
75
+ // Passing a UUID directly also works
76
+ const off2 = hub.onLockStateChangeDevice(deviceUUID, (msg) => { ... });
77
+
78
+ // Receive IR learning data (internally issues setIRMode + subscribeIRData, and reverts on unsubscribe)
79
+ const offLearn = await hub.onIRLearned("livinghub3", (irData) => {
80
+ console.log("captured:", irData);
81
+ });
82
+
83
+ // Bulk-subscribe to device state (subscribeDevicesUpdate)
84
+ const off3 = hub.onDeviceUpdate(
85
+ [{ deviceUUID, deviceModel: "sesame_5_pro" }],
86
+ (msg) => console.log(msg),
87
+ );
88
+
89
+ await new Promise((r) => setTimeout(r, 30_000));
90
+ off1(); off2(); off3();
91
+ await offLearn();
92
+ });
93
+ ```
94
+
95
+ ## The older name-based API (config required)
96
+
97
+ ```js
98
+ import { SesameHub3 } from "sesame-kit";
99
+
100
+ const hub = await SesameHub3.fromConfig();
101
+ await hub.connect();
102
+ try {
103
+ await hub.unlock("front");
104
+ await hub.send("ac", "停止");
105
+ await hub.learnIR("ac", "強風", { onPrompt: () => console.log("press the button") });
106
+ const devs = await hub.listDevices();
107
+ const hist = await hub.getDeviceHistory([{ deviceUUID: devs[0].deviceUUID }]);
108
+ } finally {
109
+ await hub.close();
110
+ }
111
+ ```
112
+
113
+ ## Low-level imports (transport / op functions / crypto directly)
114
+
115
+ Available from the main entry (`"sesame-kit"`):
116
+
117
+ ```js
118
+ import {
119
+ Hub3WsClient, // WebSocket + reconnect/keepalive/queue/sleep detection
120
+ sendIR, getIRCodes, // IR base ops (named export)
121
+ triggerLock, lockLock, lockUnlock, lockToggle, botClick, // individual lock functions (named export)
122
+ ir, devices, crypto, lock, auth, // ← these are namespace exports (objects)
123
+ FileTokenStore, ConfigStore, configPaths,
124
+ } from "sesame-kit";
125
+
126
+ // Call namespace methods via dot:
127
+ crypto.cmacTime("..."); // ✅ what you get from the main entry is the crypto namespace
128
+ auth.getValidIdToken(store); // ✅ same as above
129
+ // ⚠️ import { cmacTime } from "sesame-kit" does not work (cmacTime is inside the crypto namespace)
130
+ ```
131
+
132
+ To named-import individual functions, use the subpath (the `exports` map in `package.json`):
133
+
134
+ ```js
135
+ import { cmacTime } from "sesame-kit/crypto"; // ✅ named works on a subpath
136
+ import { learnIRKey } from "sesame-kit/ir";
137
+ import { lockLock } from "sesame-kit/lock";
138
+ ```
139
+
140
+ ## TypeScript
141
+
142
+ `.d.ts` type definitions are bundled (`types/`, generated from JSDoc with `tsc`). With `moduleResolution: "node16" / "nodenext" / "bundler"`,
143
+ package-name imports (`from "sesame-kit"` / `"sesame-kit/crypto"` etc.) get types:
144
+
145
+ ```ts
146
+ import { SesameHub3 } from "sesame-kit";
147
+ await SesameHub3.use(async (hub) => {
148
+ await hub.unlockDevice({ deviceUUID: "...", secretKey: "..." }); // arguments are type-checked
149
+ });
150
+ ```
151
+
152
+ Types can be regenerated with `npm run build:types` (run it after editing the JSDoc in the source).
@@ -0,0 +1,13 @@
1
+ <!-- [English](./migration.md) | 日本語 -->
2
+
3
+ # 旧版からのマイグレーション
4
+
5
+ > English: [migration.md](./migration.md)
6
+
7
+ 旧 `sesame-hub3` (CLI=`hub3-ir`) からのアップグレード:
8
+
9
+ - CLI 名は `sesame` に変更 (旧 `hub3-ir` は廃止)。シェルスクリプトを使っている場合は置換。
10
+ - 設定ディレクトリ (`~/.config/sesame-hub3`) は変更なし、既存 config.json はそのまま使える。
11
+ - `locks` キーは自動で追加される (空 `{}` から開始)。`sesame locks sync-from-devices` で `devices` コマンドの出力から取り込み可能。
12
+
13
+ 旧 `.env + .tokens.json + keys.json` からの移行は `sesame migrate` がそのまま使える。
@@ -0,0 +1,13 @@
1
+ <!-- English | [日本語](./migration.ja.md) -->
2
+
3
+ # Migrating from older versions
4
+
5
+ > 日本語: [migration.ja.md](./migration.ja.md)
6
+
7
+ Upgrading from the old `sesame-hub3` (CLI = `hub3-ir`):
8
+
9
+ - The CLI is renamed to `sesame` (the old `hub3-ir` is removed). Replace it in any shell scripts.
10
+ - The config directory (`~/.config/sesame-hub3`) is unchanged; an existing config.json works as-is.
11
+ - The `locks` key is added automatically (starting from an empty `{}`). Import from the `devices` command output with `sesame locks sync-from-devices`.
12
+
13
+ Migrating from an old `.env` + `.tokens.json` + `keys.json` works with `sesame migrate`.