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
package/package.json ADDED
@@ -0,0 +1,114 @@
1
+ {
2
+ "name": "sesame-kit",
3
+ "version": "0.4.0",
4
+ "description": "SESAME cloud CLI & library (lock control + Hub3 IR + device management). Node.js port of biz3 React app with the Cognito consumer client swapped in for long-lived sessions.",
5
+ "author": "Ikuma Fukumoto",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./src/index.js",
9
+ "types": "./types/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./types/index.d.ts",
13
+ "default": "./src/index.js"
14
+ },
15
+ "./auth": {
16
+ "types": "./types/auth.d.ts",
17
+ "default": "./src/auth.js"
18
+ },
19
+ "./transport": {
20
+ "types": "./types/transport.d.ts",
21
+ "default": "./src/transport.js"
22
+ },
23
+ "./config": {
24
+ "types": "./types/config.d.ts",
25
+ "default": "./src/config.js"
26
+ },
27
+ "./tokens": {
28
+ "types": "./types/tokens.d.ts",
29
+ "default": "./src/tokens.js"
30
+ },
31
+ "./crypto": {
32
+ "types": "./types/crypto.d.ts",
33
+ "default": "./src/crypto.js"
34
+ },
35
+ "./lock": {
36
+ "types": "./types/lock.d.ts",
37
+ "default": "./src/lock.js"
38
+ },
39
+ "./ir": {
40
+ "types": "./types/ir.d.ts",
41
+ "default": "./src/ir.js"
42
+ },
43
+ "./devices": {
44
+ "types": "./types/devices.d.ts",
45
+ "default": "./src/devices.js"
46
+ }
47
+ },
48
+ "bin": {
49
+ "sesame": "./bin/sesame.js"
50
+ },
51
+ "files": [
52
+ "bin/",
53
+ "src/",
54
+ "types/",
55
+ "vendor/",
56
+ "clients/",
57
+ "docs/",
58
+ "README.md",
59
+ "README.ja.md",
60
+ "LICENSE",
61
+ "LICENSE.biz3"
62
+ ],
63
+ "keywords": [
64
+ "sesame",
65
+ "candy-house",
66
+ "smart-lock",
67
+ "smart-home",
68
+ "cli",
69
+ "json-rpc",
70
+ "ble"
71
+ ],
72
+ "homepage": "https://github.com/FukumotoIkuma/sesame-kit#readme",
73
+ "repository": {
74
+ "type": "git",
75
+ "url": "git+https://github.com/FukumotoIkuma/sesame-kit.git"
76
+ },
77
+ "bugs": {
78
+ "url": "https://github.com/FukumotoIkuma/sesame-kit/issues"
79
+ },
80
+ "scripts": {
81
+ "cli": "node bin/sesame.js",
82
+ "test": "vitest run",
83
+ "test:watch": "vitest",
84
+ "build:types": "tsc -p tsconfig.json",
85
+ "build:rpc-schema": "node scripts/gen-rpc-schema.mjs",
86
+ "build:grpc-proto": "node scripts/gen-grpc-proto.mjs",
87
+ "build": "tsc -p tsconfig.json && node scripts/gen-rpc-schema.mjs && node scripts/gen-grpc-proto.mjs",
88
+ "prepack": "tsc -p tsconfig.json && node scripts/gen-rpc-schema.mjs && node scripts/gen-grpc-proto.mjs"
89
+ },
90
+ "dependencies": {
91
+ "@aws-sdk/client-cognito-identity-provider": "^3.1057.0",
92
+ "@grpc/grpc-js": "^1.14.4",
93
+ "@grpc/proto-loader": "^0.8.1",
94
+ "@inquirer/prompts": "^8.5.2",
95
+ "commander": "^15.0.0",
96
+ "ink": "^7.0.5",
97
+ "ink-select-input": "^6.2.0",
98
+ "ink-text-input": "^6.0.0",
99
+ "node-aes-cmac": "^0.1.1",
100
+ "react": "^19.2.7",
101
+ "ws": "^8.18.0"
102
+ },
103
+ "engines": {
104
+ "node": ">=18"
105
+ },
106
+ "devDependencies": {
107
+ "ink-testing-library": "^4.0.0",
108
+ "typescript": "^6.0.3",
109
+ "vitest": "^4.1.7"
110
+ },
111
+ "optionalDependencies": {
112
+ "@abandonware/noble": "^1.9.2-25"
113
+ }
114
+ }
package/src/access.js ADDED
@@ -0,0 +1,375 @@
1
+ // SESAME Touch (Pro) のアクセス制御データ管理 — NFC カード / キーパッド暗証番号 (passcode)。
2
+ //
3
+ // Ported from biz3 (CANDY-HOUSE/biz3, MIT):
4
+ // - vendor reference: references_web/src/api/useManageAuthData.js
5
+ //
6
+ // すべての op は WS action `biz3ManageAccessCtlAuthData` 上で動き、op で分岐する。
7
+ // ログイン済みセッションでサーバ側 DB を操作する層で、ここは「WS の DB 同期 op」に専念する。
8
+ //
9
+ // ⚠️ 2層構造の注意 (biz3 の設計):
10
+ // カード/パスコードの実ファームウェア書き込みは BLE (iotCmd, topic=`stp${uuid}cmd`) 経由で行い、
11
+ // 本モジュールの WS op は「サーバ DB 側の同期」を担う。実機への add/delete の物理書き込みは
12
+ // 別モジュール (biz3OperateIoT 系) の責務であり、ここでは扱わない。
13
+ // biz3 では BLE で実機を変更 → その ack コールバック内で本 WS op を投げて DB を追従させる。
14
+ //
15
+ // ⚠️ 取得 (getCards/getPasscodes) の応答は **2系統** で届く (useManageAuthData.js:116-191):
16
+ // (1) 完了通知: { action, op:'getCards' } ← data 本体なし。fetch 完了の合図のみ。
17
+ // (2) データ本体: { action, op:'pubCardLinkedIDs', data:{ deviceUUID, page, list } }
18
+ // ← page===1 で list 置換、それ以外は累積 (ページング)。
19
+ // passcode は op が 'getPasscodes' / 'pubPasscodeLinkedIDs' になる (同型)。
20
+
21
+ import { ACTION_TYPES } from "../vendor/biz3/constants/messageConstants.js";
22
+ import { assertSuccess } from "./util.js";
23
+
24
+ // action 文字列は vendor (biz3 messageConstants:9) から引く (手書きしない)。
25
+ const ACTION = ACTION_TYPES.BIZ3_MANAGE_AC_AUTHDATA; // "biz3ManageAccessCtlAuthData"
26
+
27
+ // async push の応答 op 名。biz3utils 由来の定数 (useManageAuthData.js:12-13)。
28
+ const PUB_CARD_LINKED_IDS = "pubCardLinkedIDs";
29
+ const PUB_PASSCODE_LINKED_IDS = "pubPasscodeLinkedIDs";
30
+
31
+ const DEFAULT_TIMEOUT_MS = 15_000;
32
+
33
+ // ---------- 内部: getXxx (完了通知 + pub データ push の集約) ----------
34
+
35
+ /**
36
+ * getCards / getPasscodes を投げ、pub*LinkedIDs の async push をページング集約して返す共通処理。
37
+ *
38
+ * biz3 (useManageAuthData.js:50-63,116-132,176-191) のフロー:
39
+ * 1. { action, obj:{ devices: 'uuid1,uuid2,...' }, op } を送信 (devices はカンマ連結文字列)。
40
+ * 2. サーバは対象デバイスごとに op='pubCardLinkedIDs'/'pubPasscodeLinkedIDs' で
41
+ * { data:{ deviceUUID, page, list } } を複数回 push (page でページング)。
42
+ * 3. 最後に完了通知 { op:'getCards'/'getPasscodes' } (data 無し) が届く。
43
+ *
44
+ * CLI では (1) 送信 → (2) pub を集約 → (3) 完了通知 or timeout で確定、という流れで
45
+ * デバイス横断の一覧をまとめて返す。biz3 の handleDeviceCardData (124-131) と同じく
46
+ * deviceUUID ごとに page===1 で置換 / それ以外で追記する。
47
+ *
48
+ * @param {import("./transport.js").Hub3WsClient} client
49
+ * @param {object} cfg
50
+ * @param {string} cfg.op 送信 op ('getCards' | 'getPasscodes')
51
+ * @param {string} cfg.pubOp データ push の op ('pubCardLinkedIDs' | 'pubPasscodeLinkedIDs')
52
+ * @param {string} cfg.idKey 集約キー ('cardID' | 'passwordID')
53
+ * @param {string[]} cfg.deviceUUIDs 対象 deviceUUID 配列
54
+ * @param {number} cfg.timeoutMs
55
+ * @returns {Promise<{byDevice: Record<string, object[]>, items: object[]}>}
56
+ * byDevice: deviceUUID → そのデバイスに紐づく要素配列
57
+ * items: idKey 単位に集約し uuids(=該当 deviceUUID 群) を付与した横断リスト
58
+ */
59
+ async function fetchAuthData(client, { op, pubOp, idKey, deviceUUIDs, timeoutMs }) {
60
+ if (!Array.isArray(deviceUUIDs) || deviceUUIDs.length === 0) {
61
+ return { byDevice: {}, items: [] };
62
+ }
63
+ const deviceIds = deviceUUIDs.join(","); // biz3: devices.map(d=>d.deviceUUID).join(',') (54)
64
+
65
+ return new Promise((resolve, reject) => {
66
+ /** @type {Record<string, object[]>} deviceUUID → list (ページング累積) */
67
+ const byDevice = {};
68
+ let done = false;
69
+
70
+ const finish = () => {
71
+ if (done) return;
72
+ done = true;
73
+ clearTimeout(to);
74
+ unsubPub();
75
+ unsubDone();
76
+ resolve({ byDevice, items: aggregate(byDevice, idKey) });
77
+ };
78
+
79
+ const to = setTimeout(() => {
80
+ if (done) return;
81
+ done = true;
82
+ unsubPub();
83
+ unsubDone();
84
+ reject(new Error(`${op} timeout`));
85
+ }, timeoutMs);
86
+
87
+ // (2) データ本体 push の集約 (useManageAuthData.js:116-131)。
88
+ const unsubPub = client.subscribe(`${ACTION}:${pubOp}`, (msg) => {
89
+ const data = msg?.data;
90
+ if (!data) return;
91
+ const { deviceUUID, page, list = [] } = data;
92
+ if (!deviceUUID) return;
93
+ const current = byDevice[deviceUUID] || [];
94
+ // page===1 なら置換、それ以外は累積 (biz3:126)。
95
+ byDevice[deviceUUID] = page === 1 ? [...list] : [...current, ...list];
96
+ });
97
+
98
+ // (3) 完了通知 (useManageAuthData.js:180-185)。data 本体は無い。
99
+ const unsubDone = client.subscribe(`${ACTION}:${op}`, () => {
100
+ finish();
101
+ });
102
+
103
+ // (1) 取得リクエスト送信 (useManageAuthData.js:55-62)。obj.devices にカンマ連結文字列。
104
+ client.send({ action: ACTION, obj: { devices: deviceIds }, op });
105
+ });
106
+ }
107
+
108
+ /**
109
+ * deviceUUID ごとの list を idKey 単位に集約し、uuids(該当 deviceUUID 群)を付与する。
110
+ * biz3 nfcCards / passcodes useMemo (useManageAuthData.js:134-174) と同じ集約ロジック。
111
+ * @param {Record<string, object[]>} byDevice
112
+ * @param {string} idKey 'cardID' | 'passwordID'
113
+ * @returns {object[]}
114
+ */
115
+ function aggregate(byDevice, idKey) {
116
+ /** @type {Record<string, Set<string>>} */
117
+ const idMap = {};
118
+ const cards = [];
119
+ for (const [deviceUUID, list] of Object.entries(byDevice)) {
120
+ for (const card of list) {
121
+ const id = card[idKey];
122
+ if (!idMap[id]) idMap[id] = new Set();
123
+ idMap[id].add(deviceUUID);
124
+ cards.push(card);
125
+ }
126
+ }
127
+ return cards.map((card) => ({ ...card, uuids: Array.from(idMap[card[idKey]]) }));
128
+ }
129
+
130
+ // ---------- カード: 取得 ----------
131
+
132
+ /**
133
+ * 対象デバイスの NFC カード一覧を取得する。
134
+ * 応答は op='pubCardLinkedIDs' の async push で deviceUUID/page ごとに届くため、
135
+ * 内部で集約してから完了通知 or timeout で確定する (useManageAuthData.js:50-191)。
136
+ *
137
+ * @param {import("./transport.js").Hub3WsClient} client
138
+ * @param {{deviceUUIDs:string[], timeoutMs?:number}} params
139
+ * @returns {Promise<{byDevice: Record<string, object[]>, items: object[]}>}
140
+ * items の各要素: { cardID, nameUUID, name, cardType, subUUID, ..., uuids:string[] }
141
+ */
142
+ export async function getCards(client, { deviceUUIDs, timeoutMs = DEFAULT_TIMEOUT_MS }) {
143
+ return fetchAuthData(client, {
144
+ op: "getCards",
145
+ pubOp: PUB_CARD_LINKED_IDS,
146
+ idKey: "cardID",
147
+ deviceUUIDs,
148
+ timeoutMs,
149
+ });
150
+ }
151
+
152
+ // ---------- パスコード: 取得 ----------
153
+
154
+ /**
155
+ * 対象デバイスの暗証番号 (passcode) 一覧を取得する。getCards と同型。
156
+ * 応答データ本体は op='pubPasscodeLinkedIDs' で届く (useManageAuthData.js:189-191)。
157
+ *
158
+ * @param {import("./transport.js").Hub3WsClient} client
159
+ * @param {{deviceUUIDs:string[], timeoutMs?:number}} params
160
+ * @returns {Promise<{byDevice: Record<string, object[]>, items: object[]}>}
161
+ * items の各要素: { passwordID, keyBoardPassCode, keyBoardPassCodeNameUUID, name, nameUUID, subUUID, ..., uuids:string[] }
162
+ */
163
+ export async function getPasscodes(client, { deviceUUIDs, timeoutMs = DEFAULT_TIMEOUT_MS }) {
164
+ return fetchAuthData(client, {
165
+ op: "getPasscodes",
166
+ pubOp: PUB_PASSCODE_LINKED_IDS,
167
+ idKey: "passwordID",
168
+ deviceUUIDs,
169
+ timeoutMs,
170
+ });
171
+ }
172
+
173
+ // ---------- 内部: op 付き同期応答を待つ共通処理 ----------
174
+
175
+ /**
176
+ * action+op 一致の同期応答を request で待つ。biz3 は invokeCallbacks(message) で
177
+ * コールバック発火しているだけだが (useManageAuthData.js:260-271)、CLI では
178
+ * 応答メッセージ (reqContext 含む) を呼び出し側に返す。
179
+ * @returns {Promise<object>} 応答メッセージ
180
+ */
181
+ async function requestOp(client, frame, opLabel, timeoutMs) {
182
+ const resp = await client.request(frame, timeoutMs);
183
+ return assertSuccess(resp, opLabel);
184
+ }
185
+
186
+ // ---------- カード: 登録 (DB 同期) ----------
187
+
188
+ /**
189
+ * カードをサーバ DB に登録する (postCards)。
190
+ *
191
+ * ⚠️ getCards/clearCards と異なり obj でラップせず、deviceUUID と list を
192
+ * トップレベルに置く非対称構造 (useManageAuthData.js:379-394)。混同しないこと。
193
+ * ⚠️ これは「DB への登録」のみ。実ファームウェア書き込みは別途 BLE(iotCmd) で行う 2 段構造。
194
+ * list.length < 1 なら何もしない (biz3:381)。
195
+ *
196
+ * @param {import("./transport.js").Hub3WsClient} client
197
+ * @param {{deviceUUID:string, list:object[], timeoutMs?:number}} params
198
+ * list 要素: { cardID, nameUUID, name, cardType, memberID? } 等 (cards/index.js:268-286)
199
+ * @returns {Promise<object|null>} 応答メッセージ。list 空のときは null。
200
+ */
201
+ export async function postCards(client, { deviceUUID, list, timeoutMs = DEFAULT_TIMEOUT_MS }) {
202
+ if (!Array.isArray(list) || list.length < 1) return null;
203
+ return requestOp(client, { action: ACTION, deviceUUID, list, op: "postCards" }, "postCards", timeoutMs);
204
+ }
205
+
206
+ // ---------- パスコード: 登録 (DB 同期) ----------
207
+
208
+ /**
209
+ * パスコードをサーバ DB に登録する (postPasscodes)。postCards と同型 (useManageAuthData.js:396-411)。
210
+ * obj ラップ無し、deviceUUID と list をトップレベルに置く。list.length < 1 なら何もしない。
211
+ *
212
+ * @param {import("./transport.js").Hub3WsClient} client
213
+ * @param {{deviceUUID:string, list:object[], timeoutMs?:number}} params
214
+ * list 要素の正確なフィールドは biz3 のこのファイル内では未確認 (UI 由来)。getPasscodes 応答 item
215
+ * (passwordID 等) と対応すると推測される。**未確認: 実機検証要**。
216
+ * @returns {Promise<object|null>}
217
+ */
218
+ export async function postPasscodes(client, { deviceUUID, list, timeoutMs = DEFAULT_TIMEOUT_MS }) {
219
+ if (!Array.isArray(list) || list.length < 1) return null;
220
+ return requestOp(client, { action: ACTION, deviceUUID, list, op: "postPasscodes" }, "postPasscodes", timeoutMs);
221
+ }
222
+
223
+ // ---------- カード: 削除 (DB 同期) ----------
224
+
225
+ /**
226
+ * カードをサーバ DB から削除する (delCards)。
227
+ *
228
+ * ⚠️ obj/deviceUUID ラップ無し、items 配列をトップレベルに置く (useManageAuthData.js:355-365)。
229
+ * items 要素は { deviceID, cardID } (deviceUUID ではなく deviceID)。
230
+ * ⚠️ これは「BLE 削除 ack 後の DB 後始末」。実削除は BLE iotCmd 経由で行う 2 段構造。
231
+ * !items.length なら何もしない (biz3:356)。
232
+ * ⚠️ biz3 では delCards に応答ハンドラもコールバック登録も無い (useManageAuthData.js:265-267)。
233
+ * サーバは応答 op を返さないため、request で待つと必ず timeout する。biz3 と同じく
234
+ * **fire-and-forget (send)** にする。!items.length なら何もしない。
235
+ *
236
+ * @param {import("./transport.js").Hub3WsClient} client
237
+ * @param {{items:Array<{deviceID:string, cardID:string}>}} params
238
+ * @returns {boolean} 送信したら true、items 空で何もしなければ false
239
+ */
240
+ export function delCards(client, { items }) {
241
+ if (!Array.isArray(items) || items.length === 0) return false;
242
+ client.send({ action: ACTION, items, op: "delCards" });
243
+ return true;
244
+ }
245
+
246
+ // ---------- パスコード: 削除 (DB 同期) ----------
247
+
248
+ /**
249
+ * パスコードをサーバ DB から削除する (delPasscodes)。delCards と同型 (useManageAuthData.js:367-377)。
250
+ * items 要素は { deviceID, passwordID }。!items.length なら何もしない。
251
+ *
252
+ * ⚠️ biz3 では delPasscodes の応答ハンドラに専用 case が無く default に落ちる (272-273)。
253
+ * = 専用応答を期待していない。delCards と同様 **fire-and-forget (send)** にする
254
+ * (request で待つと応答 op が来ず timeout する)。!items.length なら何もしない。
255
+ *
256
+ * @param {import("./transport.js").Hub3WsClient} client
257
+ * @param {{items:Array<{deviceID:string, passwordID:string}>}} params
258
+ * @returns {boolean} 送信したら true、items 空で何もしなければ false
259
+ */
260
+ export function delPasscodes(client, { items }) {
261
+ if (!Array.isArray(items) || items.length === 0) return false;
262
+ client.send({ action: ACTION, items, op: "delPasscodes" });
263
+ return true;
264
+ }
265
+
266
+ // ---------- カード: 全クリア ----------
267
+
268
+ /**
269
+ * 指定デバイスのカードを全削除する (clearCards)。
270
+ *
271
+ * ⚠️ obj.devices は **単一 deviceUUID 文字列** (getCards のようなカンマ連結ではない:
272
+ * useManageAuthData.js:295-311)。!deviceUUID なら何もしない。
273
+ *
274
+ * @param {import("./transport.js").Hub3WsClient} client
275
+ * @param {{deviceUUID:string, timeoutMs?:number}} params
276
+ * @returns {Promise<object|null>}
277
+ */
278
+ export async function clearCards(client, { deviceUUID, timeoutMs = DEFAULT_TIMEOUT_MS }) {
279
+ if (!deviceUUID) return null;
280
+ return requestOp(client, { action: ACTION, obj: { devices: deviceUUID }, op: "clearCards" }, "clearCards", timeoutMs);
281
+ }
282
+
283
+ // ---------- パスコード: 全クリア ----------
284
+
285
+ /**
286
+ * 指定デバイスのパスコードを全削除する (clearPasscodes)。clearCards と同型。
287
+ * obj.devices は単一 deviceUUID 文字列 (useManageAuthData.js:313-329)。
288
+ * 注: biz3 の関数名は clearPasswords だが op は 'clearPasscodes'。
289
+ *
290
+ * @param {import("./transport.js").Hub3WsClient} client
291
+ * @param {{deviceUUID:string, timeoutMs?:number}} params
292
+ * @returns {Promise<object|null>}
293
+ */
294
+ export async function clearPasscodes(client, { deviceUUID, timeoutMs = DEFAULT_TIMEOUT_MS }) {
295
+ if (!deviceUUID) return null;
296
+ return requestOp(client, { action: ACTION, obj: { devices: deviceUUID }, op: "clearPasscodes" }, "clearPasscodes", timeoutMs);
297
+ }
298
+
299
+ // ---------- カード: 名前 / nameUUID 更新 ----------
300
+
301
+ /**
302
+ * カード名 (と nameUUID) を更新する (updateCardName)。
303
+ *
304
+ * biz3 handlePutCardName (useManageAuthData.js:331-344) は { action, obj:{...item}, op } を送る。
305
+ * item には { cardID, name, cardNameUUID, timestamp, cardType, stpDeviceUUID } を入れる
306
+ * (carddetails.js:79-87,177-184)。応答は reqContext に送ったフィールドが echo back される
307
+ * (useManageAuthData.js:192-234)。
308
+ *
309
+ * ⚠️ biz3 の updateItemName (438-471) は **cardNameUUID が UUIDv4 形式でない場合**、
310
+ * WS を直接投げず先に BLE (SSM_OS3_CARD_CHANGE=107) で nameUUID を v4 化する分岐がある。
311
+ * その BLE payload 構築は別モジュール (iotCmd) の責務。
312
+ * 本関数は **WS の updateCardName 送信のみ** を行う。CLI で BLE 前段を回避するには、
313
+ * 呼び出し側が cardNameUUID に v4 UUID を渡すこと (crypto.generateUUID() で生成可)。
314
+ *
315
+ * @param {import("./transport.js").Hub3WsClient} client
316
+ * @param {{item:object, timeoutMs?:number}} params
317
+ * item: { cardID, name, cardNameUUID, timestamp?, cardType?, stpDeviceUUID }
318
+ * @returns {Promise<object>} 応答メッセージ (reqContext 含む)
319
+ */
320
+ export async function updateCardName(client, { item, timeoutMs = DEFAULT_TIMEOUT_MS }) {
321
+ return requestOp(client, { action: ACTION, obj: { ...item }, op: "updateCardName" }, "updateCardName", timeoutMs);
322
+ }
323
+
324
+ // ---------- パスコード: 名前 / nameUUID 更新 ----------
325
+
326
+ /**
327
+ * パスコード名 (と nameUUID) を更新する (updatePasscodeName)。updateCardName と同型。
328
+ * item には { stpDeviceUUID, keyBoardPassCode, keyBoardPassCodeNameUUID, name } を入れる
329
+ * (useManageAuthData.js:201-210,331-344)。
330
+ *
331
+ * ⚠️ keyBoardPassCodeNameUUID が UUIDv4 形式でない場合、biz3 は先に BLE
332
+ * (SSM_OS3_PASSCODE_CHANGE=123) で v4 化する分岐がある (別モジュール責務)。
333
+ * 本関数は WS 送信のみ。v4 UUID を渡せば BLE 前段を回避できる。
334
+ *
335
+ * @param {import("./transport.js").Hub3WsClient} client
336
+ * @param {{item:object, timeoutMs?:number}} params
337
+ * item: { stpDeviceUUID, keyBoardPassCode, keyBoardPassCodeNameUUID, name }
338
+ * @returns {Promise<object>}
339
+ */
340
+ export async function updatePasscodeName(client, { item, timeoutMs = DEFAULT_TIMEOUT_MS }) {
341
+ return requestOp(client, { action: ACTION, obj: { ...item }, op: "updatePasscodeName" }, "updatePasscodeName", timeoutMs);
342
+ }
343
+
344
+ // ---------- カード: 所有者割当 ----------
345
+
346
+ /**
347
+ * カードの所有者 (メンバー) を割り当てる (updateCardOwner)。これは WS のみで完結 (BLE 不要)。
348
+ *
349
+ * biz3 (useManageAuthData.js:346-353) は 'ownerSubUUID' in item の時だけ送る。
350
+ * ownerSubUUID は割り当てるメンバーの subUUID。空文字 '' でも送信 = 未割当解除。
351
+ * frame は { action, obj:{ cardID, ownerSubUUID }, op:'updateCardOwner' }。
352
+ * 応答は reqContext:{ cardID, ownerSubUUID } を echo back (235-259)。
353
+ *
354
+ * @param {import("./transport.js").Hub3WsClient} client
355
+ * @param {{cardID:string, ownerSubUUID:string, timeoutMs?:number}} params
356
+ * ownerSubUUID は省略 (undefined) すると送信しない (null 相当)。'' は送信して未割当解除。
357
+ * @returns {Promise<object|null>} ownerSubUUID 未指定なら null。
358
+ */
359
+ export async function updateCardOwner(client, { cardID, ownerSubUUID, timeoutMs = DEFAULT_TIMEOUT_MS }) {
360
+ // biz3: 'ownerSubUUID' in item の時だけ送る (348)。undefined は送らない。'' は送る。
361
+ if (ownerSubUUID === undefined) return null;
362
+ return requestOp(
363
+ client,
364
+ { action: ACTION, obj: { cardID, ownerSubUUID }, op: "updateCardOwner" },
365
+ "updateCardOwner",
366
+ timeoutMs,
367
+ );
368
+ }
369
+
370
+ // 公開 op の allowlist (SesameHub3._bindNs / serve registry が参照する単一の真実)。
371
+ export const NAMESPACE_OPS = [
372
+ "getCards", "getPasscodes", "postCards", "postPasscodes",
373
+ "delCards", "delPasscodes", "clearCards", "clearPasscodes",
374
+ "updateCardName", "updatePasscodeName", "updateCardOwner",
375
+ ];
package/src/account.js ADDED
@@ -0,0 +1,36 @@
1
+ // ログインユーザ情報 (biz3GetLoginUser)。
2
+ //
3
+ // Ported from biz3 (CANDY-HOUSE/biz3, MIT):
4
+ // - vendor reference: references_web/src/api/useStripeInfo.js:82-92, 191-197
5
+ //
6
+ // 注: これは「認証」ではなく「ログイン済みセッションで自分の会社情報を引く op」。
7
+ // 認証フロー (Cognito client / refresh / DEVICE_KEY 永続化) は auth.js のまま
8
+ // アプリ寄せを維持しており、ここは一切関与しない。
9
+ //
10
+ // フレーム (op なし): { action: "biz3GetLoginUser", email }
11
+ // 応答: message.data = { customerInfo, quotas }
12
+ // customerInfo に companyID / subUUID / subscriptionId / name 等が入る。
13
+
14
+ import { ACTION_TYPES } from "../vendor/biz3/constants/messageConstants.js";
15
+ import { assertSuccess } from "./util.js";
16
+
17
+ const ACT_LOGIN = ACTION_TYPES.BIZ3_GET_LOGIN_INFO; // "biz3GetLoginUser"
18
+ const DEFAULT_TIMEOUT_MS = 10_000;
19
+
20
+ /**
21
+ * ログインユーザの customerInfo / quotas を取得する。
22
+ * @param {import("./transport.js").Hub3WsClient} client
23
+ * @param {{email:string}} params login に使った email (tokenStore の username)
24
+ * @returns {Promise<{customerInfo: object|null, quotas: object|null}>}
25
+ */
26
+ export async function getLoginUser(client, { email }) {
27
+ if (!email) throw new Error("email required (login に使った email)");
28
+ // biz3 は op を付けない (useStripeInfo.js:192-194)。応答も action のみで判定される
29
+ // ため、request の key は "biz3GetLoginUser:" (op 空) で一致する。
30
+ const resp = await client.request({ action: ACT_LOGIN, email }, DEFAULT_TIMEOUT_MS);
31
+ assertSuccess(resp, "getLoginUser");
32
+ return {
33
+ customerInfo: resp?.data?.customerInfo ?? null,
34
+ quotas: resp?.data?.quotas ?? null,
35
+ };
36
+ }