@unagents/messenger-protocol 0.9.0 → 0.11.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/dist/index.d.mts +210 -4
- package/dist/index.d.ts +210 -4
- package/dist/index.mjs +56 -1
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -56,6 +56,37 @@ declare const ENV: {
|
|
|
56
56
|
readonly DELIVERY: "AGENT_MESSENGER_DELIVERY";
|
|
57
57
|
};
|
|
58
58
|
type EnvName = (typeof ENV)[keyof typeof ENV];
|
|
59
|
+
/**
|
|
60
|
+
* Extra POST routes of the protocol registry. Like `RELAY_ROUTE`, not part of `BROKER_POST_ROUTES`
|
|
61
|
+
* (that table mirrors the legacy broker); request / response shapes are `ProtocolRouteMap` in `http.ts`.
|
|
62
|
+
*/
|
|
63
|
+
declare const PROTOCOL_ROUTES: readonly ["/set-protocol", "/unset-protocol", "/get-protocol"];
|
|
64
|
+
type ProtocolRoute = (typeof PROTOCOL_ROUTES)[number];
|
|
65
|
+
/** Max size of `protocol.json` (UTF-8 bytes). */
|
|
66
|
+
declare const PROTOCOL_MANIFEST_MAX_BYTES: number;
|
|
67
|
+
/** Max size of `PROTOCOL.md` (UTF-8 bytes). */
|
|
68
|
+
declare const PROTOCOL_DOC_MAX_BYTES: number;
|
|
69
|
+
/** Max size of manifest + doc together (UTF-8 bytes). */
|
|
70
|
+
declare const PROTOCOL_TOTAL_MAX_BYTES: number;
|
|
71
|
+
/** Max number of `(name, version)` definitions one broker holds; more is `LIMIT`. */
|
|
72
|
+
declare const PROTOCOL_MAX_STORED = 256;
|
|
73
|
+
/** Max length (characters) of each of `meta.protocol` and `meta.version`. */
|
|
74
|
+
declare const PROTOCOL_META_MAX_LENGTH = 128;
|
|
75
|
+
/** Valid protocol `name`. */
|
|
76
|
+
declare const PROTOCOL_NAME_PATTERN: RegExp;
|
|
77
|
+
/**
|
|
78
|
+
* Error `code`s of the protocol feature (design 7.2). `NO_TAG` is not listed: a repo without tags is
|
|
79
|
+
* not an error (`0.0.0+<sha7>`). Raised by the broker: HASH_MISMATCH, PROTOCOL_CONFLICT, LIMIT,
|
|
80
|
+
* PROTOCOL_NOT_FOUND, and TOO_LARGE / INVALID_DEFINITION on re-check. The rest are raised by the client.
|
|
81
|
+
*/
|
|
82
|
+
declare const PROTOCOL_ERROR_CODES: readonly ["REPO_UNREACHABLE", "UNSUPPORTED_REPO", "VERSION_NOT_FOUND", "INVALID_DEFINITION", "VERSION_MISMATCH", "TOO_LARGE", "HASH_MISMATCH", "PROTOCOL_CONFLICT", "LIMIT", "PROTOCOL_NOT_FOUND", "BROKER_UNSUPPORTED", "INVALID_META"];
|
|
83
|
+
type ProtocolErrorCode = (typeof PROTOCOL_ERROR_CODES)[number];
|
|
84
|
+
/** Discovery send targets (`host:port`, comma separated). When set, probes / announces go there instead of broadcast. */
|
|
85
|
+
declare const DISCOVERY_TARGETS_ENV = "AGENT_MESSENGER_DISCOVERY_TARGETS";
|
|
86
|
+
/** Client state file with the saved broker (default `~/.agent-messenger/client.json`). */
|
|
87
|
+
declare const CLIENT_STATE_ENV = "AGENT_MESSENGER_CLIENT_STATE";
|
|
88
|
+
/** Mesh announce interval in ms (default 10000). */
|
|
89
|
+
declare const MESH_ANNOUNCE_ENV = "AGENT_MESSENGER_MESH_ANNOUNCE_MS";
|
|
59
90
|
|
|
60
91
|
/**
|
|
61
92
|
* Broker HTTP API — request / response JSON shapes.
|
|
@@ -72,6 +103,7 @@ type EnvName = (typeof ENV)[keyof typeof ENV];
|
|
|
72
103
|
* - Unknown POST path: `404 {"error":"not found"}`. Handler exception: `500 {"error":<message>}`.
|
|
73
104
|
* - Any other method: `200 text/plain` `agent-messenger broker <version>\n`.
|
|
74
105
|
*/
|
|
106
|
+
|
|
75
107
|
/** A registered session as stored and returned by the broker. */
|
|
76
108
|
interface Peer {
|
|
77
109
|
/** 8-char broker-generated id (`[a-z0-9]`). */
|
|
@@ -95,6 +127,42 @@ interface Peer {
|
|
|
95
127
|
* registered directly. Never returned by `/list-peers`.
|
|
96
128
|
*/
|
|
97
129
|
origin?: string;
|
|
130
|
+
/**
|
|
131
|
+
* Protocols this peer serves (`/set-protocol`, re-sent on `/register` and `/heartbeat`). Hash only; the
|
|
132
|
+
* definition body lives in the broker's protocol store. Absent when none (and from 0.9.x brokers).
|
|
133
|
+
*/
|
|
134
|
+
protocols?: ProtocolDecl[];
|
|
135
|
+
}
|
|
136
|
+
/** A protocol a peer declares: identity (`name` + `version`) and the hash of its definition body. */
|
|
137
|
+
interface ProtocolDecl {
|
|
138
|
+
/** `^[a-z0-9][a-z0-9._-]{0,63}$` (`PROTOCOL_NAME_PATTERN`). */
|
|
139
|
+
name: string;
|
|
140
|
+
/** semver, or `0.0.0+<sha7>` for a repo without tags. */
|
|
141
|
+
version: string;
|
|
142
|
+
/** `sha256(canonicalJSON({manifest, doc}))` as lower-case hex. */
|
|
143
|
+
hash: string;
|
|
144
|
+
}
|
|
145
|
+
/** The definition body a server fetched from its protocol repo. */
|
|
146
|
+
interface ProtocolDefinition {
|
|
147
|
+
/** Parsed `protocol.json`. */
|
|
148
|
+
manifest: object;
|
|
149
|
+
/** `PROTOCOL.md` text; `""` when the repo has none. */
|
|
150
|
+
doc: string;
|
|
151
|
+
/** Normalized repo notation (`github:o/r`, `gitea:<base>/o/r`, `file:<abs path>`). Not part of the hash. */
|
|
152
|
+
source: string;
|
|
153
|
+
/** tag or sha the body was read at (`local` for a local path). Not part of the hash. */
|
|
154
|
+
ref: string;
|
|
155
|
+
}
|
|
156
|
+
/** What the broker keeps per `(name, version)`. */
|
|
157
|
+
interface StoredProtocol extends ProtocolDecl {
|
|
158
|
+
definition: ProtocolDefinition;
|
|
159
|
+
/** ISO 8601 timestamp of the first successful `/set-protocol` for this `(name, version)`. */
|
|
160
|
+
registered_at: string;
|
|
161
|
+
}
|
|
162
|
+
/** Protocol tag of a message: which protocol (and version) the sender spoke. Both fields are required when present. */
|
|
163
|
+
interface MessageMeta {
|
|
164
|
+
protocol: string;
|
|
165
|
+
version: string;
|
|
98
166
|
}
|
|
99
167
|
type MessageMode = "pull" | "push" | "ping";
|
|
100
168
|
/** A message as stored and returned by the broker. */
|
|
@@ -120,6 +188,8 @@ interface Message {
|
|
|
120
188
|
acknowledged: 0 | 1;
|
|
121
189
|
/** Mesh only: `<sender broker id>:<id there>` of a message forwarded by another broker (duplicate guard). */
|
|
122
190
|
mesh_key?: string;
|
|
191
|
+
/** Protocol tag given to `/send-message`; returned by `/poll-messages` and kept across relay / mesh forwarding. */
|
|
192
|
+
meta?: MessageMeta;
|
|
123
193
|
}
|
|
124
194
|
/** `/list-peers` scope filter. Unknown values behave as `"all"`. */
|
|
125
195
|
type PeerScope = "all" | "host" | "directory" | "repo";
|
|
@@ -146,6 +216,8 @@ interface HealthResponse {
|
|
|
146
216
|
peers: number;
|
|
147
217
|
/** Present (`true`) only when the broker was started as a local fallback (`AGENT_MESSENGER_FALLBACK=1`). */
|
|
148
218
|
fallback?: true;
|
|
219
|
+
/** Present (`true`) only when the broker takes part in the mesh (0.11.0). */
|
|
220
|
+
mesh?: true;
|
|
149
221
|
}
|
|
150
222
|
interface RegisterRequest {
|
|
151
223
|
pid: number;
|
|
@@ -155,15 +227,29 @@ interface RegisterRequest {
|
|
|
155
227
|
tty?: string | null;
|
|
156
228
|
summary?: string;
|
|
157
229
|
name?: string;
|
|
230
|
+
/** Protocols to declare right away (hash only; bodies follow via `/set-protocol`). */
|
|
231
|
+
protocols?: ProtocolDecl[];
|
|
158
232
|
}
|
|
159
233
|
interface RegisterResponse {
|
|
160
234
|
id: string;
|
|
161
235
|
}
|
|
162
236
|
interface HeartbeatRequest {
|
|
163
237
|
id: string;
|
|
238
|
+
/** Every protocol the peer currently serves (hash only), sent on each heartbeat. */
|
|
239
|
+
protocols?: ProtocolDecl[];
|
|
164
240
|
}
|
|
165
|
-
/**
|
|
166
|
-
|
|
241
|
+
/**
|
|
242
|
+
* `ok:false` with `"unknown peer (re-register)"` when the broker does not know the id.
|
|
243
|
+
* `resend` lists the `"name@version"` of declared protocols whose body the broker does not hold; the client answers
|
|
244
|
+
* with `/set-protocol`. Absent when nothing is missing (and from 0.9.x brokers).
|
|
245
|
+
*/
|
|
246
|
+
type HeartbeatResponse = {
|
|
247
|
+
ok: true;
|
|
248
|
+
resend?: string[];
|
|
249
|
+
} | {
|
|
250
|
+
ok: false;
|
|
251
|
+
error: string;
|
|
252
|
+
};
|
|
167
253
|
interface SetSummaryRequest {
|
|
168
254
|
id: string;
|
|
169
255
|
summary?: string;
|
|
@@ -184,6 +270,10 @@ interface ListPeersRequest {
|
|
|
184
270
|
git_root?: string | null;
|
|
185
271
|
/** Peer id to omit from the result (the caller itself). */
|
|
186
272
|
exclude_id?: string;
|
|
273
|
+
/** Only peers that declare this protocol (AND with `scope`). */
|
|
274
|
+
protocol?: string;
|
|
275
|
+
/** Only with `protocol`: only peers that declare exactly this version. */
|
|
276
|
+
version?: string;
|
|
187
277
|
}
|
|
188
278
|
type ListPeersResponse = Peer[];
|
|
189
279
|
interface SendMessageRequest {
|
|
@@ -195,6 +285,8 @@ interface SendMessageRequest {
|
|
|
195
285
|
text?: string;
|
|
196
286
|
/** Defaults to `"pull"`. Unknown values are rejected. */
|
|
197
287
|
mode?: MessageMode;
|
|
288
|
+
/** Protocol tag. Both fields must be strings of at most `PROTOCOL_META_MAX_LENGTH` characters. */
|
|
289
|
+
meta?: MessageMeta;
|
|
198
290
|
}
|
|
199
291
|
type SendMessageResponse = {
|
|
200
292
|
ok: true;
|
|
@@ -243,6 +335,7 @@ interface RelayedMessage {
|
|
|
243
335
|
text: string;
|
|
244
336
|
mode?: MessageMode;
|
|
245
337
|
sent_at: string;
|
|
338
|
+
meta?: MessageMeta;
|
|
246
339
|
}
|
|
247
340
|
interface RelayMessagesRequest {
|
|
248
341
|
messages: RelayedMessage[];
|
|
@@ -256,6 +349,72 @@ interface RelayMessagesResponse {
|
|
|
256
349
|
}
|
|
257
350
|
/** Extra POST route served by the TypeScript broker. Not in `BROKER_POST_ROUTES` (that table mirrors the legacy broker). */
|
|
258
351
|
declare const RELAY_ROUTE: "/relay-messages";
|
|
352
|
+
/** `{ok:false}` answer of the protocol routes; `code` is one of `PROTOCOL_ERROR_CODES`. */
|
|
353
|
+
interface ProtocolErrorResponse {
|
|
354
|
+
ok: false;
|
|
355
|
+
error: string;
|
|
356
|
+
code: ProtocolErrorCode;
|
|
357
|
+
/** `PROTOCOL_CONFLICT`: hash the broker already holds for this `(name, version)`. */
|
|
358
|
+
existing_hash?: string;
|
|
359
|
+
/** `PROTOCOL_CONFLICT`: servers (`name@host`) that hold it. */
|
|
360
|
+
servers?: string[];
|
|
361
|
+
/** `PROTOCOL_NOT_FOUND`: versions the broker does hold for the name (may be empty). */
|
|
362
|
+
versions?: string[];
|
|
363
|
+
}
|
|
364
|
+
interface SetProtocolRequest {
|
|
365
|
+
/** Peer id of the server. */
|
|
366
|
+
id: string;
|
|
367
|
+
name: string;
|
|
368
|
+
version: string;
|
|
369
|
+
/** Re-computed by the broker; a different value is `HASH_MISMATCH`. */
|
|
370
|
+
hash: string;
|
|
371
|
+
definition: ProtocolDefinition;
|
|
372
|
+
}
|
|
373
|
+
/** `{ok:false, error}` without `code` only for an unknown peer id. */
|
|
374
|
+
type SetProtocolResponse = {
|
|
375
|
+
ok: true;
|
|
376
|
+
} | ProtocolErrorResponse | {
|
|
377
|
+
ok: false;
|
|
378
|
+
error: string;
|
|
379
|
+
};
|
|
380
|
+
interface UnsetProtocolRequest {
|
|
381
|
+
id: string;
|
|
382
|
+
/** Protocol to drop; all declarations of the peer when omitted. */
|
|
383
|
+
name?: string;
|
|
384
|
+
}
|
|
385
|
+
type UnsetProtocolResponse = {
|
|
386
|
+
ok: true;
|
|
387
|
+
removed: number;
|
|
388
|
+
} | {
|
|
389
|
+
ok: false;
|
|
390
|
+
error: string;
|
|
391
|
+
};
|
|
392
|
+
interface GetProtocolRequest {
|
|
393
|
+
name: string;
|
|
394
|
+
/** Highest version the broker holds when omitted (`0.0.0+sha` counts as lowest). */
|
|
395
|
+
version?: string;
|
|
396
|
+
}
|
|
397
|
+
/** `servers` = number of alive peers (replicas included) that declare the returned protocol. */
|
|
398
|
+
type GetProtocolResponse = {
|
|
399
|
+
ok: true;
|
|
400
|
+
protocol: StoredProtocol;
|
|
401
|
+
servers: number;
|
|
402
|
+
} | ProtocolErrorResponse;
|
|
403
|
+
/** Request / response pair per protocol route. */
|
|
404
|
+
interface ProtocolRouteMap {
|
|
405
|
+
"/set-protocol": {
|
|
406
|
+
request: SetProtocolRequest;
|
|
407
|
+
response: SetProtocolResponse;
|
|
408
|
+
};
|
|
409
|
+
"/unset-protocol": {
|
|
410
|
+
request: UnsetProtocolRequest;
|
|
411
|
+
response: UnsetProtocolResponse;
|
|
412
|
+
};
|
|
413
|
+
"/get-protocol": {
|
|
414
|
+
request: GetProtocolRequest;
|
|
415
|
+
response: GetProtocolResponse;
|
|
416
|
+
};
|
|
417
|
+
}
|
|
259
418
|
/** The only GET route. */
|
|
260
419
|
declare const HEALTH_ROUTE: "/health";
|
|
261
420
|
/** POST routes, in the order of `ROUTES` in `legacy/src/broker.js`. */
|
|
@@ -319,6 +478,8 @@ interface MeshSyncRequest {
|
|
|
319
478
|
peers: Peer[];
|
|
320
479
|
/** Undelivered messages the sender holds for peers that live on the receiver. Ids are the sender's. */
|
|
321
480
|
messages: Message[];
|
|
481
|
+
/** Definitions declared by the sender's direct peers. Absent from 0.9.x brokers. */
|
|
482
|
+
protocols?: StoredProtocol[];
|
|
322
483
|
}
|
|
323
484
|
interface MeshSyncResponse {
|
|
324
485
|
/** Id of the receiving broker. */
|
|
@@ -327,6 +488,8 @@ interface MeshSyncResponse {
|
|
|
327
488
|
peers: Peer[];
|
|
328
489
|
/** Sender-side ids of the messages the receiver took over; the sender drops them. */
|
|
329
490
|
accepted: number[];
|
|
491
|
+
/** Definitions declared by the receiver's direct peers. Absent from 0.9.x brokers. */
|
|
492
|
+
protocols?: StoredProtocol[];
|
|
330
493
|
}
|
|
331
494
|
|
|
332
495
|
/**
|
|
@@ -342,9 +505,13 @@ declare const DISCOVERY_KEY: "agent-messenger";
|
|
|
342
505
|
declare const DISCOVERY_PROBE_VALUE: "probe";
|
|
343
506
|
/** Value of `DISCOVERY_KEY` in a broker reply. */
|
|
344
507
|
declare const DISCOVERY_REPLY_VALUE: "broker";
|
|
508
|
+
/** Value of `DISCOVERY_KEY` in a mesh broker's self-announcement (0.11.0). */
|
|
509
|
+
declare const DISCOVERY_ANNOUNCE_VALUE: "announce";
|
|
345
510
|
/** Client → broadcast: `{"agent-messenger":"probe"}` */
|
|
346
511
|
interface DiscoveryProbe {
|
|
347
512
|
[DISCOVERY_KEY]: typeof DISCOVERY_PROBE_VALUE;
|
|
513
|
+
/** Mesh brokers add a 16 byte random hex nonce; the reply's `mac` is bound to it. Clients send none. */
|
|
514
|
+
n?: string;
|
|
348
515
|
}
|
|
349
516
|
/** Broker → client: `{"agent-messenger":"broker","id":..,"port":..,"version":..}` */
|
|
350
517
|
interface DiscoveryReply {
|
|
@@ -357,7 +524,25 @@ interface DiscoveryReply {
|
|
|
357
524
|
version: string;
|
|
358
525
|
/** Present (`true`) only when the broker is a local fallback; clients prefer other brokers, fallbacks never relay to each other. */
|
|
359
526
|
fallback?: true;
|
|
527
|
+
/** Present (`true`) only when the broker takes part in the mesh (`AGENT_MESSENGER_MESH=on`). */
|
|
528
|
+
mesh?: true;
|
|
529
|
+
/** Mesh broker only, and only when the probe carried `n`: `meshMac(token, n, id, port)`. */
|
|
530
|
+
mac?: string;
|
|
531
|
+
}
|
|
532
|
+
/** Mesh broker → broadcast, every `AGENT_MESSENGER_MESH_ANNOUNCE_MS`: `{"agent-messenger":"announce",id,port,version,mesh:true,ts,mac}` */
|
|
533
|
+
interface DiscoveryAnnounce {
|
|
534
|
+
[DISCOVERY_KEY]: typeof DISCOVERY_ANNOUNCE_VALUE;
|
|
535
|
+
id: string;
|
|
536
|
+
port: number;
|
|
537
|
+
version: string;
|
|
538
|
+
mesh: true;
|
|
539
|
+
/** Send time (ms since epoch); also the MAC nonce (decimal string). Receivers accept `|now - ts| <= MESH_ANNOUNCE_MAX_SKEW_MS`. */
|
|
540
|
+
ts: number;
|
|
541
|
+
/** `meshMac(token, String(ts), id, port)` */
|
|
542
|
+
mac: string;
|
|
360
543
|
}
|
|
544
|
+
/** Announces older (or newer) than this are ignored. */
|
|
545
|
+
declare const MESH_ANNOUNCE_MAX_SKEW_MS = 60000;
|
|
361
546
|
/** The exact probe object sent by the client. */
|
|
362
547
|
declare const DISCOVERY_PROBE: DiscoveryProbe;
|
|
363
548
|
/** Default probe target when `AGENT_MESSENGER_DISCOVERY_ADDR` is unset (plus per-interface directed broadcast). */
|
|
@@ -390,5 +575,26 @@ interface SessionUserLine {
|
|
|
390
575
|
}
|
|
391
576
|
type SessionSocketLine = SessionAuthLine | SessionUserLine;
|
|
392
577
|
|
|
393
|
-
|
|
394
|
-
|
|
578
|
+
/**
|
|
579
|
+
* Canonical JSON for protocol hashes: object keys in ascending (UTF-16 code unit) order at every depth,
|
|
580
|
+
* no whitespace, otherwise exactly what `JSON.stringify` writes for each value. Pure TypeScript with no
|
|
581
|
+
* Node dependency, so any runtime can import it. The hash itself,
|
|
582
|
+
* `sha256(canonicalJSON({manifest, doc}))` in lower-case hex, is computed by each side with its own
|
|
583
|
+
* sha256 (broker: `node:crypto`).
|
|
584
|
+
*
|
|
585
|
+
* Input is expected to be JSON data (what `JSON.parse` returns). As in `JSON.stringify`, an object member whose
|
|
586
|
+
* value is `undefined` / a function / a symbol is skipped, and such an array element becomes `null`.
|
|
587
|
+
*/
|
|
588
|
+
declare function canonicalJSON(value: unknown): string;
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Mesh membership proof (0.11.0): `hex(HMAC-SHA256(key = token, "am-mesh/1|" + nonce + "|" + id + "|" + port))`
|
|
592
|
+
* cut to 32 hex characters (128 bit). The token itself never goes on the wire. `nonce` is the probe's `n`
|
|
593
|
+
* (reply) or the announce `ts` as a decimal string (announce).
|
|
594
|
+
*/
|
|
595
|
+
declare function meshMac(token: string, nonce: string, id: string, port: number): string;
|
|
596
|
+
/** Constant-time check of a received `mac` against the one computed with our token. */
|
|
597
|
+
declare function meshMacEqual(expected: string, received: unknown): boolean;
|
|
598
|
+
|
|
599
|
+
export { BROKER_POST_ROUTES, CLIENT_STATE_ENV, DEFAULT_BIND, DEFAULT_DISCOVERY_PORT, DEFAULT_DISCOVERY_TIMEOUT_MS, DEFAULT_HTTP_PORT, DISCOVERY_ANNOUNCE_VALUE, DISCOVERY_BROADCAST_ADDR, DISCOVERY_KEY, DISCOVERY_PROBE, DISCOVERY_PROBE_VALUE, DISCOVERY_REPLY_VALUE, DISCOVERY_TARGETS_ENV, ENV, HEALTH_ROUTE, HEARTBEAT_INTERVAL_MS, HEARTBEAT_TIMEOUT_MS, LOCAL_HOSTS, MESH_ANNOUNCE_ENV, MESH_ANNOUNCE_MAX_SKEW_MS, MESH_SYNC_ROUTE, POLL_INTERVAL_MS, PROTOCOL_DOC_MAX_BYTES, PROTOCOL_ERROR_CODES, PROTOCOL_MANIFEST_MAX_BYTES, PROTOCOL_MAX_STORED, PROTOCOL_META_MAX_LENGTH, PROTOCOL_NAME_PATTERN, PROTOCOL_ROUTES, PROTOCOL_TOTAL_MAX_BYTES, RELAY_ROUTE, SESSION_SOCKET_ENV, SESSION_TOKEN_ENV, canonicalJSON, meshMac, meshMacEqual };
|
|
600
|
+
export type { AcknowledgeMessagesRequest, AcknowledgeMessagesResponse, BrokerErrorResponse, BrokerPostRoute, BrokerRequest, BrokerResponse, BrokerRouteMap, DiscoveryAnnounce, DiscoveryProbe, DiscoveryReply, EnvName, GetBufferedMessagesRequest, GetBufferedMessagesResponse, GetProtocolRequest, GetProtocolResponse, HealthResponse, HeartbeatRequest, HeartbeatResponse, ListPeersRequest, ListPeersResponse, MeshSyncRequest, MeshSyncResponse, Message, MessageMeta, MessageMode, OkResult, Peer, PeerScope, PollMessagesRequest, PollMessagesResponse, ProtocolDecl, ProtocolDefinition, ProtocolErrorCode, ProtocolErrorResponse, ProtocolRoute, ProtocolRouteMap, RegisterRequest, RegisterResponse, RelayMessagesRequest, RelayMessagesResponse, RelayedMessage, SendMessageRequest, SendMessageResponse, SessionAuthLine, SessionSocketLine, SessionUserLine, SetNameRequest, SetNameResponse, SetProtocolRequest, SetProtocolResponse, SetSummaryRequest, SetSummaryResponse, StoredProtocol, UnregisterRequest, UnregisterResponse, UnsetProtocolRequest, UnsetProtocolResponse };
|
package/dist/index.d.ts
CHANGED
|
@@ -56,6 +56,37 @@ declare const ENV: {
|
|
|
56
56
|
readonly DELIVERY: "AGENT_MESSENGER_DELIVERY";
|
|
57
57
|
};
|
|
58
58
|
type EnvName = (typeof ENV)[keyof typeof ENV];
|
|
59
|
+
/**
|
|
60
|
+
* Extra POST routes of the protocol registry. Like `RELAY_ROUTE`, not part of `BROKER_POST_ROUTES`
|
|
61
|
+
* (that table mirrors the legacy broker); request / response shapes are `ProtocolRouteMap` in `http.ts`.
|
|
62
|
+
*/
|
|
63
|
+
declare const PROTOCOL_ROUTES: readonly ["/set-protocol", "/unset-protocol", "/get-protocol"];
|
|
64
|
+
type ProtocolRoute = (typeof PROTOCOL_ROUTES)[number];
|
|
65
|
+
/** Max size of `protocol.json` (UTF-8 bytes). */
|
|
66
|
+
declare const PROTOCOL_MANIFEST_MAX_BYTES: number;
|
|
67
|
+
/** Max size of `PROTOCOL.md` (UTF-8 bytes). */
|
|
68
|
+
declare const PROTOCOL_DOC_MAX_BYTES: number;
|
|
69
|
+
/** Max size of manifest + doc together (UTF-8 bytes). */
|
|
70
|
+
declare const PROTOCOL_TOTAL_MAX_BYTES: number;
|
|
71
|
+
/** Max number of `(name, version)` definitions one broker holds; more is `LIMIT`. */
|
|
72
|
+
declare const PROTOCOL_MAX_STORED = 256;
|
|
73
|
+
/** Max length (characters) of each of `meta.protocol` and `meta.version`. */
|
|
74
|
+
declare const PROTOCOL_META_MAX_LENGTH = 128;
|
|
75
|
+
/** Valid protocol `name`. */
|
|
76
|
+
declare const PROTOCOL_NAME_PATTERN: RegExp;
|
|
77
|
+
/**
|
|
78
|
+
* Error `code`s of the protocol feature (design 7.2). `NO_TAG` is not listed: a repo without tags is
|
|
79
|
+
* not an error (`0.0.0+<sha7>`). Raised by the broker: HASH_MISMATCH, PROTOCOL_CONFLICT, LIMIT,
|
|
80
|
+
* PROTOCOL_NOT_FOUND, and TOO_LARGE / INVALID_DEFINITION on re-check. The rest are raised by the client.
|
|
81
|
+
*/
|
|
82
|
+
declare const PROTOCOL_ERROR_CODES: readonly ["REPO_UNREACHABLE", "UNSUPPORTED_REPO", "VERSION_NOT_FOUND", "INVALID_DEFINITION", "VERSION_MISMATCH", "TOO_LARGE", "HASH_MISMATCH", "PROTOCOL_CONFLICT", "LIMIT", "PROTOCOL_NOT_FOUND", "BROKER_UNSUPPORTED", "INVALID_META"];
|
|
83
|
+
type ProtocolErrorCode = (typeof PROTOCOL_ERROR_CODES)[number];
|
|
84
|
+
/** Discovery send targets (`host:port`, comma separated). When set, probes / announces go there instead of broadcast. */
|
|
85
|
+
declare const DISCOVERY_TARGETS_ENV = "AGENT_MESSENGER_DISCOVERY_TARGETS";
|
|
86
|
+
/** Client state file with the saved broker (default `~/.agent-messenger/client.json`). */
|
|
87
|
+
declare const CLIENT_STATE_ENV = "AGENT_MESSENGER_CLIENT_STATE";
|
|
88
|
+
/** Mesh announce interval in ms (default 10000). */
|
|
89
|
+
declare const MESH_ANNOUNCE_ENV = "AGENT_MESSENGER_MESH_ANNOUNCE_MS";
|
|
59
90
|
|
|
60
91
|
/**
|
|
61
92
|
* Broker HTTP API — request / response JSON shapes.
|
|
@@ -72,6 +103,7 @@ type EnvName = (typeof ENV)[keyof typeof ENV];
|
|
|
72
103
|
* - Unknown POST path: `404 {"error":"not found"}`. Handler exception: `500 {"error":<message>}`.
|
|
73
104
|
* - Any other method: `200 text/plain` `agent-messenger broker <version>\n`.
|
|
74
105
|
*/
|
|
106
|
+
|
|
75
107
|
/** A registered session as stored and returned by the broker. */
|
|
76
108
|
interface Peer {
|
|
77
109
|
/** 8-char broker-generated id (`[a-z0-9]`). */
|
|
@@ -95,6 +127,42 @@ interface Peer {
|
|
|
95
127
|
* registered directly. Never returned by `/list-peers`.
|
|
96
128
|
*/
|
|
97
129
|
origin?: string;
|
|
130
|
+
/**
|
|
131
|
+
* Protocols this peer serves (`/set-protocol`, re-sent on `/register` and `/heartbeat`). Hash only; the
|
|
132
|
+
* definition body lives in the broker's protocol store. Absent when none (and from 0.9.x brokers).
|
|
133
|
+
*/
|
|
134
|
+
protocols?: ProtocolDecl[];
|
|
135
|
+
}
|
|
136
|
+
/** A protocol a peer declares: identity (`name` + `version`) and the hash of its definition body. */
|
|
137
|
+
interface ProtocolDecl {
|
|
138
|
+
/** `^[a-z0-9][a-z0-9._-]{0,63}$` (`PROTOCOL_NAME_PATTERN`). */
|
|
139
|
+
name: string;
|
|
140
|
+
/** semver, or `0.0.0+<sha7>` for a repo without tags. */
|
|
141
|
+
version: string;
|
|
142
|
+
/** `sha256(canonicalJSON({manifest, doc}))` as lower-case hex. */
|
|
143
|
+
hash: string;
|
|
144
|
+
}
|
|
145
|
+
/** The definition body a server fetched from its protocol repo. */
|
|
146
|
+
interface ProtocolDefinition {
|
|
147
|
+
/** Parsed `protocol.json`. */
|
|
148
|
+
manifest: object;
|
|
149
|
+
/** `PROTOCOL.md` text; `""` when the repo has none. */
|
|
150
|
+
doc: string;
|
|
151
|
+
/** Normalized repo notation (`github:o/r`, `gitea:<base>/o/r`, `file:<abs path>`). Not part of the hash. */
|
|
152
|
+
source: string;
|
|
153
|
+
/** tag or sha the body was read at (`local` for a local path). Not part of the hash. */
|
|
154
|
+
ref: string;
|
|
155
|
+
}
|
|
156
|
+
/** What the broker keeps per `(name, version)`. */
|
|
157
|
+
interface StoredProtocol extends ProtocolDecl {
|
|
158
|
+
definition: ProtocolDefinition;
|
|
159
|
+
/** ISO 8601 timestamp of the first successful `/set-protocol` for this `(name, version)`. */
|
|
160
|
+
registered_at: string;
|
|
161
|
+
}
|
|
162
|
+
/** Protocol tag of a message: which protocol (and version) the sender spoke. Both fields are required when present. */
|
|
163
|
+
interface MessageMeta {
|
|
164
|
+
protocol: string;
|
|
165
|
+
version: string;
|
|
98
166
|
}
|
|
99
167
|
type MessageMode = "pull" | "push" | "ping";
|
|
100
168
|
/** A message as stored and returned by the broker. */
|
|
@@ -120,6 +188,8 @@ interface Message {
|
|
|
120
188
|
acknowledged: 0 | 1;
|
|
121
189
|
/** Mesh only: `<sender broker id>:<id there>` of a message forwarded by another broker (duplicate guard). */
|
|
122
190
|
mesh_key?: string;
|
|
191
|
+
/** Protocol tag given to `/send-message`; returned by `/poll-messages` and kept across relay / mesh forwarding. */
|
|
192
|
+
meta?: MessageMeta;
|
|
123
193
|
}
|
|
124
194
|
/** `/list-peers` scope filter. Unknown values behave as `"all"`. */
|
|
125
195
|
type PeerScope = "all" | "host" | "directory" | "repo";
|
|
@@ -146,6 +216,8 @@ interface HealthResponse {
|
|
|
146
216
|
peers: number;
|
|
147
217
|
/** Present (`true`) only when the broker was started as a local fallback (`AGENT_MESSENGER_FALLBACK=1`). */
|
|
148
218
|
fallback?: true;
|
|
219
|
+
/** Present (`true`) only when the broker takes part in the mesh (0.11.0). */
|
|
220
|
+
mesh?: true;
|
|
149
221
|
}
|
|
150
222
|
interface RegisterRequest {
|
|
151
223
|
pid: number;
|
|
@@ -155,15 +227,29 @@ interface RegisterRequest {
|
|
|
155
227
|
tty?: string | null;
|
|
156
228
|
summary?: string;
|
|
157
229
|
name?: string;
|
|
230
|
+
/** Protocols to declare right away (hash only; bodies follow via `/set-protocol`). */
|
|
231
|
+
protocols?: ProtocolDecl[];
|
|
158
232
|
}
|
|
159
233
|
interface RegisterResponse {
|
|
160
234
|
id: string;
|
|
161
235
|
}
|
|
162
236
|
interface HeartbeatRequest {
|
|
163
237
|
id: string;
|
|
238
|
+
/** Every protocol the peer currently serves (hash only), sent on each heartbeat. */
|
|
239
|
+
protocols?: ProtocolDecl[];
|
|
164
240
|
}
|
|
165
|
-
/**
|
|
166
|
-
|
|
241
|
+
/**
|
|
242
|
+
* `ok:false` with `"unknown peer (re-register)"` when the broker does not know the id.
|
|
243
|
+
* `resend` lists the `"name@version"` of declared protocols whose body the broker does not hold; the client answers
|
|
244
|
+
* with `/set-protocol`. Absent when nothing is missing (and from 0.9.x brokers).
|
|
245
|
+
*/
|
|
246
|
+
type HeartbeatResponse = {
|
|
247
|
+
ok: true;
|
|
248
|
+
resend?: string[];
|
|
249
|
+
} | {
|
|
250
|
+
ok: false;
|
|
251
|
+
error: string;
|
|
252
|
+
};
|
|
167
253
|
interface SetSummaryRequest {
|
|
168
254
|
id: string;
|
|
169
255
|
summary?: string;
|
|
@@ -184,6 +270,10 @@ interface ListPeersRequest {
|
|
|
184
270
|
git_root?: string | null;
|
|
185
271
|
/** Peer id to omit from the result (the caller itself). */
|
|
186
272
|
exclude_id?: string;
|
|
273
|
+
/** Only peers that declare this protocol (AND with `scope`). */
|
|
274
|
+
protocol?: string;
|
|
275
|
+
/** Only with `protocol`: only peers that declare exactly this version. */
|
|
276
|
+
version?: string;
|
|
187
277
|
}
|
|
188
278
|
type ListPeersResponse = Peer[];
|
|
189
279
|
interface SendMessageRequest {
|
|
@@ -195,6 +285,8 @@ interface SendMessageRequest {
|
|
|
195
285
|
text?: string;
|
|
196
286
|
/** Defaults to `"pull"`. Unknown values are rejected. */
|
|
197
287
|
mode?: MessageMode;
|
|
288
|
+
/** Protocol tag. Both fields must be strings of at most `PROTOCOL_META_MAX_LENGTH` characters. */
|
|
289
|
+
meta?: MessageMeta;
|
|
198
290
|
}
|
|
199
291
|
type SendMessageResponse = {
|
|
200
292
|
ok: true;
|
|
@@ -243,6 +335,7 @@ interface RelayedMessage {
|
|
|
243
335
|
text: string;
|
|
244
336
|
mode?: MessageMode;
|
|
245
337
|
sent_at: string;
|
|
338
|
+
meta?: MessageMeta;
|
|
246
339
|
}
|
|
247
340
|
interface RelayMessagesRequest {
|
|
248
341
|
messages: RelayedMessage[];
|
|
@@ -256,6 +349,72 @@ interface RelayMessagesResponse {
|
|
|
256
349
|
}
|
|
257
350
|
/** Extra POST route served by the TypeScript broker. Not in `BROKER_POST_ROUTES` (that table mirrors the legacy broker). */
|
|
258
351
|
declare const RELAY_ROUTE: "/relay-messages";
|
|
352
|
+
/** `{ok:false}` answer of the protocol routes; `code` is one of `PROTOCOL_ERROR_CODES`. */
|
|
353
|
+
interface ProtocolErrorResponse {
|
|
354
|
+
ok: false;
|
|
355
|
+
error: string;
|
|
356
|
+
code: ProtocolErrorCode;
|
|
357
|
+
/** `PROTOCOL_CONFLICT`: hash the broker already holds for this `(name, version)`. */
|
|
358
|
+
existing_hash?: string;
|
|
359
|
+
/** `PROTOCOL_CONFLICT`: servers (`name@host`) that hold it. */
|
|
360
|
+
servers?: string[];
|
|
361
|
+
/** `PROTOCOL_NOT_FOUND`: versions the broker does hold for the name (may be empty). */
|
|
362
|
+
versions?: string[];
|
|
363
|
+
}
|
|
364
|
+
interface SetProtocolRequest {
|
|
365
|
+
/** Peer id of the server. */
|
|
366
|
+
id: string;
|
|
367
|
+
name: string;
|
|
368
|
+
version: string;
|
|
369
|
+
/** Re-computed by the broker; a different value is `HASH_MISMATCH`. */
|
|
370
|
+
hash: string;
|
|
371
|
+
definition: ProtocolDefinition;
|
|
372
|
+
}
|
|
373
|
+
/** `{ok:false, error}` without `code` only for an unknown peer id. */
|
|
374
|
+
type SetProtocolResponse = {
|
|
375
|
+
ok: true;
|
|
376
|
+
} | ProtocolErrorResponse | {
|
|
377
|
+
ok: false;
|
|
378
|
+
error: string;
|
|
379
|
+
};
|
|
380
|
+
interface UnsetProtocolRequest {
|
|
381
|
+
id: string;
|
|
382
|
+
/** Protocol to drop; all declarations of the peer when omitted. */
|
|
383
|
+
name?: string;
|
|
384
|
+
}
|
|
385
|
+
type UnsetProtocolResponse = {
|
|
386
|
+
ok: true;
|
|
387
|
+
removed: number;
|
|
388
|
+
} | {
|
|
389
|
+
ok: false;
|
|
390
|
+
error: string;
|
|
391
|
+
};
|
|
392
|
+
interface GetProtocolRequest {
|
|
393
|
+
name: string;
|
|
394
|
+
/** Highest version the broker holds when omitted (`0.0.0+sha` counts as lowest). */
|
|
395
|
+
version?: string;
|
|
396
|
+
}
|
|
397
|
+
/** `servers` = number of alive peers (replicas included) that declare the returned protocol. */
|
|
398
|
+
type GetProtocolResponse = {
|
|
399
|
+
ok: true;
|
|
400
|
+
protocol: StoredProtocol;
|
|
401
|
+
servers: number;
|
|
402
|
+
} | ProtocolErrorResponse;
|
|
403
|
+
/** Request / response pair per protocol route. */
|
|
404
|
+
interface ProtocolRouteMap {
|
|
405
|
+
"/set-protocol": {
|
|
406
|
+
request: SetProtocolRequest;
|
|
407
|
+
response: SetProtocolResponse;
|
|
408
|
+
};
|
|
409
|
+
"/unset-protocol": {
|
|
410
|
+
request: UnsetProtocolRequest;
|
|
411
|
+
response: UnsetProtocolResponse;
|
|
412
|
+
};
|
|
413
|
+
"/get-protocol": {
|
|
414
|
+
request: GetProtocolRequest;
|
|
415
|
+
response: GetProtocolResponse;
|
|
416
|
+
};
|
|
417
|
+
}
|
|
259
418
|
/** The only GET route. */
|
|
260
419
|
declare const HEALTH_ROUTE: "/health";
|
|
261
420
|
/** POST routes, in the order of `ROUTES` in `legacy/src/broker.js`. */
|
|
@@ -319,6 +478,8 @@ interface MeshSyncRequest {
|
|
|
319
478
|
peers: Peer[];
|
|
320
479
|
/** Undelivered messages the sender holds for peers that live on the receiver. Ids are the sender's. */
|
|
321
480
|
messages: Message[];
|
|
481
|
+
/** Definitions declared by the sender's direct peers. Absent from 0.9.x brokers. */
|
|
482
|
+
protocols?: StoredProtocol[];
|
|
322
483
|
}
|
|
323
484
|
interface MeshSyncResponse {
|
|
324
485
|
/** Id of the receiving broker. */
|
|
@@ -327,6 +488,8 @@ interface MeshSyncResponse {
|
|
|
327
488
|
peers: Peer[];
|
|
328
489
|
/** Sender-side ids of the messages the receiver took over; the sender drops them. */
|
|
329
490
|
accepted: number[];
|
|
491
|
+
/** Definitions declared by the receiver's direct peers. Absent from 0.9.x brokers. */
|
|
492
|
+
protocols?: StoredProtocol[];
|
|
330
493
|
}
|
|
331
494
|
|
|
332
495
|
/**
|
|
@@ -342,9 +505,13 @@ declare const DISCOVERY_KEY: "agent-messenger";
|
|
|
342
505
|
declare const DISCOVERY_PROBE_VALUE: "probe";
|
|
343
506
|
/** Value of `DISCOVERY_KEY` in a broker reply. */
|
|
344
507
|
declare const DISCOVERY_REPLY_VALUE: "broker";
|
|
508
|
+
/** Value of `DISCOVERY_KEY` in a mesh broker's self-announcement (0.11.0). */
|
|
509
|
+
declare const DISCOVERY_ANNOUNCE_VALUE: "announce";
|
|
345
510
|
/** Client → broadcast: `{"agent-messenger":"probe"}` */
|
|
346
511
|
interface DiscoveryProbe {
|
|
347
512
|
[DISCOVERY_KEY]: typeof DISCOVERY_PROBE_VALUE;
|
|
513
|
+
/** Mesh brokers add a 16 byte random hex nonce; the reply's `mac` is bound to it. Clients send none. */
|
|
514
|
+
n?: string;
|
|
348
515
|
}
|
|
349
516
|
/** Broker → client: `{"agent-messenger":"broker","id":..,"port":..,"version":..}` */
|
|
350
517
|
interface DiscoveryReply {
|
|
@@ -357,7 +524,25 @@ interface DiscoveryReply {
|
|
|
357
524
|
version: string;
|
|
358
525
|
/** Present (`true`) only when the broker is a local fallback; clients prefer other brokers, fallbacks never relay to each other. */
|
|
359
526
|
fallback?: true;
|
|
527
|
+
/** Present (`true`) only when the broker takes part in the mesh (`AGENT_MESSENGER_MESH=on`). */
|
|
528
|
+
mesh?: true;
|
|
529
|
+
/** Mesh broker only, and only when the probe carried `n`: `meshMac(token, n, id, port)`. */
|
|
530
|
+
mac?: string;
|
|
531
|
+
}
|
|
532
|
+
/** Mesh broker → broadcast, every `AGENT_MESSENGER_MESH_ANNOUNCE_MS`: `{"agent-messenger":"announce",id,port,version,mesh:true,ts,mac}` */
|
|
533
|
+
interface DiscoveryAnnounce {
|
|
534
|
+
[DISCOVERY_KEY]: typeof DISCOVERY_ANNOUNCE_VALUE;
|
|
535
|
+
id: string;
|
|
536
|
+
port: number;
|
|
537
|
+
version: string;
|
|
538
|
+
mesh: true;
|
|
539
|
+
/** Send time (ms since epoch); also the MAC nonce (decimal string). Receivers accept `|now - ts| <= MESH_ANNOUNCE_MAX_SKEW_MS`. */
|
|
540
|
+
ts: number;
|
|
541
|
+
/** `meshMac(token, String(ts), id, port)` */
|
|
542
|
+
mac: string;
|
|
360
543
|
}
|
|
544
|
+
/** Announces older (or newer) than this are ignored. */
|
|
545
|
+
declare const MESH_ANNOUNCE_MAX_SKEW_MS = 60000;
|
|
361
546
|
/** The exact probe object sent by the client. */
|
|
362
547
|
declare const DISCOVERY_PROBE: DiscoveryProbe;
|
|
363
548
|
/** Default probe target when `AGENT_MESSENGER_DISCOVERY_ADDR` is unset (plus per-interface directed broadcast). */
|
|
@@ -390,5 +575,26 @@ interface SessionUserLine {
|
|
|
390
575
|
}
|
|
391
576
|
type SessionSocketLine = SessionAuthLine | SessionUserLine;
|
|
392
577
|
|
|
393
|
-
|
|
394
|
-
|
|
578
|
+
/**
|
|
579
|
+
* Canonical JSON for protocol hashes: object keys in ascending (UTF-16 code unit) order at every depth,
|
|
580
|
+
* no whitespace, otherwise exactly what `JSON.stringify` writes for each value. Pure TypeScript with no
|
|
581
|
+
* Node dependency, so any runtime can import it. The hash itself,
|
|
582
|
+
* `sha256(canonicalJSON({manifest, doc}))` in lower-case hex, is computed by each side with its own
|
|
583
|
+
* sha256 (broker: `node:crypto`).
|
|
584
|
+
*
|
|
585
|
+
* Input is expected to be JSON data (what `JSON.parse` returns). As in `JSON.stringify`, an object member whose
|
|
586
|
+
* value is `undefined` / a function / a symbol is skipped, and such an array element becomes `null`.
|
|
587
|
+
*/
|
|
588
|
+
declare function canonicalJSON(value: unknown): string;
|
|
589
|
+
|
|
590
|
+
/**
|
|
591
|
+
* Mesh membership proof (0.11.0): `hex(HMAC-SHA256(key = token, "am-mesh/1|" + nonce + "|" + id + "|" + port))`
|
|
592
|
+
* cut to 32 hex characters (128 bit). The token itself never goes on the wire. `nonce` is the probe's `n`
|
|
593
|
+
* (reply) or the announce `ts` as a decimal string (announce).
|
|
594
|
+
*/
|
|
595
|
+
declare function meshMac(token: string, nonce: string, id: string, port: number): string;
|
|
596
|
+
/** Constant-time check of a received `mac` against the one computed with our token. */
|
|
597
|
+
declare function meshMacEqual(expected: string, received: unknown): boolean;
|
|
598
|
+
|
|
599
|
+
export { BROKER_POST_ROUTES, CLIENT_STATE_ENV, DEFAULT_BIND, DEFAULT_DISCOVERY_PORT, DEFAULT_DISCOVERY_TIMEOUT_MS, DEFAULT_HTTP_PORT, DISCOVERY_ANNOUNCE_VALUE, DISCOVERY_BROADCAST_ADDR, DISCOVERY_KEY, DISCOVERY_PROBE, DISCOVERY_PROBE_VALUE, DISCOVERY_REPLY_VALUE, DISCOVERY_TARGETS_ENV, ENV, HEALTH_ROUTE, HEARTBEAT_INTERVAL_MS, HEARTBEAT_TIMEOUT_MS, LOCAL_HOSTS, MESH_ANNOUNCE_ENV, MESH_ANNOUNCE_MAX_SKEW_MS, MESH_SYNC_ROUTE, POLL_INTERVAL_MS, PROTOCOL_DOC_MAX_BYTES, PROTOCOL_ERROR_CODES, PROTOCOL_MANIFEST_MAX_BYTES, PROTOCOL_MAX_STORED, PROTOCOL_META_MAX_LENGTH, PROTOCOL_NAME_PATTERN, PROTOCOL_ROUTES, PROTOCOL_TOTAL_MAX_BYTES, RELAY_ROUTE, SESSION_SOCKET_ENV, SESSION_TOKEN_ENV, canonicalJSON, meshMac, meshMacEqual };
|
|
600
|
+
export type { AcknowledgeMessagesRequest, AcknowledgeMessagesResponse, BrokerErrorResponse, BrokerPostRoute, BrokerRequest, BrokerResponse, BrokerRouteMap, DiscoveryAnnounce, DiscoveryProbe, DiscoveryReply, EnvName, GetBufferedMessagesRequest, GetBufferedMessagesResponse, GetProtocolRequest, GetProtocolResponse, HealthResponse, HeartbeatRequest, HeartbeatResponse, ListPeersRequest, ListPeersResponse, MeshSyncRequest, MeshSyncResponse, Message, MessageMeta, MessageMode, OkResult, Peer, PeerScope, PollMessagesRequest, PollMessagesResponse, ProtocolDecl, ProtocolDefinition, ProtocolErrorCode, ProtocolErrorResponse, ProtocolRoute, ProtocolRouteMap, RegisterRequest, RegisterResponse, RelayMessagesRequest, RelayMessagesResponse, RelayedMessage, SendMessageRequest, SendMessageResponse, SessionAuthLine, SessionSocketLine, SessionUserLine, SetNameRequest, SetNameResponse, SetProtocolRequest, SetProtocolResponse, SetSummaryRequest, SetSummaryResponse, StoredProtocol, UnregisterRequest, UnregisterResponse, UnsetProtocolRequest, UnsetProtocolResponse };
|
package/dist/index.mjs
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { createHmac, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
|
|
1
3
|
const DEFAULT_HTTP_PORT = 7901;
|
|
2
4
|
const DEFAULT_BIND = "0.0.0.0";
|
|
3
5
|
const DEFAULT_DISCOVERY_PORT = 7902;
|
|
@@ -36,6 +38,30 @@ const ENV = {
|
|
|
36
38
|
/** Inbound delivery mode: `"auto"` (default) / `"socket"` / `"channel"`. */
|
|
37
39
|
DELIVERY: "AGENT_MESSENGER_DELIVERY"
|
|
38
40
|
};
|
|
41
|
+
const PROTOCOL_ROUTES = ["/set-protocol", "/unset-protocol", "/get-protocol"];
|
|
42
|
+
const PROTOCOL_MANIFEST_MAX_BYTES = 64 * 1024;
|
|
43
|
+
const PROTOCOL_DOC_MAX_BYTES = 64 * 1024;
|
|
44
|
+
const PROTOCOL_TOTAL_MAX_BYTES = 128 * 1024;
|
|
45
|
+
const PROTOCOL_MAX_STORED = 256;
|
|
46
|
+
const PROTOCOL_META_MAX_LENGTH = 128;
|
|
47
|
+
const PROTOCOL_NAME_PATTERN = /^[a-z0-9][a-z0-9._-]{0,63}$/;
|
|
48
|
+
const PROTOCOL_ERROR_CODES = [
|
|
49
|
+
"REPO_UNREACHABLE",
|
|
50
|
+
"UNSUPPORTED_REPO",
|
|
51
|
+
"VERSION_NOT_FOUND",
|
|
52
|
+
"INVALID_DEFINITION",
|
|
53
|
+
"VERSION_MISMATCH",
|
|
54
|
+
"TOO_LARGE",
|
|
55
|
+
"HASH_MISMATCH",
|
|
56
|
+
"PROTOCOL_CONFLICT",
|
|
57
|
+
"LIMIT",
|
|
58
|
+
"PROTOCOL_NOT_FOUND",
|
|
59
|
+
"BROKER_UNSUPPORTED",
|
|
60
|
+
"INVALID_META"
|
|
61
|
+
];
|
|
62
|
+
const DISCOVERY_TARGETS_ENV = "AGENT_MESSENGER_DISCOVERY_TARGETS";
|
|
63
|
+
const CLIENT_STATE_ENV = "AGENT_MESSENGER_CLIENT_STATE";
|
|
64
|
+
const MESH_ANNOUNCE_ENV = "AGENT_MESSENGER_MESH_ANNOUNCE_MS";
|
|
39
65
|
|
|
40
66
|
const RELAY_ROUTE = "/relay-messages";
|
|
41
67
|
const HEALTH_ROUTE = "/health";
|
|
@@ -56,10 +82,39 @@ const MESH_SYNC_ROUTE = "/mesh/sync";
|
|
|
56
82
|
const DISCOVERY_KEY = "agent-messenger";
|
|
57
83
|
const DISCOVERY_PROBE_VALUE = "probe";
|
|
58
84
|
const DISCOVERY_REPLY_VALUE = "broker";
|
|
85
|
+
const DISCOVERY_ANNOUNCE_VALUE = "announce";
|
|
86
|
+
const MESH_ANNOUNCE_MAX_SKEW_MS = 6e4;
|
|
59
87
|
const DISCOVERY_PROBE = { [DISCOVERY_KEY]: DISCOVERY_PROBE_VALUE };
|
|
60
88
|
const DISCOVERY_BROADCAST_ADDR = "255.255.255.255";
|
|
61
89
|
|
|
62
90
|
const SESSION_SOCKET_ENV = "CLAUDE_CODE_MESSAGING_SOCKET";
|
|
63
91
|
const SESSION_TOKEN_ENV = "CLAUDE_CODE_MESSAGING_TOKEN";
|
|
64
92
|
|
|
65
|
-
|
|
93
|
+
function canonicalJSON(value) {
|
|
94
|
+
if (value === null || typeof value !== "object") {
|
|
95
|
+
return JSON.stringify(value) ?? "null";
|
|
96
|
+
}
|
|
97
|
+
if (Array.isArray(value)) {
|
|
98
|
+
return `[${value.map((v) => canonicalJSON(v)).join(",")}]`;
|
|
99
|
+
}
|
|
100
|
+
const obj = value;
|
|
101
|
+
const parts = [];
|
|
102
|
+
for (const k of Object.keys(obj).sort()) {
|
|
103
|
+
const v = obj[k];
|
|
104
|
+
if (v === void 0 || typeof v === "function" || typeof v === "symbol") continue;
|
|
105
|
+
parts.push(`${JSON.stringify(k)}:${canonicalJSON(v)}`);
|
|
106
|
+
}
|
|
107
|
+
return `{${parts.join(",")}}`;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function meshMac(token, nonce, id, port) {
|
|
111
|
+
return createHmac("sha256", token).update(`am-mesh/1|${nonce}|${id}|${port}`).digest("hex").slice(0, 32);
|
|
112
|
+
}
|
|
113
|
+
function meshMacEqual(expected, received) {
|
|
114
|
+
if (typeof received !== "string") return false;
|
|
115
|
+
const a = Buffer.from(expected);
|
|
116
|
+
const b = Buffer.from(received);
|
|
117
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export { BROKER_POST_ROUTES, CLIENT_STATE_ENV, DEFAULT_BIND, DEFAULT_DISCOVERY_PORT, DEFAULT_DISCOVERY_TIMEOUT_MS, DEFAULT_HTTP_PORT, DISCOVERY_ANNOUNCE_VALUE, DISCOVERY_BROADCAST_ADDR, DISCOVERY_KEY, DISCOVERY_PROBE, DISCOVERY_PROBE_VALUE, DISCOVERY_REPLY_VALUE, DISCOVERY_TARGETS_ENV, ENV, HEALTH_ROUTE, HEARTBEAT_INTERVAL_MS, HEARTBEAT_TIMEOUT_MS, LOCAL_HOSTS, MESH_ANNOUNCE_ENV, MESH_ANNOUNCE_MAX_SKEW_MS, MESH_SYNC_ROUTE, POLL_INTERVAL_MS, PROTOCOL_DOC_MAX_BYTES, PROTOCOL_ERROR_CODES, PROTOCOL_MANIFEST_MAX_BYTES, PROTOCOL_MAX_STORED, PROTOCOL_META_MAX_LENGTH, PROTOCOL_NAME_PATTERN, PROTOCOL_ROUTES, PROTOCOL_TOTAL_MAX_BYTES, RELAY_ROUTE, SESSION_SOCKET_ENV, SESSION_TOKEN_ENV, canonicalJSON, meshMac, meshMacEqual };
|
package/package.json
CHANGED