@log0u7/opencode-mesh 0.2.0 → 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.
- package/CHANGELOG.md +150 -0
- package/README.md +46 -13
- package/dist/lib/client.d.ts +2 -0
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +6 -1
- package/dist/lib/client.js.map +1 -1
- package/dist/lib/db.d.ts.map +1 -1
- package/dist/lib/db.js +26 -1
- package/dist/lib/db.js.map +1 -1
- package/dist/lib/discovery.d.ts +3 -0
- package/dist/lib/discovery.d.ts.map +1 -1
- package/dist/lib/discovery.js +33 -7
- package/dist/lib/discovery.js.map +1 -1
- package/dist/lib/identity.d.ts +10 -8
- package/dist/lib/identity.d.ts.map +1 -1
- package/dist/lib/identity.js +132 -32
- package/dist/lib/identity.js.map +1 -1
- package/dist/lib/locks.d.ts.map +1 -1
- package/dist/lib/locks.js +20 -12
- package/dist/lib/locks.js.map +1 -1
- package/dist/lib/peers.d.ts +13 -1
- package/dist/lib/peers.d.ts.map +1 -1
- package/dist/lib/peers.js +114 -18
- package/dist/lib/peers.js.map +1 -1
- package/dist/lib/serve.d.ts +2 -0
- package/dist/lib/serve.d.ts.map +1 -1
- package/dist/lib/serve.js +62 -71
- package/dist/lib/serve.js.map +1 -1
- package/dist/lib/spawn.d.ts +14 -4
- package/dist/lib/spawn.d.ts.map +1 -1
- package/dist/lib/spawn.js +210 -21
- package/dist/lib/spawn.js.map +1 -1
- package/dist/lib/sqlite.d.ts.map +1 -1
- package/dist/lib/sqlite.js +15 -4
- package/dist/lib/sqlite.js.map +1 -1
- package/dist/lib/workers.d.ts +2 -0
- package/dist/lib/workers.d.ts.map +1 -1
- package/dist/lib/workers.js +45 -12
- package/dist/lib/workers.js.map +1 -1
- package/dist/lib/worktree.d.ts +22 -4
- package/dist/lib/worktree.d.ts.map +1 -1
- package/dist/lib/worktree.js +54 -6
- package/dist/lib/worktree.js.map +1 -1
- package/dist/plugin-v2.d.ts.map +1 -1
- package/dist/plugin-v2.js +65 -337
- package/dist/plugin-v2.js.map +1 -1
- package/dist/plugin.d.ts +2 -6
- package/dist/plugin.d.ts.map +1 -1
- package/dist/plugin.js +119 -265
- package/dist/plugin.js.map +1 -1
- package/dist/tools.d.ts +30 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +315 -0
- package/dist/tools.js.map +1 -0
- package/dist/types/peer.d.ts +2 -0
- package/dist/types/peer.d.ts.map +1 -1
- package/package.json +10 -8
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,156 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.4.0] - 2026-10-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Signed pairing offers close the pending-token rebind window (Closes #30).
|
|
15
|
+
Each node keeps an Ed25519 keypair in `node.json` (generated on first run or
|
|
16
|
+
on migration; the `node_id` is preserved). Pairing offers carry the emitter's
|
|
17
|
+
public key (`pk`), completing a pairing pins it, mDNS TXT advertises it, and
|
|
18
|
+
every outgoing mail carries a pairing proof (`<pk>.<signature>` over
|
|
19
|
+
`opencode-mesh-pair:<node_id>:<token>`). A pending token now binds (or
|
|
20
|
+
rotates) a peer row only with a valid proof from the pinned key: a leaked
|
|
21
|
+
offer alone can no longer take over a paired peer's credential. Peers paired
|
|
22
|
+
without a pinned key (0.3.0-era rows, or completions without `pk`) refuse
|
|
23
|
+
remote rebinding: re-run `mesh_pair` to rotate them. `peers` gains a
|
|
24
|
+
`public_key` column (schema version 2, migrated in place).
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- Peer addresses in the IPv4-mapped IPv6 form (`[::ffff:192.168.1.10]:4399`)
|
|
29
|
+
are accepted, so a dual-stack resolver's reported address no longer leaves
|
|
30
|
+
its peer unreachable ("no known address with a port"). Portless and
|
|
31
|
+
empty-zone forms stay rejected.
|
|
32
|
+
|
|
33
|
+
## [0.3.0] - 2026-10-14
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
|
|
37
|
+
- Documentation: `docs/CONFIGURATION.md` (the full options reference), and new
|
|
38
|
+
architecture and wire protocol docs detailing the process model, worker
|
|
39
|
+
lifecycle, data-dir layout, and the HTTP/mDNS/pairing protocol. The README
|
|
40
|
+
links them and documents the plugin options inline.
|
|
41
|
+
- Plugin options are validated at setup. A `port` outside `[0, 65535]` or not an
|
|
42
|
+
integer, a `bind` other than `loopback`/`lan`, a non-boolean `advertise`, or an
|
|
43
|
+
empty/non-string `dataDir` now fails fast with a clear message instead of
|
|
44
|
+
surfacing later as `EADDRINUSE`, a bind on the wrong interface, or a data dir
|
|
45
|
+
at the wrong path. `tsconfig.test.json` and a `pnpm typecheck:tests` step
|
|
46
|
+
typecheck the test suite, which `tsconfig.json` (src only) never did.
|
|
47
|
+
|
|
48
|
+
### Changed
|
|
49
|
+
|
|
50
|
+
- `engines.node` is now `>=22.5.0` (the first release with `node:sqlite`), and
|
|
51
|
+
`@types/node` is pinned to the max Node major tested in CI (24) instead of 26.
|
|
52
|
+
`scripts/smoke-dist.mjs` now asserts the v2 (`setup`) entrypoint, and
|
|
53
|
+
`biome.json` is migrated to the 2.5.x schema.
|
|
54
|
+
- `mesh_lock` is documented and advertised as local to this machine: it is
|
|
55
|
+
enforced between sessions sharing this host's data directory and is not part
|
|
56
|
+
of the wire protocol. A guard test fails the build if a lock route reappears
|
|
57
|
+
on the server.
|
|
58
|
+
- Removed the Ed25519 keypair ceremony in node identity: nothing signed or
|
|
59
|
+
verified with it, so the short fingerprint is derived from `node_id`.
|
|
60
|
+
Existing node ids are preserved on upgrade; the fingerprint value changes,
|
|
61
|
+
which may require re-pairing peers.
|
|
62
|
+
- Workers spawned by `mesh_spawn` run with `OPENCODE_MESH_CHILD=1` and skip the
|
|
63
|
+
server, mDNS and all mesh tools, so a pool of N workers no longer costs N
|
|
64
|
+
mesh nodes.
|
|
65
|
+
- `mesh_worker_logs` reads only the tail of a worker log instead of loading the
|
|
66
|
+
whole file on the host's event loop; `mesh_status` caches `tailscale status`
|
|
67
|
+
for 60s and bounds the subprocess with a 2s timeout.
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
|
|
71
|
+
- The docs no longer claim security behaviour the code does not implement:
|
|
72
|
+
`SECURITY.md` drops the "refuses entries that look like API-key formats"
|
|
73
|
+
promise (no such filtering exists) and the umask-077 claim (the data
|
|
74
|
+
*directory* is created `0700`; the SQLite file itself is not `chmod`ed), and
|
|
75
|
+
the README drops the non-existent `"allow_tailnet"` option while updating its
|
|
76
|
+
stale install pin.
|
|
77
|
+
- `mesh_pair` now rejects an empty `node_id` or `token` instead of completing a
|
|
78
|
+
pairing with a credential nobody can present (or that clobbers a peer record).
|
|
79
|
+
A partially-supplied pair (`node_id` without `token`, or vice versa) is an
|
|
80
|
+
error rather than being silently ignored.
|
|
81
|
+
- The mesh server reports a body read failure as `400` (malformed request) rather
|
|
82
|
+
than `413` (too large): a client that drops the connection mid-body no longer
|
|
83
|
+
looks like an oversized payload.
|
|
84
|
+
- Peer addresses that carry an IPv6 zone id (`[fe80::1%eth0]:4399`) are accepted,
|
|
85
|
+
so a link-local peer is no longer silently unreachable.
|
|
86
|
+
- `defaultDataDir()` no longer resolves to a filesystem-root path
|
|
87
|
+
(`/.local/share/opencode-mesh`) when `HOME` is unset or blank: it falls back to
|
|
88
|
+
`os.homedir()`, then `os.tmpdir()`.
|
|
89
|
+
- The node identity migration now finishes on disk: a `node.json` written by
|
|
90
|
+
<= 0.2.0 is rewritten without its dead Ed25519 keypair, so the stale key
|
|
91
|
+
material no longer lingers after the id is loaded. A corrupt or `node_id`-less
|
|
92
|
+
`node.json` now fails loudly with a recovery path instead of silently minting a
|
|
93
|
+
new node id, which would break every peer that recognised the node. Closes #31.
|
|
94
|
+
- `mesh_lock` no longer throws a raw `UNIQUE constraint failed` error when two
|
|
95
|
+
opencode sessions sharing the same data directory race for the same path. The
|
|
96
|
+
lock claim is a single atomic `INSERT ... ON CONFLICT DO NOTHING`, and the
|
|
97
|
+
worker status transition is a single guarded `UPDATE`, so a stale
|
|
98
|
+
read-then-write can neither raise nor overwrite a concurrently finalized row.
|
|
99
|
+
- The mesh database now records a schema version (`PRAGMA user_version`) and
|
|
100
|
+
creates indexes for its hot lookups (unread messages, pending pairing tokens,
|
|
101
|
+
peer tokens, running workers, expired locks).
|
|
102
|
+
- On OpenCode 2.x hosts, `mesh_spawn` and `mesh_worker_remove` no longer hand the
|
|
103
|
+
raw `ctx.worktree` domain to the REST-shaped worktree client. The in-process
|
|
104
|
+
domain (which resolves payloads directly, without the v1 `{ data, error }`
|
|
105
|
+
envelope) is wrapped back into that shape, and an injected
|
|
106
|
+
`options.worktreeClient` now takes precedence. Closes #29.
|
|
107
|
+
- Worktree create/remove calls on the 1.x REST client are bounded by a 15s
|
|
108
|
+
timeout. A create response with no directory, or a remove response that is
|
|
109
|
+
not a boolean, now raises a clear error instead of persisting an `undefined`
|
|
110
|
+
directory. When the 2.x domain reports only a directory (no branch), the
|
|
111
|
+
worker's branch falls back to that directory's name.
|
|
112
|
+
- A spawn that fails before the child runs no longer leaks its worktree:
|
|
113
|
+
`mesh_spawn` removes the worktree and the dead registry row when the child
|
|
114
|
+
never starts or `runWorker` throws. `mesh_worker_remove` keeps the registry
|
|
115
|
+
row when the worktree was not actually removed, instead of orphaning it.
|
|
116
|
+
- Node runtime support: the published package no longer calls `require()` from
|
|
117
|
+
ESM modules. The Node fallback paths (`node:sqlite` engine, `node:crypto`)
|
|
118
|
+
now use static and dynamic imports and actually run. Vitest's module runner
|
|
119
|
+
injects a `require`, which hid the `ReferenceError` from the suite, so
|
|
120
|
+
`scripts/smoke-dist.mjs` loads the built package under plain Node and is part
|
|
121
|
+
of `pnpm verify`.
|
|
122
|
+
- `mesh_send` no longer derives the peer's port from the local node. Discovered
|
|
123
|
+
addresses now carry the port from the mDNS SRV record (`[ipv6]:port` for IPv6
|
|
124
|
+
literals), and a portless address is refused instead of resolving to a wrong
|
|
125
|
+
socket. Peers that fall back to an ephemeral port are now reachable.
|
|
126
|
+
- Workers killed through `mesh_worker_stop` no longer orphan their own child
|
|
127
|
+
processes: workers are detached process-group leaders and a stop takes the
|
|
128
|
+
group down. The late `exit` event after a deliberate stop no longer throws;
|
|
129
|
+
a host restart reconciles `running` rows whose pid is gone.
|
|
130
|
+
- A worker that fails to start (binary missing, `error` event with no `exit`)
|
|
131
|
+
is now finalized as `failed` instead of staying `running` forever with a
|
|
132
|
+
leaked live entry; a `-1` pid is never persisted. `mesh_spawn` reports the
|
|
133
|
+
failure instead of a success envelope.
|
|
134
|
+
- A worker's stderr is drained into its log; a child writing more than the pipe
|
|
135
|
+
buffer (~64 KB) to stderr no longer blocks. `mesh_worker_stop` escalates
|
|
136
|
+
`SIGTERM` to `SIGKILL` after 3s so a worker ignoring the signal cannot linger.
|
|
137
|
+
- Worker logs are capped at 512 KB (rotated to `<id>.log.1`) and deleted by
|
|
138
|
+
`mesh_worker_remove`, so a chatty worker cannot fill the disk.
|
|
139
|
+
- A JSON line split across two stdout chunks is now reassembled before parsing,
|
|
140
|
+
so a worker's `session_id` is captured instead of silently dropping to null.
|
|
141
|
+
A session id arriving after the row is terminal is ignored.
|
|
142
|
+
|
|
143
|
+
### Security
|
|
144
|
+
|
|
145
|
+
- The mesh HTTP server binds to `127.0.0.1` by default. `"bind": "lan"` opts
|
|
146
|
+
into listening on all interfaces, and `mesh_status` / the `mesh_pair` offer
|
|
147
|
+
report the address actually bound instead of a hardcoded loopback string.
|
|
148
|
+
- Pairing offers expire after 5 minutes, are pruned on check, and a pending
|
|
149
|
+
token alone no longer installs a permanent peer: the claimed node must
|
|
150
|
+
already be known to this host (mDNS discovery or explicit `mesh_pair`).
|
|
151
|
+
Auto-pairing a previously unknown node id is gone.
|
|
152
|
+
- Discovered peers keep their hostname and fingerprint through pairing instead
|
|
153
|
+
of collapsing to `"pending"`, so `mesh_status` still shows a real identity.
|
|
154
|
+
|
|
155
|
+
### Removed
|
|
156
|
+
|
|
157
|
+
- `/announce` endpoint, its parser and `touchAddress` (no client ever called
|
|
158
|
+
the route).
|
|
159
|
+
|
|
10
160
|
## [0.2.0] - 2026-10-12
|
|
11
161
|
|
|
12
162
|
### Added
|
package/README.md
CHANGED
|
@@ -10,6 +10,8 @@ Coordination for [OpenCode](https://opencode.ai): multiple sessions working toge
|
|
|
10
10
|
|
|
11
11
|
Each node advertises itself over mDNS, pairs with explicit operator approval (per-peer bearer tokens, deny by default), then sessions can exchange messages (`mesh_send` / `mesh_inbox`) and coordinate on shared work (`mesh_lock` / `mesh_unlock`). Tailscale IPs are picked up automatically when `tailscale status` works, for cross-subnet pools.
|
|
12
12
|
|
|
13
|
+
`mesh_lock` is **local to your machine**: it is enforced between OpenCode sessions sharing this host's data directory (`~/.local/share/opencode-mesh/`). Locks are not part of the wire protocol, so a peer on another node does not see or respect them. Remote nodes coordinate through messages (`mesh_send`), not locks.
|
|
14
|
+
|
|
13
15
|
## Install
|
|
14
16
|
|
|
15
17
|
Register the plugin in `opencode.json` (project or global `~/.config/opencode/opencode.json`):
|
|
@@ -24,12 +26,36 @@ Restart OpenCode. The package is installed automatically at startup into opencod
|
|
|
24
26
|
|
|
25
27
|
```json
|
|
26
28
|
{
|
|
27
|
-
"plugin": ["@log0u7/opencode-mesh@0.
|
|
29
|
+
"plugin": ["@log0u7/opencode-mesh@0.4.0"]
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Configuration
|
|
34
|
+
|
|
35
|
+
All options are optional; see [docs/CONFIGURATION.md](docs/CONFIGURATION.md) for the reference.
|
|
36
|
+
|
|
37
|
+
On OpenCode 1.x hosts, options travel in a package-and-options tuple:
|
|
38
|
+
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"plugin": [["@log0u7/opencode-mesh", { "port": 4399, "bind": "loopback", "advertise": true }]]
|
|
42
|
+
}
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
On 2.x hosts the key is `plugins` and each entry is an object:
|
|
46
|
+
|
|
47
|
+
```json
|
|
48
|
+
{
|
|
49
|
+
"plugins": [
|
|
50
|
+
{ "package": "@log0u7/opencode-mesh", "options": { "port": 4399, "bind": "lan" } }
|
|
51
|
+
]
|
|
28
52
|
}
|
|
29
53
|
```
|
|
30
54
|
|
|
31
55
|
Node identity and mailbox live under `~/.local/share/opencode-mesh/` (honors `XDG_DATA_HOME`), created with restrictive permissions.
|
|
32
56
|
|
|
57
|
+
Workers spawned with `mesh_spawn` run with `OPENCODE_MESH_CHILD=1`: they skip the mesh server, mDNS and all mesh tools, so a pool of N workers costs N worktrees, not N mesh nodes.
|
|
58
|
+
|
|
33
59
|
Note (npm 12): the package ships no lifecycle install scripts and needs no `allowScripts` / allowlist on install (its runtime dependency `bonjour-service` has none either).
|
|
34
60
|
|
|
35
61
|
## Usage
|
|
@@ -38,10 +64,10 @@ Same machine: start two OpenCode instances in the same repository.
|
|
|
38
64
|
|
|
39
65
|
```
|
|
40
66
|
mesh_status() # local sessions + paired peers + active locks
|
|
41
|
-
mesh_pair() #
|
|
67
|
+
mesh_pair() # emit a pairing offer (5 min) / complete the peer's offer
|
|
42
68
|
mesh_send(peer="laptop", subject="handoff", body="...")
|
|
43
69
|
mesh_inbox() # pull new messages, ack
|
|
44
|
-
mesh_lock(path="src/api.ts", ttl=300) # claim a file before editing
|
|
70
|
+
mesh_lock(path="src/api.ts", ttl=300) # claim a file before editing (this machine only)
|
|
45
71
|
mesh_unlock(path="src/api.ts")
|
|
46
72
|
```
|
|
47
73
|
|
|
@@ -50,10 +76,10 @@ mesh_unlock(path="src/api.ts")
|
|
|
50
76
|
| Tool | Args | Description |
|
|
51
77
|
|---|---|---|
|
|
52
78
|
| `mesh_status` | : local session registry, own address, paired peers, active locks. |
|
|
53
|
-
| `mesh_pair` | `
|
|
79
|
+
| `mesh_pair` | `node_id?`, `token?`, `address?` | No args: emit a pairing offer (5 min ttl). With args: complete the peer's offer. |
|
|
54
80
|
| `mesh_send` | `peer`, `subject`, `body` | Deliver a message to a peer's mailbox. |
|
|
55
81
|
| `mesh_inbox` | `ack?` | Fetch unread messages; ack marks them read. |
|
|
56
|
-
| `mesh_lock` | `path`, `ttl?` | Exclusive claim on a file or
|
|
82
|
+
| `mesh_lock` | `path`, `ttl?` | Exclusive claim on a file or path, enforced only between sessions on this machine (default ttl 600s). Not visible to remote peers. |
|
|
57
83
|
| `mesh_unlock` | `path` | Release a claim. |
|
|
58
84
|
|
|
59
85
|
### Orchestrator
|
|
@@ -72,22 +98,29 @@ Workers run `opencode run --dir <worktree> --format json` headless with `--auto`
|
|
|
72
98
|
|
|
73
99
|
### Security model
|
|
74
100
|
|
|
75
|
-
-
|
|
76
|
-
-
|
|
77
|
-
-
|
|
78
|
-
-
|
|
101
|
+
- The HTTP mesh server binds to `127.0.0.1` by default. Set `"bind": "lan"` in the plugin options to listen on all interfaces for a LAN pool.
|
|
102
|
+
- Every endpoint requires a per-peer bearer token; nothing is open by default.
|
|
103
|
+
- Pairing offers expire after 5 minutes. A pending token alone grants nothing: the claimed node must already be known to this host (discovered over mDNS, or paired out of band with `mesh_pair`). Both sides run `mesh_pair` to complete a pairing, so a leaked offer cannot install a permanent peer on its own.
|
|
104
|
+
- Peer addresses always carry the advertised port; a portless address is refused instead of being completed with the local port.
|
|
105
|
+
- mDNS TXT records carry node id + fingerprint only, never secrets.
|
|
106
|
+
- Tailnet addresses are surfaced by `mesh_status` when `tailscale` runs, for cross-subnet pools.
|
|
107
|
+
- Messages travel over plain HTTP: there is no TLS layer. Loopback and trusted networks only.
|
|
79
108
|
|
|
80
109
|
## Development
|
|
81
110
|
|
|
82
|
-
Requires Node >= 22 (
|
|
111
|
+
Requires Node >= 22.5 (`mise install`) and pnpm (corepack).
|
|
83
112
|
|
|
84
113
|
```sh
|
|
85
114
|
pnpm install
|
|
86
|
-
pnpm verify
|
|
87
|
-
pnpm
|
|
115
|
+
pnpm verify # biome + typecheck + vitest + Node smoke of dist/
|
|
116
|
+
pnpm typecheck:tests # typecheck the test suite (also enforced in CI)
|
|
117
|
+
pnpm build:check # tsc build + pack dry-run
|
|
118
|
+
pnpm smoke:dist # build, then load dist/ under plain Node (no vitest shims)
|
|
88
119
|
```
|
|
89
120
|
|
|
90
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for the workflow
|
|
121
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for the workflow, and the [docs/](docs/) folder for
|
|
122
|
+
[configuration](docs/CONFIGURATION.md), [architecture](docs/ARCHITECTURE.md), and the
|
|
123
|
+
wire [protocol](docs/PROTOCOL.md).
|
|
91
124
|
|
|
92
125
|
## License
|
|
93
126
|
|
package/dist/lib/client.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export type SendTarget = {
|
|
|
4
4
|
from: string;
|
|
5
5
|
subject: string;
|
|
6
6
|
body: string;
|
|
7
|
+
/** `<base64 spki>.<base64 ed25519 signature>` over node_id:token. */
|
|
8
|
+
proof?: string;
|
|
7
9
|
};
|
|
8
10
|
export type SendResult = "ok" | "unreachable" | "unauthorized" | "error";
|
|
9
11
|
export declare function sendMail(target: SendTarget): Promise<SendResult>;
|
package/dist/lib/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,UAAU,GAAG;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,aAAa,GAAG,cAAc,GAAG,OAAO,CAAC;AAIzE,wBAAsB,QAAQ,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,CA0BtE"}
|
package/dist/lib/client.js
CHANGED
|
@@ -8,7 +8,12 @@ export async function sendMail(target) {
|
|
|
8
8
|
"content-type": "application/json",
|
|
9
9
|
authorization: `Bearer ${target.token}`,
|
|
10
10
|
},
|
|
11
|
-
body: JSON.stringify({
|
|
11
|
+
body: JSON.stringify({
|
|
12
|
+
from: target.from,
|
|
13
|
+
subject: target.subject,
|
|
14
|
+
body: target.body,
|
|
15
|
+
...(target.proof !== undefined ? { proof: target.proof } : {}),
|
|
16
|
+
}),
|
|
12
17
|
signal: AbortSignal.timeout(5000),
|
|
13
18
|
});
|
|
14
19
|
if (response.ok) {
|
package/dist/lib/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/lib/client.ts"],"names":[],"mappings":"AAYA,8EAA8E;AAC9E,gCAAgC;AAChC,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,MAAkB;IAC/C,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,MAAM,CAAC,GAAG,OAAO,EAAE;YACjD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,cAAc,EAAE,kBAAkB;gBAClC,aAAa,EAAE,UAAU,MAAM,CAAC,KAAK,EAAE;aACxC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,OAAO,EAAE,MAAM,CAAC,OAAO;gBACvB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,GAAG,CAAC,MAAM,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aAC/D,CAAC;YACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,IAAI,QAAQ,CAAC,EAAE,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,QAAQ,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC5B,OAAO,cAAc,CAAC;QACxB,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,aAAa,CAAC;IACvB,CAAC;AACH,CAAC"}
|
package/dist/lib/db.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;
|
|
1
|
+
{"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAGA,OAAO,EAAc,KAAK,UAAU,EAAE,MAAM,aAAa,CAAC;AAE1D,MAAM,MAAM,MAAM,GAAG;IACnB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAuEF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAW/C"}
|
package/dist/lib/db.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { mkdirSync } from "node:fs";
|
|
2
2
|
import { dirname } from "node:path";
|
|
3
3
|
import { openSqlite } from "./sqlite.js";
|
|
4
|
+
// Bump when a schema change needs a migration step; the version anchors future
|
|
5
|
+
// migrations that cannot be expressed as idempotent `CREATE ... IF NOT EXISTS`.
|
|
6
|
+
const SCHEMA_VERSION = 2;
|
|
4
7
|
const SCHEMA = `
|
|
5
8
|
CREATE TABLE IF NOT EXISTS peers (
|
|
6
9
|
node_id TEXT PRIMARY KEY,
|
|
@@ -9,6 +12,7 @@ CREATE TABLE IF NOT EXISTS peers (
|
|
|
9
12
|
addresses TEXT NOT NULL DEFAULT '[]',
|
|
10
13
|
paired INTEGER NOT NULL DEFAULT 0,
|
|
11
14
|
token TEXT,
|
|
15
|
+
public_key TEXT,
|
|
12
16
|
last_seen INTEGER NOT NULL
|
|
13
17
|
);
|
|
14
18
|
CREATE TABLE IF NOT EXISTS messages (
|
|
@@ -41,7 +45,28 @@ CREATE TABLE IF NOT EXISTS workers (
|
|
|
41
45
|
started_at INTEGER NOT NULL,
|
|
42
46
|
finished_at INTEGER
|
|
43
47
|
);
|
|
48
|
+
CREATE INDEX IF NOT EXISTS idx_messages_status_created ON messages(status, created_at);
|
|
49
|
+
CREATE INDEX IF NOT EXISTS idx_pending_tokens_created ON pending_tokens(created_at);
|
|
50
|
+
CREATE INDEX IF NOT EXISTS idx_peers_token ON peers(token);
|
|
51
|
+
CREATE INDEX IF NOT EXISTS idx_workers_status ON workers(status);
|
|
52
|
+
CREATE INDEX IF NOT EXISTS idx_locks_expires ON locks(expires_at);
|
|
44
53
|
`;
|
|
54
|
+
function migrate(conn) {
|
|
55
|
+
const current = conn.get("PRAGMA user_version")?.user_version ?? 0;
|
|
56
|
+
if (current >= SCHEMA_VERSION) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
// Every statement in SCHEMA is idempotent, so a version-0 database (fresh or
|
|
60
|
+
// pre-versioning) is brought up to date by re-running it.
|
|
61
|
+
conn.exec(SCHEMA);
|
|
62
|
+
// v2: pairing proofs are verified against a pinned public key, so peers gain
|
|
63
|
+
// the column. ALTER TABLE is not idempotent: guard it on the live schema.
|
|
64
|
+
const peerColumns = conn.all("PRAGMA table_info(peers)").map((row) => row.name);
|
|
65
|
+
if (!peerColumns.includes("public_key")) {
|
|
66
|
+
conn.exec("ALTER TABLE peers ADD COLUMN public_key TEXT");
|
|
67
|
+
}
|
|
68
|
+
conn.run(`PRAGMA user_version = ${SCHEMA_VERSION}`);
|
|
69
|
+
}
|
|
45
70
|
export function openMeshDb(path) {
|
|
46
71
|
if (path !== ":memory:") {
|
|
47
72
|
mkdirSync(dirname(path), { recursive: true });
|
|
@@ -49,7 +74,7 @@ export function openMeshDb(path) {
|
|
|
49
74
|
const conn = openSqlite(path);
|
|
50
75
|
conn.run("PRAGMA journal_mode = WAL");
|
|
51
76
|
conn.run("PRAGMA busy_timeout = 5000");
|
|
52
|
-
conn
|
|
77
|
+
migrate(conn);
|
|
53
78
|
return { conn, close: () => conn.close() };
|
|
54
79
|
}
|
|
55
80
|
//# sourceMappingURL=db.js.map
|
package/dist/lib/db.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAC;AAO1D,MAAM,MAAM,GAAG
|
|
1
|
+
{"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/lib/db.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,UAAU,EAAmB,MAAM,aAAa,CAAC;AAO1D,+EAA+E;AAC/E,gFAAgF;AAChF,MAAM,cAAc,GAAG,CAAC,CAAC;AAEzB,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8Cd,CAAC;AAEF,SAAS,OAAO,CAAC,IAAgB;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAA2B,qBAAqB,CAAC,EAAE,YAAY,IAAI,CAAC,CAAC;IAC7F,IAAI,OAAO,IAAI,cAAc,EAAE,CAAC;QAC9B,OAAO;IACT,CAAC;IACD,6EAA6E;IAC7E,0DAA0D;IAC1D,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAClB,6EAA6E;IAC7E,0EAA0E;IAC1E,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAAmB,0BAA0B,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAClG,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,8CAA8C,CAAC,CAAC;IAC5D,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,yBAAyB,cAAc,EAAE,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAY;IACrC,IAAI,IAAI,KAAK,UAAU,EAAE,CAAC;QACxB,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;IAED,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IACtC,IAAI,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;IACvC,OAAO,CAAC,IAAI,CAAC,CAAC;IAEd,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,CAAC;AAC7C,CAAC"}
|
package/dist/lib/discovery.d.ts
CHANGED
|
@@ -8,12 +8,14 @@ export declare function advertiseMesh(options: {
|
|
|
8
8
|
port: number;
|
|
9
9
|
node_id: string;
|
|
10
10
|
fingerprint: string;
|
|
11
|
+
public_key: string;
|
|
11
12
|
}): AdvertiseHandle;
|
|
12
13
|
export type DiscoveredPeer = {
|
|
13
14
|
node_id: string;
|
|
14
15
|
hostname: string;
|
|
15
16
|
fingerprint: string;
|
|
16
17
|
addresses: string[];
|
|
18
|
+
public_key?: string;
|
|
17
19
|
};
|
|
18
20
|
export declare function browseMesh(options: {
|
|
19
21
|
bonjour: Bonjour;
|
|
@@ -21,5 +23,6 @@ export declare function browseMesh(options: {
|
|
|
21
23
|
}): {
|
|
22
24
|
close(): void;
|
|
23
25
|
};
|
|
26
|
+
export declare function resetTailnetCache(): void;
|
|
24
27
|
export declare function tailnetAddresses(): Promise<string[]>;
|
|
25
28
|
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAIF,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAC;AAE/C,eAAO,MAAM,iBAAiB,kBAAkB,CAAC;AAEjD,MAAM,MAAM,eAAe,GAAG;IAC5B,KAAK,IAAI,IAAI,CAAC;CACf,CAAC;AAIF,wBAAgB,aAAa,CAAC,OAAO,EAAE;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB,GAAG,eAAe,CAalB;AAED,MAAM,MAAM,cAAc,GAAG;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,wBAAgB,UAAU,CAAC,OAAO,EAAE;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CAC9C,GAAG;IAAE,KAAK,IAAI,IAAI,CAAA;CAAE,CAuBpB;AAsBD,wBAAgB,iBAAiB,IAAI,IAAI,CAExC;AAED,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC,CAgC1D"}
|
package/dist/lib/discovery.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
export const MESH_SERVICE_TYPE = "opencode-mesh";
|
|
2
|
-
// Advertise this node on the LAN. TXT carries
|
|
3
|
-
//
|
|
2
|
+
// Advertise this node on the LAN. TXT carries the node id, key fingerprint and
|
|
3
|
+
// the pairing public key (pk): never secrets.
|
|
4
4
|
export function advertiseMesh(options) {
|
|
5
5
|
const service = options.bonjour.publish({
|
|
6
6
|
name: options.node_id,
|
|
7
7
|
type: MESH_SERVICE_TYPE,
|
|
8
8
|
port: options.port,
|
|
9
|
-
txt: { id: options.node_id, fp: options.fingerprint },
|
|
9
|
+
txt: { id: options.node_id, fp: options.fingerprint, pk: options.public_key },
|
|
10
10
|
});
|
|
11
11
|
return {
|
|
12
12
|
close() {
|
|
@@ -25,7 +25,10 @@ export function browseMesh(options) {
|
|
|
25
25
|
node_id: id,
|
|
26
26
|
hostname: service.host ?? service.name,
|
|
27
27
|
fingerprint: fp,
|
|
28
|
-
addresses: service.addresses
|
|
28
|
+
addresses: socketAddresses(service.addresses, service.port),
|
|
29
|
+
...(typeof service.txt?.pk === "string" && service.txt.pk.length > 0
|
|
30
|
+
? { public_key: service.txt.pk }
|
|
31
|
+
: {}),
|
|
29
32
|
});
|
|
30
33
|
});
|
|
31
34
|
return {
|
|
@@ -34,12 +37,33 @@ export function browseMesh(options) {
|
|
|
34
37
|
},
|
|
35
38
|
};
|
|
36
39
|
}
|
|
40
|
+
// An mDNS A/AAAA record is a bare IP: the peer's listening port comes from the
|
|
41
|
+
// SRV record in the same service. Guessing the port from the local node is
|
|
42
|
+
// wrong whenever the peer fell back to an ephemeral port, so a record without
|
|
43
|
+
// a port yields no address at all rather than a wrong one.
|
|
44
|
+
function socketAddresses(ips, port) {
|
|
45
|
+
if (port === undefined) {
|
|
46
|
+
return [];
|
|
47
|
+
}
|
|
48
|
+
return (ips ?? []).map((ip) => (ip.includes(":") ? `[${ip}]:${port}` : `${ip}:${port}`));
|
|
49
|
+
}
|
|
37
50
|
// Tailnet addresses let peers connect across subnets when tailscale runs.
|
|
38
|
-
// Absent CLI = empty list, never an error.
|
|
51
|
+
// Absent CLI = empty list, never an error. The result is cached: mesh_status is
|
|
52
|
+
// a hot tool call and `tailscale status --json` is a subprocess we must not pay
|
|
53
|
+
// on every invocation.
|
|
54
|
+
const TAILNET_TTL_MS = 60_000;
|
|
55
|
+
const TAILNET_TIMEOUT_MS = 2000;
|
|
56
|
+
let tailnetCache = null;
|
|
57
|
+
export function resetTailnetCache() {
|
|
58
|
+
tailnetCache = null;
|
|
59
|
+
}
|
|
39
60
|
export async function tailnetAddresses() {
|
|
61
|
+
if (tailnetCache !== null && tailnetCache.expiresAt > Date.now()) {
|
|
62
|
+
return tailnetCache.addresses;
|
|
63
|
+
}
|
|
40
64
|
const { execFile } = await import("node:child_process");
|
|
41
|
-
|
|
42
|
-
execFile("tailscale", ["status", "--json"], (error, stdout) => {
|
|
65
|
+
const addresses = await new Promise((resolve) => {
|
|
66
|
+
execFile("tailscale", ["status", "--json"], { timeout: TAILNET_TIMEOUT_MS }, (error, stdout) => {
|
|
43
67
|
if (error) {
|
|
44
68
|
resolve([]);
|
|
45
69
|
return;
|
|
@@ -54,5 +78,7 @@ export async function tailnetAddresses() {
|
|
|
54
78
|
}
|
|
55
79
|
});
|
|
56
80
|
});
|
|
81
|
+
tailnetCache = { addresses, expiresAt: Date.now() + TAILNET_TTL_MS };
|
|
82
|
+
return addresses;
|
|
57
83
|
}
|
|
58
84
|
//# sourceMappingURL=discovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAMjD
|
|
1
|
+
{"version":3,"file":"discovery.js","sourceRoot":"","sources":["../../src/lib/discovery.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,iBAAiB,GAAG,eAAe,CAAC;AAMjD,+EAA+E;AAC/E,8CAA8C;AAC9C,MAAM,UAAU,aAAa,CAAC,OAM7B;IACC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QACtC,IAAI,EAAE,OAAO,CAAC,OAAO;QACrB,IAAI,EAAE,iBAAiB;QACvB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,GAAG,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,OAAO,EAAE,EAAE,EAAE,OAAO,CAAC,WAAW,EAAE,EAAE,EAAE,OAAO,CAAC,UAAU,EAAE;KAC9E,CAAC,CAAC;IAEH,OAAO;QACL,KAAK;YACH,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAUD,MAAM,UAAU,UAAU,CAAC,OAG1B;IACC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,EAAE,CAAC,OAAO,EAAE,EAAE;QAC5E,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC;QAC3B,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,OAAO,EAAE,KAAK,QAAQ,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACxE,OAAO;QACT,CAAC;QACD,OAAO,CAAC,YAAY,CAAC;YACnB,OAAO,EAAE,EAAE;YACX,QAAQ,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;YACtC,WAAW,EAAE,EAAE;YACf,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,IAAI,CAAC;YAC3D,GAAG,CAAC,OAAO,OAAO,CAAC,GAAG,EAAE,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,GAAG,CAAC;gBAClE,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE;gBAChC,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK;YACH,OAAO,CAAC,IAAI,EAAE,CAAC;QACjB,CAAC;KACF,CAAC;AACJ,CAAC;AAED,+EAA+E;AAC/E,2EAA2E;AAC3E,8EAA8E;AAC9E,2DAA2D;AAC3D,SAAS,eAAe,CAAC,GAAyB,EAAE,IAAwB;IAC1E,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC;AAC3F,CAAC;AAED,0EAA0E;AAC1E,gFAAgF;AAChF,gFAAgF;AAChF,uBAAuB;AACvB,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,IAAI,YAAY,GAAsD,IAAI,CAAC;AAE3E,MAAM,UAAU,iBAAiB;IAC/B,YAAY,GAAG,IAAI,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,YAAY,KAAK,IAAI,IAAI,YAAY,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;QACjE,OAAO,YAAY,CAAC,SAAS,CAAC;IAChC,CAAC;IAED,MAAM,EAAE,QAAQ,EAAE,GAAG,MAAM,MAAM,CAAC,oBAAoB,CAAC,CAAC;IAExD,MAAM,SAAS,GAAG,MAAM,IAAI,OAAO,CAAW,CAAC,OAAO,EAAE,EAAE;QACxD,QAAQ,CACN,WAAW,EACX,CAAC,QAAQ,EAAE,QAAQ,CAAC,EACpB,EAAE,OAAO,EAAE,kBAAkB,EAAE,EAC/B,CAAC,KAAmB,EAAE,MAAc,EAAE,EAAE;YACtC,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,CAAC,EAAE,CAAC,CAAC;gBACZ,OAAO;YACT,CAAC;YACD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAA2C,CAAC;gBAC5E,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC;gBACtC,OAAO,CACL,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,EAAE,EAAgB,EAAE,CAAC,OAAO,EAAE,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CACnF,CAAC;YACJ,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,CAAC,EAAE,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,YAAY,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,cAAc,EAAE,CAAC;IACrE,OAAO,SAAS,CAAC;AACnB,CAAC"}
|
package/dist/lib/identity.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
type Jwk = {
|
|
2
|
-
kty?: string;
|
|
3
|
-
x?: string;
|
|
4
|
-
[key: string]: unknown;
|
|
5
|
-
};
|
|
6
1
|
export type NodeIdentity = {
|
|
7
2
|
node_id: string;
|
|
8
3
|
hostname: string;
|
|
4
|
+
public_key: string;
|
|
5
|
+
private_key: string;
|
|
9
6
|
fingerprint: string;
|
|
10
|
-
public_key: Jwk;
|
|
11
|
-
private_key: Jwk;
|
|
12
7
|
};
|
|
13
8
|
export declare function loadOrCreateIdentity(dataDir: string): NodeIdentity;
|
|
14
|
-
export
|
|
9
|
+
export declare function pairingProofPayload(nodeId: string, token: string): string;
|
|
10
|
+
export declare function signPairingProof(privateKey: string, payload: string): string;
|
|
11
|
+
export declare function pairingProof(identity: {
|
|
12
|
+
node_id: string;
|
|
13
|
+
public_key: string;
|
|
14
|
+
private_key: string;
|
|
15
|
+
}, token: string): string;
|
|
16
|
+
export declare function verifyPairingProof(publicKey: string, payload: string, proof: string): boolean;
|
|
15
17
|
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/lib/identity.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../../src/lib/identity.ts"],"names":[],"mappings":"AAaA,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;CACrB,CAAC;AAIF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAoBlE;AA+FD,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEzE;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAO5E;AAGD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,EACtE,KAAK,EAAE,MAAM,GACZ,MAAM,CAKR;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAW7F"}
|