sesame-kit 0.4.1 → 0.5.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.
- package/README.ja.md +106 -73
- package/README.md +76 -43
- package/clients/js/sesame-client.mjs +2 -2
- package/clients/python/__pycache__/sesame_client.cpython-313.pyc +0 -0
- package/clients/python/sesame_client.py +2 -2
- package/docs/{architecture.md → en/architecture.md} +7 -7
- package/docs/en/ble.md +65 -0
- package/docs/{commands.md → en/commands.md} +26 -11
- package/docs/en/index.md +20 -0
- package/docs/en/integration.md +181 -0
- package/docs/{library.md → en/library.md} +6 -5
- package/docs/en/migration.md +13 -0
- package/docs/en/quickstart.md +51 -0
- package/docs/{architecture.ja.md → ja/architecture.md} +37 -37
- package/docs/ja/ble.md +65 -0
- package/docs/{commands.ja.md → ja/commands.md} +54 -39
- package/docs/ja/index.md +20 -0
- package/docs/ja/integration.md +181 -0
- package/docs/{library.ja.md → ja/library.md} +6 -5
- package/docs/ja/migration.md +13 -0
- package/docs/ja/quickstart.md +51 -0
- package/package.json +6 -2
- package/src/cli/serve.js +1 -1
- package/src/cli.js +14 -12
- package/src/client.js +2 -2
- package/src/config.js +1 -1
- package/src/paths.js +5 -5
- package/src/session-ui.js +85 -52
- package/src/tokens.js +1 -1
- package/types/cli.d.ts.map +1 -1
- package/types/client.d.ts +1 -1
- package/types/session-ui.d.ts.map +1 -1
- package/docs/migration.ja.md +0 -13
- package/docs/migration.md +0 -13
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
<!-- [English](../en/integration.md) | 日本語 -->
|
|
2
|
+
|
|
3
|
+
# 他言語からの組み込み (`sesame serve`)
|
|
4
|
+
|
|
5
|
+
> [English](../en/integration.md) · [ドキュメント目次](./index.md)
|
|
6
|
+
|
|
7
|
+
`sesame serve` は常駐する JSON-RPC 2.0 デーモンです。一度サインインするとクラウド接続を維持し続け、操作の実行とイベントの配信を繰り返します。すべての機能を任意の言語から呼び出せます。
|
|
8
|
+
|
|
9
|
+
## 1. サインインしてデーモンを起動
|
|
10
|
+
|
|
11
|
+
デーモンは保存済みのログイン情報を使い、デーモン自身はサインインしません。CLI で一度サインインしてから、デーモンを起動します。
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
sesame login your@email.com && sesame verify # if not already signed in
|
|
15
|
+
sesame serve --http 8080 # serve over HTTP on port 8080
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
デーモンは起動時にトークンを出力します(`~/.config/sesame-kit/serve.token` にも保存されます)。すべての HTTP リクエストは `Authorization: Bearer <token>` を送る必要があります。
|
|
19
|
+
|
|
20
|
+
> 同一マシンでの利用なら、フラグなしの `sesame serve` は Unix ソケットで待ち受け、トークンは不要です。ここで HTTP を使うのは、任意の言語・任意のマシンから動作するためです。
|
|
21
|
+
|
|
22
|
+
## 2. 最初の呼び出し — ライブラリのインストール不要
|
|
23
|
+
|
|
24
|
+
HTTP 上の素の JSON-RPC です。POST できるものなら何でも動作します。
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
TOKEN=... # the token printed by `sesame serve`
|
|
28
|
+
|
|
29
|
+
curl -s -H "Authorization: Bearer $TOKEN" -H "content-type: application/json" \
|
|
30
|
+
-d '{"jsonrpc":"2.0","id":1,"method":"lock.unlock","params":{"name":"front"}}' \
|
|
31
|
+
http://127.0.0.1:8080/rpc
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
同じものを Python で、標準ライブラリだけで(pip install 不要):
|
|
35
|
+
|
|
36
|
+
```python
|
|
37
|
+
import json, urllib.request
|
|
38
|
+
|
|
39
|
+
TOKEN = "..." # the token printed by `sesame serve`
|
|
40
|
+
|
|
41
|
+
def rpc(method, params=None):
|
|
42
|
+
body = json.dumps({"jsonrpc": "2.0", "id": 1, "method": method, "params": params or {}}).encode()
|
|
43
|
+
req = urllib.request.Request("http://127.0.0.1:8080/rpc", data=body,
|
|
44
|
+
headers={"content-type": "application/json", "authorization": f"Bearer {TOKEN}"})
|
|
45
|
+
return json.load(urllib.request.urlopen(req))
|
|
46
|
+
|
|
47
|
+
print(rpc("status"))
|
|
48
|
+
print(rpc("lock.unlock", {"name": "front"}))
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
レスポンスは成功時に `{"jsonrpc":"2.0","id":1,"result": ...}`、失敗時に `{"jsonrpc":"2.0","id":1,"error":{"code","message","data":{"kind"}}}` です。
|
|
52
|
+
|
|
53
|
+
## 3. メソッドと渡す値の調べ方
|
|
54
|
+
|
|
55
|
+
`sesame rpc` は全メソッドとそのパラメータを一覧します(必須はそのまま、任意は `[brackets]` で表示):
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
sesame rpc
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
lock.unlock [name] [deviceUUID] [secretKey]
|
|
63
|
+
lock.status deviceUUID
|
|
64
|
+
devices.list
|
|
65
|
+
device.history deviceUUID [pageSize]
|
|
66
|
+
ir.send [remote] key
|
|
67
|
+
org.getEmployees companyID
|
|
68
|
+
…
|
|
69
|
+
79 methods.
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
この一覧から、使いたいメソッドの行を読みます。各行は `メソッド名 <必須> [任意]` の形です。例えば `device.history deviceUUID [pageSize]` は、**`deviceUUID` が必須・`pageSize` が任意**という意味です。
|
|
73
|
+
|
|
74
|
+
あとは各パラメータに**値**を入れるだけです。値の出所は 2 種類あります。
|
|
75
|
+
|
|
76
|
+
- **ID 系**(`deviceUUID` / `companyID` など)は、別の一覧メソッドが返します。`deviceUUID` なら `devices.list` の結果から取ります:
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
sesame rpc devices.list
|
|
80
|
+
# → [{"deviceUUID":"AB12CD34...","deviceName":"front", ...}, ...]
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
- **自分で決める値**(`pageSize` / `name` など)は、任意で好きな値を入れます。`pageSize` は取得件数です。
|
|
84
|
+
|
|
85
|
+
決めた値を `--params` の JSON に入れて呼びます:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
sesame rpc device.history --params '{"deviceUUID":"AB12CD34...","pageSize":10}'
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
ここで決めた**メソッド名と params が、そのまま任意のクライアントから送る内容**です(セクション2の `method` / `params` フィールドに対応します)。
|
|
92
|
+
|
|
93
|
+
> ロック操作は `deviceUUID` の代わりに設定名も受け付けます。`{"name":"front"}` が `lock.unlock` / `lock.lock` / `lock.toggle` / `lock.click` で動きます(`lock.status` は `deviceUUID` を取ります)。
|
|
94
|
+
|
|
95
|
+
正確なパラメータ型(例えばコード生成用)が必要なら、`sesame rpc --json rpc.discover` が完全な OpenRPC 文書を返します。各メソッドのエントリが param の型を持ちます:
|
|
96
|
+
|
|
97
|
+
```json
|
|
98
|
+
{
|
|
99
|
+
"name": "device.history",
|
|
100
|
+
"params": [
|
|
101
|
+
{ "name": "deviceUUID", "required": true, "schema": { "type": "string" } },
|
|
102
|
+
{ "name": "pageSize", "required": false, "schema": { "type": "number" } }
|
|
103
|
+
]
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## 4. 同梱クライアント(任意)
|
|
108
|
+
|
|
109
|
+
薄いクライアントが上記をラップし、JSON を手で組み立てる代わりに `c.unlock("front")` と書けます。任意であり、セクション 2 はこれらなしでも動作します。
|
|
110
|
+
|
|
111
|
+
**Node** — `npm install sesame-kit` の後:
|
|
112
|
+
|
|
113
|
+
```js
|
|
114
|
+
import { SesameClient } from "sesame-kit/client";
|
|
115
|
+
|
|
116
|
+
const c = SesameClient.unix(); // default Unix socket
|
|
117
|
+
console.log(await c.unlock("front")); // convenience method
|
|
118
|
+
console.log(await c.call("device.history", { deviceUUID: "AB12CD34...", pageSize: 10 })); // any method
|
|
119
|
+
console.log((await c.discover()).methods.map((m) => m.name)); // list methods from JS
|
|
120
|
+
await c.subscribe(["lockState"], (topic, p) => console.log(topic, p)); // always await
|
|
121
|
+
|
|
122
|
+
// const h = SesameClient.http("http://127.0.0.1:8080"); // token auto-read from serve.token
|
|
123
|
+
// const w = await SesameClient.ws("ws://127.0.0.1:8081"); // npm i ws for header auth
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
**Python** — クライアントはパッケージに同梱される単一ファイルです:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
pip install ./clients/python # from a cloned repo
|
|
130
|
+
pip install "$(npm root -g)/sesame-kit/clients/python" # from a global `npm install -g sesame-kit`
|
|
131
|
+
```
|
|
132
|
+
```python
|
|
133
|
+
from sesame_client import SesameClient
|
|
134
|
+
|
|
135
|
+
c = SesameClient.unix() # default Unix socket
|
|
136
|
+
print(c.unlock("front")) # convenience method
|
|
137
|
+
print(c.call("device.history", deviceUUID="AB12CD34...", pageSize=10)) # any method
|
|
138
|
+
print(c.discover_names()) # list methods from Python
|
|
139
|
+
c.subscribe(["lockState"], lambda topic, payload: print(topic, payload))
|
|
140
|
+
# HTTP: SesameClient.http("http://127.0.0.1:8080") / embedded: SesameClient.stdio()
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## 経路(フレーミング)
|
|
144
|
+
|
|
145
|
+
同じメソッドが 5 つの経路で利用できます。ネットワークアクセスには HTTP/WS/gRPC を、ローカルマシンには Unix ソケットまたは stdio を使います。
|
|
146
|
+
|
|
147
|
+
| フレーミング | 用途 | イベント | 認証 |
|
|
148
|
+
|---|---|---|---|
|
|
149
|
+
| stdio | 組み込み(子プロセス) | `event.*` 通知 | 親プロセスの信頼を継承 |
|
|
150
|
+
| Unix ソケット | ローカルデーモン、複数クライアント | `event.*` 通知 | ファイルパーミッション 0600 |
|
|
151
|
+
| HTTP | 任意の言語 / ブラウザ | `GET /events`(SSE) | `Authorization: Bearer <token>` |
|
|
152
|
+
| WebSocket | 任意の言語 / ブラウザ(全二重) | `event.*` 通知 | トークン |
|
|
153
|
+
| gRPC | 多言語向けの型付きスタブ | `Subscribe` ストリーム | トークン(メタデータ) |
|
|
154
|
+
|
|
155
|
+
gRPC は型付きです。`src/serve/sesame.proto` には op ごとに型付きメソッドがあります。スタブは
|
|
156
|
+
`python -m grpc_tools.protoc -I src/serve --python_out=. --grpc_python_out=. src/serve/sesame.proto`
|
|
157
|
+
で生成します。スカラー/配列パラメータは protobuf 型、動的パラメータは JSON 文字列フィールド、レスポンスは `JsonRpc{json}` です。型付きメソッドを持たない op は汎用の `Invoke` を使います。
|
|
158
|
+
|
|
159
|
+
## イベント
|
|
160
|
+
|
|
161
|
+
```jsonc
|
|
162
|
+
// request (over Unix socket / WebSocket / stdio):
|
|
163
|
+
{"jsonrpc":"2.0","id":1,"method":"events.subscribe","params":{"topics":["lockState","deviceUpdate"]}}
|
|
164
|
+
// then notifications arrive (no id):
|
|
165
|
+
{"jsonrpc":"2.0","method":"event.lockState","params":{ /* state */ }}
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
トピック:`lockState`、`deviceUpdate`。HTTP では `GET /events?topics=…`(SSE)を、gRPC では `Subscribe` ストリームを使います。`POST /rpc` と gRPC の `Invoke` はリクエスト/レスポンス専用で、`events.*` を拒否します。
|
|
169
|
+
|
|
170
|
+
## エラー
|
|
171
|
+
|
|
172
|
+
エラーは `{error:{code, message, data:{kind}}}` です。`kind` は次のいずれかです:
|
|
173
|
+
`not_authenticated`(CLI でサインインしてからデーモンを再起動)/ `connection_lost`(クラウド接続が切断)/ `timeout` / `bad_params` / `not_implemented`(不明なメソッド)/ `internal`(それ以外。詳細は `message` に)。
|
|
174
|
+
|
|
175
|
+
## 互換性
|
|
176
|
+
|
|
177
|
+
結果の形はメソッド固有です。互換性を確認するには、コントラクトバージョンを読みます。`status` は `contractVersion` を返し、`rpc.discover` は `info["x-contractVersion"]` を返します。これは機械向けコントラクトの SemVer であり、互換性を壊す変更のみがメジャーを上げます。
|
|
178
|
+
|
|
179
|
+
## セキュリティ境界
|
|
180
|
+
|
|
181
|
+
対話的ログインは CLI 専用で、デーモン内では決して実行されません。Unix ソケットは同一ユーザーの任意のプロセスから使えます(CLI と同じ境界)。HTTP / WS / gRPC は TCP 上であり、起動時に生成されるループバックトークンを要求します。これらは平文(TLS なし)であり、ループバックでのみ公開するか、SSH / TLS リバースプロキシ経由でトンネルします。POSIX のみ対応です(Windows UDS は対象外。stdio / HTTP / WS / gRPC は動作します)。
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
<!-- [English](
|
|
1
|
+
<!-- [English](../en/library.md) | 日本語 -->
|
|
2
2
|
|
|
3
3
|
# ライブラリとして使う
|
|
4
4
|
|
|
5
|
-
> English
|
|
5
|
+
> [English](../en/library.md) · [ドキュメント目次](./index.md)
|
|
6
6
|
|
|
7
|
-
`sesame` CLI と同じ機能を Node.js
|
|
7
|
+
`sesame` CLI と同じ機能を Node.js から直接呼べます。他言語から使うなら [`sesame serve`](../../README.ja.md#言語非依存バックエンド-sesame-serve) を、Node 内で使うならこちら。
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## `use()` ヘルパ (auto connect/close)
|
|
10
10
|
|
|
11
11
|
```js
|
|
12
12
|
import { SesameHub3 } from "sesame-kit";
|
|
@@ -53,10 +53,11 @@ await SesameHub3.use(async (hub) => {
|
|
|
53
53
|
await hub.lockDevice({ deviceUUID, secretKey });
|
|
54
54
|
await hub.toggleDevice({ deviceUUID, secretKey });
|
|
55
55
|
await hub.botClickDevice({ deviceUUID, secretKey });
|
|
56
|
-
await hub.triggerLockDevice({ deviceUUID, secretKey, cmd: 83 }); //
|
|
56
|
+
await hub.triggerLockDevice({ deviceUUID, secretKey, cmd: 83 }); // 生 itemCode: 83=解錠, 82=施錠, 88=トグル, 89=クリック
|
|
57
57
|
|
|
58
58
|
// IR
|
|
59
59
|
await hub.sendIRDirect({
|
|
60
|
+
// irType はリモコン種別: 49152 (0xC000)=エアコン, 8192=TV, 32768=扇風機, 57344=照明
|
|
60
61
|
hub3DeviceId, irDeviceUUID, irType: 49152, command: keyUUID, operation: "learnEmit",
|
|
61
62
|
});
|
|
62
63
|
const keys = await hub.getIRCodesDirect({ hub3DeviceId, irDeviceUUID });
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!-- [English](../en/migration.md) | 日本語 -->
|
|
2
|
+
|
|
3
|
+
# 旧版からのマイグレーション
|
|
4
|
+
|
|
5
|
+
> [English](../en/migration.md) · [ドキュメント目次](./index.md)
|
|
6
|
+
|
|
7
|
+
旧 `sesame-hub3` (CLI=`hub3-ir`) からのアップグレード:
|
|
8
|
+
|
|
9
|
+
- CLI 名は `sesame` に変更 (旧 `hub3-ir` は廃止)。シェルスクリプトを使っている場合は置換。
|
|
10
|
+
- 設定とトークンは `~/.config/sesame-kit` に保存されます。
|
|
11
|
+
- config は単一の `devices` マップに保存されます。`locks` は読み込み時に毎回再構築される派生 view で、保存されるキーではありません。`sesame locks sync-from-devices` でサーバから `devices` を取り込みます。
|
|
12
|
+
|
|
13
|
+
旧 `.env + .tokens.json + keys.json` からの移行は `sesame migrate` がそのまま使えます。
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<!-- [English](../en/quickstart.md) | 日本語 -->
|
|
2
|
+
|
|
3
|
+
# クイックスタート
|
|
4
|
+
|
|
5
|
+
> [English](../en/quickstart.md) · [ドキュメント目次](./index.md)
|
|
6
|
+
|
|
7
|
+
数分でコマンドラインからロックを開けます。
|
|
8
|
+
|
|
9
|
+
## 1. インストール
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -g sesame-kit # グローバル CLI: `sesame ...`
|
|
13
|
+
# インストールせず実行: npx sesame-kit ...
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Node.js 18 以上が必要です。
|
|
17
|
+
|
|
18
|
+
## 2. サインイン
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
sesame init # ~/.config/sesame-kit/ を作成 (初回のみ)
|
|
22
|
+
sesame login your@email.com # 確認コードがメールに届く
|
|
23
|
+
sesame verify # コードを入力
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
`verify` がデバイスを鍵ごと自動で取り込むので、直後から操作できます。
|
|
27
|
+
|
|
28
|
+
## 3. ロックを操作する
|
|
29
|
+
|
|
30
|
+
`sesame` を引数なしで実行すると対話メニューが表示され、デバイスと各デバイスで使える操作が一覧されます。
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
sesame # ↑↓ 移動 · →(または Enter)決定 · ←(または Esc)戻る · q 終了
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
やりたいことが決まっていれば直接実行することもできます。主語はデバイスです: `sesame <device> <action>`(部分一致)。
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
sesame front status # 現在状態 (施錠 / 解錠)
|
|
40
|
+
sesame front unlock # 解錠
|
|
41
|
+
sesame front lock # 施錠
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## 次のステップ
|
|
45
|
+
|
|
46
|
+
- CLI の全コマンド: [CLI リファレンス](./commands.md)
|
|
47
|
+
- クラウドを介さず Bluetooth で操作する: [BLE 直接制御](./ble.md)
|
|
48
|
+
- 他言語から呼び出す: [`sesame serve` 連携](./integration.md)
|
|
49
|
+
- Node コードから使う: [Node ライブラリ](./library.md)
|
|
50
|
+
|
|
51
|
+
> クラウド制御にはサインインが必要です。BLE 単独の制御はサインインなしで動作します — [BLE 直接制御](./ble.md)を参照。
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sesame-kit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
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
5
|
"author": "Ikuma Fukumoto",
|
|
6
6
|
"license": "MIT",
|
|
@@ -43,6 +43,9 @@
|
|
|
43
43
|
"./devices": {
|
|
44
44
|
"types": "./types/devices.d.ts",
|
|
45
45
|
"default": "./src/devices.js"
|
|
46
|
+
},
|
|
47
|
+
"./client": {
|
|
48
|
+
"default": "./clients/js/sesame-client.mjs"
|
|
46
49
|
}
|
|
47
50
|
},
|
|
48
51
|
"bin": {
|
|
@@ -85,7 +88,8 @@
|
|
|
85
88
|
"build:rpc-schema": "node scripts/gen-rpc-schema.mjs",
|
|
86
89
|
"build:grpc-proto": "node scripts/gen-grpc-proto.mjs",
|
|
87
90
|
"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"
|
|
91
|
+
"prepack": "tsc -p tsconfig.json && node scripts/gen-rpc-schema.mjs && node scripts/gen-grpc-proto.mjs",
|
|
92
|
+
"release": "bash scripts/release.sh"
|
|
89
93
|
},
|
|
90
94
|
"dependencies": {
|
|
91
95
|
"@aws-sdk/client-cognito-identity-provider": "^3.1057.0",
|
package/src/cli/serve.js
CHANGED
|
@@ -65,7 +65,7 @@ export function registerServeCommand(program) {
|
|
|
65
65
|
program.command("serve")
|
|
66
66
|
.description("常駐 JSON-RPC バックエンド (stdio/UDS/HTTP/WS/gRPC で全機能を他言語へ公開)")
|
|
67
67
|
.option("--stdio", "stdin/stdout で NDJSON JSON-RPC (埋め込み: 親が子プロセスとして spawn)")
|
|
68
|
-
.option("--socket [path]", "Unix domain socket (省略時 ~/.config/sesame-
|
|
68
|
+
.option("--socket [path]", "Unix domain socket (省略時 ~/.config/sesame-kit/sesame.sock)")
|
|
69
69
|
.option("--no-socket", "UDS を無効化")
|
|
70
70
|
.option("--http [port]", `HTTP(+SSE) を listen (既定 ${DEF.http})`)
|
|
71
71
|
.option("--ws [port]", `WebSocket を listen (既定 ${DEF.ws})`)
|
package/src/cli.js
CHANGED
|
@@ -198,7 +198,7 @@ async function pickLockName(program, configStore, current) {
|
|
|
198
198
|
if (current) return current;
|
|
199
199
|
const cfg = configStore.load();
|
|
200
200
|
const names = Object.keys(cfg.locks || {});
|
|
201
|
-
if (names.length === 0) die("ロックが未登録です。`sesame
|
|
201
|
+
if (names.length === 0) die("ロックが未登録です。`sesame locks add` か `sesame locks sync-from-devices` を実行してください。", 2);
|
|
202
202
|
if (names.length === 1) return names[0];
|
|
203
203
|
if (!canPrompt(program)) return null;
|
|
204
204
|
return selectFromList("どのロック?", names, (n) => {
|
|
@@ -459,7 +459,7 @@ async function cmdInit(_opts, program) {
|
|
|
459
459
|
console.log(``);
|
|
460
460
|
console.log(`次のステップ (所要 約3分):`);
|
|
461
461
|
console.log(` 1. sesame login <email> # email に確認コードが届く → sesame verify <code>`);
|
|
462
|
-
console.log(` 2a. ロックを使うなら: sesame
|
|
462
|
+
console.log(` 2a. ロックを使うなら: sesame locks sync-from-devices # 自動取り込み`);
|
|
463
463
|
console.log(` 2b. Hub3 IR を使うなら: sesame remote sync-from-devices # Hub3+リモコン+キーを一括取得`);
|
|
464
464
|
console.log(``);
|
|
465
465
|
console.log(`概念: Hub3=IR を飛ばす中継器 / remote=リモコン定義 / lock=施錠デバイス。`);
|
|
@@ -1010,7 +1010,7 @@ async function resolveLockEntry(program, name) {
|
|
|
1010
1010
|
|
|
1011
1011
|
/**
|
|
1012
1012
|
* 単発コマンドの経路を決定する。
|
|
1013
|
-
* - 既定 (
|
|
1013
|
+
* - 既定 (オート): 能力フル。経路はツールが自動選択する。BLE はスキャン/接続のオーバーヘッドが
|
|
1014
1014
|
* あるため毎回は張らず、cloud で運べる op は cloud、cloud で運べない op (autolock など BLE 必須)
|
|
1015
1015
|
* のみ BLE で一時接続する (cloud が速いという意味ではなく、BLE の接続コストを毎回払わないため)。
|
|
1016
1016
|
* - `--ble-only` / `--cloud-only`: 経路を固定したいときの明示指定 (最優先)。
|
|
@@ -1029,7 +1029,7 @@ function pickTransport(op, options, model) {
|
|
|
1029
1029
|
if (!allowed.includes("cloud")) { die(`${op} はクラウドでは実機に反映されません (BLE 必須)。--ble-only か無指定で。`, 2); }
|
|
1030
1030
|
return "cloud";
|
|
1031
1031
|
}
|
|
1032
|
-
//
|
|
1032
|
+
// オート: cloud で運べるなら cloud (BLE の接続コストを避けるため)。cloud 不可な op (autolock) のみ BLE。
|
|
1033
1033
|
return allowed.includes("cloud") ? "cloud" : "ble";
|
|
1034
1034
|
}
|
|
1035
1035
|
|
|
@@ -1300,7 +1300,7 @@ async function cmdSession(names, options, program) {
|
|
|
1300
1300
|
|
|
1301
1301
|
let blePromise = null;
|
|
1302
1302
|
if (loggedIn) {
|
|
1303
|
-
//
|
|
1303
|
+
// オートのアプリ的挙動: クラウドでメニューを即表示し、BLE は **バックグラウンド** で接続する
|
|
1304
1304
|
// (繋がったデバイスは次の描画で ·BLE に昇格し、以降 BLE 優先)。起動を BLE スキャンで待たせない。
|
|
1305
1305
|
if (lockTargets.length) console.error("[ble] バックグラウンドで接続中... (クラウドで操作可能)");
|
|
1306
1306
|
blePromise = connectBle();
|
|
@@ -1347,7 +1347,7 @@ const DEVICE_ACTIONS = new Set(["unlock", "lock", "toggle", "click", "status", "
|
|
|
1347
1347
|
* デバイス主語の実行: `sesame <device> [action] [args]`。
|
|
1348
1348
|
* - action 省略 + TTY → そのデバイス (複数可) の対話セッション。
|
|
1349
1349
|
* - action 省略 + 非対話 → status を表示。
|
|
1350
|
-
* - action 指定 → 1 発実行 (cmdAct
|
|
1350
|
+
* - action 指定 → 1 発実行 (cmdAct に委譲。経路はオートで自動)。
|
|
1351
1351
|
*/
|
|
1352
1352
|
async function cmdDeviceOp(device, action, args, options, program) {
|
|
1353
1353
|
if (!action) {
|
|
@@ -1512,7 +1512,7 @@ export async function run(argv = process.argv) {
|
|
|
1512
1512
|
// この前に設定すると後で追加する全サブコマンドへ継承される。--json 時は writeErr 側で抑止。
|
|
1513
1513
|
.showHelpAfterError()
|
|
1514
1514
|
.showSuggestionAfterError()
|
|
1515
|
-
.option("--config-dir <path>", "設定ディレクトリ上書き (default: ~/.config/sesame-
|
|
1515
|
+
.option("--config-dir <path>", "設定ディレクトリ上書き (default: ~/.config/sesame-kit)")
|
|
1516
1516
|
.option("--debug", "詳細ログ")
|
|
1517
1517
|
.option("--json", "JSON 出力");
|
|
1518
1518
|
|
|
@@ -1615,7 +1615,7 @@ devices だけで完結します (手入力は呼び名のみ):
|
|
|
1615
1615
|
// ---------- デバイス主語の実行 (sesame <device> [action]) ----------
|
|
1616
1616
|
// 主語はデバイス。`sesame front unlock` = front.unlock() 相当 (SDK の device.method() と同じ)。
|
|
1617
1617
|
// action 省略は対話メニュー (= そのデバイスの session)。引数なし `sesame` は全デバイスの session。
|
|
1618
|
-
//
|
|
1618
|
+
// 経路は既定「オート」(能力フル・自動。BLE 必須 op のみ BLE)。固定は --ble-only / --cloud-only。
|
|
1619
1619
|
// 例: sesame front unlock / sesame kitchen click / sesame front autolock 30 / sesame front --ble-only
|
|
1620
1620
|
//
|
|
1621
1621
|
// 実体は隠し op コマンド。先頭トークンが既知コマンドでなければ run() がここへ振り分ける。
|
|
@@ -1755,9 +1755,11 @@ devices だけで完結します (手入力は呼び名のみ):
|
|
|
1755
1755
|
// BLE 権限/電源エラーは macOS なら該当設定ペインを自動で開いて誘導する。
|
|
1756
1756
|
if (maybeHandleBleError(err)) { finishCli(); return; }
|
|
1757
1757
|
const code = (typeof err.exitCode === "number" && err.exitCode !== 0) ? err.exitCode : 1;
|
|
1758
|
-
// commander の usage
|
|
1759
|
-
if (typeof err.code === "string" && err.code.startsWith("commander.")
|
|
1760
|
-
process.exitCode = code; finishCli(); return;
|
|
1758
|
+
// commander の usage エラー。非 JSON 時は commander が stderr に整形済み (usage 付き) なので二重出力を避ける。
|
|
1759
|
+
if (typeof err.code === "string" && err.code.startsWith("commander.")) {
|
|
1760
|
+
if (!CLI_JSON) { process.exitCode = code; finishCli(); return; }
|
|
1761
|
+
// --json: commander のメッセージ先頭 "error: " を剥がして封筒に載せる (error が二重にならないように)。
|
|
1762
|
+
die((err.message || "usage error").replace(/^error:\s*/i, ""), code); return;
|
|
1761
1763
|
}
|
|
1762
1764
|
die(withStaleHint(err.message || String(err)), code);
|
|
1763
1765
|
}
|
|
@@ -1814,6 +1816,6 @@ function withStaleHint(msg) {
|
|
|
1814
1816
|
/not found/i.test(m) ||
|
|
1815
1817
|
/invalid.*device/i.test(m);
|
|
1816
1818
|
if (!looksStale) return m;
|
|
1817
|
-
return `${m}\nヒント: ローカル config が古い可能性があります。\n IR キー: sesame remote sync-keys [name]\n ロック/Hub3: sesame
|
|
1819
|
+
return `${m}\nヒント: ローカル config が古い可能性があります。\n IR キー: sesame remote sync-keys [name]\n ロック/Hub3: sesame locks sync-from-devices / sesame hub3 sync-from-devices`;
|
|
1818
1820
|
}
|
|
1819
1821
|
|
package/src/client.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
// 低レベル WS (Hub3WsClient) とトークン管理 / 設定解決を内部で抱える。
|
|
3
3
|
//
|
|
4
4
|
// 使い方:
|
|
5
|
-
// const hub = await SesameHub3.fromConfig(); // ~/.config/sesame-
|
|
5
|
+
// const hub = await SesameHub3.fromConfig(); // ~/.config/sesame-kit から
|
|
6
6
|
// await hub.connect();
|
|
7
7
|
// await hub.send("ac", "停止"); // (remote名, キー名 or keyUUID)
|
|
8
8
|
// await hub.close();
|
|
@@ -65,7 +65,7 @@ const UUID_RE = /^[0-9a-fA-F-]{32,}$/;
|
|
|
65
65
|
|
|
66
66
|
export class SesameHub3 {
|
|
67
67
|
/**
|
|
68
|
-
* 既定の設定ディレクトリ (~/.config/sesame-
|
|
68
|
+
* 既定の設定ディレクトリ (~/.config/sesame-kit 等) から読み込んで構築。
|
|
69
69
|
* CLI 内部はこのファクトリを使う。
|
|
70
70
|
* @param {{ configDir?: string, debug?: boolean }} [opts]
|
|
71
71
|
*/
|
package/src/config.js
CHANGED
|
@@ -135,7 +135,7 @@ export class ConfigStore {
|
|
|
135
135
|
// mode 0600 で保存する (Review M-5)。
|
|
136
136
|
// 注: POSIX 専用。Windows では mode は read-only flag になる程度。
|
|
137
137
|
// 既存ディレクトリの mode は変更されない (新規作成時のみ反映) ので、
|
|
138
|
-
// 旧バージョンで作られた場合は手動で `chmod 700 ~/.config/sesame-
|
|
138
|
+
// 旧バージョンで作られた場合は手動で `chmod 700 ~/.config/sesame-kit` が必要。
|
|
139
139
|
mkdirSync(dirname(this.configPath), { recursive: true, mode: 0o700 });
|
|
140
140
|
writeFileSync(this.configPath, JSON.stringify(persist, null, 2) + "\n", { mode: 0o600 });
|
|
141
141
|
}
|
package/src/paths.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
// 設定ディレクトリ解決。優先順位:
|
|
2
2
|
// 1. 明示渡し (overrideDir, CLI --config-dir)
|
|
3
|
-
// 2. env
|
|
4
|
-
// 3. env XDG_CONFIG_HOME → $XDG_CONFIG_HOME/sesame-
|
|
5
|
-
// 4. ~/.config/sesame-
|
|
3
|
+
// 2. env SESAME_KIT_HOME (アプリ専用)
|
|
4
|
+
// 3. env XDG_CONFIG_HOME → $XDG_CONFIG_HOME/sesame-kit
|
|
5
|
+
// 4. ~/.config/sesame-kit
|
|
6
6
|
import { homedir } from "node:os";
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
|
|
9
|
-
const APP_DIRNAME = "sesame-
|
|
9
|
+
const APP_DIRNAME = "sesame-kit";
|
|
10
10
|
|
|
11
11
|
export function resolveConfigDir(overrideDir) {
|
|
12
12
|
if (overrideDir) return resolve(overrideDir);
|
|
13
|
-
if (process.env.
|
|
13
|
+
if (process.env.SESAME_KIT_HOME) return resolve(process.env.SESAME_KIT_HOME);
|
|
14
14
|
const xdg = process.env.XDG_CONFIG_HOME;
|
|
15
15
|
if (xdg) return resolve(xdg, APP_DIRNAME);
|
|
16
16
|
return resolve(homedir(), ".config", APP_DIRNAME);
|