@embassys/ambassador 0.0.0 → 0.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (85) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +69 -2
  3. package/dist/agent-capabilities.d.ts +35 -0
  4. package/dist/agent-capabilities.js +221 -0
  5. package/dist/agent-capabilities.js.map +1 -0
  6. package/dist/ambassador-options.d.ts +6 -0
  7. package/dist/ambassador-options.js +13 -0
  8. package/dist/ambassador-options.js.map +1 -0
  9. package/dist/central-credential.d.ts +41 -0
  10. package/dist/central-credential.js +355 -0
  11. package/dist/central-credential.js.map +1 -0
  12. package/dist/central-enrollment.d.ts +31 -0
  13. package/dist/central-enrollment.js +278 -0
  14. package/dist/central-enrollment.js.map +1 -0
  15. package/dist/central-json.d.ts +8 -0
  16. package/dist/central-json.js +259 -0
  17. package/dist/central-json.js.map +1 -0
  18. package/dist/central-protected-transport.d.ts +21 -0
  19. package/dist/central-protected-transport.js +217 -0
  20. package/dist/central-protected-transport.js.map +1 -0
  21. package/dist/central-rest.d.ts +50 -0
  22. package/dist/central-rest.js +401 -0
  23. package/dist/central-rest.js.map +1 -0
  24. package/dist/cli.d.ts +26 -0
  25. package/dist/cli.js +129 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/credential-store.d.ts +18 -0
  28. package/dist/credential-store.js +617 -0
  29. package/dist/credential-store.js.map +1 -0
  30. package/dist/delivery-profile.d.ts +43 -0
  31. package/dist/delivery-profile.js +253 -0
  32. package/dist/delivery-profile.js.map +1 -0
  33. package/dist/direct-delivery.d.ts +37 -0
  34. package/dist/direct-delivery.js +312 -0
  35. package/dist/direct-delivery.js.map +1 -0
  36. package/dist/dpop.d.ts +28 -0
  37. package/dist/dpop.js +119 -0
  38. package/dist/dpop.js.map +1 -0
  39. package/dist/errors.d.ts +5 -0
  40. package/dist/errors.js +11 -0
  41. package/dist/errors.js.map +1 -0
  42. package/dist/gateway-application.d.ts +32 -0
  43. package/dist/gateway-application.js +255 -0
  44. package/dist/gateway-application.js.map +1 -0
  45. package/dist/gateway-paths.d.ts +11 -0
  46. package/dist/gateway-paths.js +29 -0
  47. package/dist/gateway-paths.js.map +1 -0
  48. package/dist/guided-registration.d.ts +23 -0
  49. package/dist/guided-registration.js +117 -0
  50. package/dist/guided-registration.js.map +1 -0
  51. package/dist/identity.d.ts +20 -0
  52. package/dist/identity.js +54 -0
  53. package/dist/identity.js.map +1 -0
  54. package/dist/local-mcp.d.ts +28 -0
  55. package/dist/local-mcp.js +410 -0
  56. package/dist/local-mcp.js.map +1 -0
  57. package/dist/local-tool-result.d.ts +4 -0
  58. package/dist/local-tool-result.js +17 -0
  59. package/dist/local-tool-result.js.map +1 -0
  60. package/dist/mcp-contract.d.ts +10 -0
  61. package/dist/mcp-contract.js +63 -0
  62. package/dist/mcp-contract.js.map +1 -0
  63. package/dist/notification-journal.d.ts +24 -0
  64. package/dist/notification-journal.js +194 -0
  65. package/dist/notification-journal.js.map +1 -0
  66. package/dist/notification-relay.d.ts +31 -0
  67. package/dist/notification-relay.js +203 -0
  68. package/dist/notification-relay.js.map +1 -0
  69. package/dist/process-lock.d.ts +8 -0
  70. package/dist/process-lock.js +122 -0
  71. package/dist/process-lock.js.map +1 -0
  72. package/dist/sqlite-artifact.d.ts +7 -0
  73. package/dist/sqlite-artifact.js +121 -0
  74. package/dist/sqlite-artifact.js.map +1 -0
  75. package/dist/webhook-delivery.d.ts +23 -0
  76. package/dist/webhook-delivery.js +122 -0
  77. package/dist/webhook-delivery.js.map +1 -0
  78. package/docs/getting-started-claude.md +33 -0
  79. package/docs/getting-started-codex.md +36 -0
  80. package/docs/getting-started-gemini.md +31 -0
  81. package/docs/getting-started-hermes.md +47 -0
  82. package/docs/getting-started-openclaw.md +48 -0
  83. package/docs/live-qualification.md +174 -0
  84. package/package.json +48 -7
  85. package/index.js +0 -1
@@ -0,0 +1,355 @@
1
+ import { createHash, createPrivateKey, createPublicKey, } from "node:crypto";
2
+ import { TextDecoder } from "node:util";
3
+ const ACCESS_TOKEN_MAX_BYTES = 4_096;
4
+ const PRIVATE_KEY_MAX_CHARACTERS = 1_024;
5
+ const CREDENTIAL_MAX_BYTES = 8_192;
6
+ const BASE64URL = /^[A-Za-z0-9_-]+$/u;
7
+ const ASCII_TOKEN = /^[\x21-\x7e]+$/u;
8
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/u;
9
+ const RECORD_KEYS = ["access_token", "credential_format", "dpop_private_key_pkcs8"];
10
+ export class CentralCredentialError extends Error {
11
+ constructor() {
12
+ super("The central credential is invalid");
13
+ this.name = "CentralCredentialError";
14
+ }
15
+ }
16
+ function invalid() {
17
+ throw new CentralCredentialError();
18
+ }
19
+ function isRecord(value) {
20
+ return value !== null && typeof value === "object" && !Array.isArray(value);
21
+ }
22
+ class StrictJsonParser {
23
+ text;
24
+ #index = 0;
25
+ #members = 0;
26
+ constructor(text) {
27
+ this.text = text;
28
+ }
29
+ parse() {
30
+ const result = this.#value(0);
31
+ this.#whitespace();
32
+ if (this.#index !== this.text.length)
33
+ invalid();
34
+ return result;
35
+ }
36
+ #value(depth) {
37
+ if (depth > 16)
38
+ invalid();
39
+ this.#whitespace();
40
+ const character = this.text[this.#index];
41
+ if (character === "{")
42
+ return this.#object(depth + 1);
43
+ if (character === "[")
44
+ return this.#array(depth + 1);
45
+ if (character === '"')
46
+ return this.#string();
47
+ if (this.text.startsWith("true", this.#index)) {
48
+ this.#index += 4;
49
+ return true;
50
+ }
51
+ if (this.text.startsWith("false", this.#index)) {
52
+ this.#index += 5;
53
+ return false;
54
+ }
55
+ if (this.text.startsWith("null", this.#index)) {
56
+ this.#index += 4;
57
+ return null;
58
+ }
59
+ return this.#number();
60
+ }
61
+ #object(depth) {
62
+ this.#index += 1;
63
+ this.#whitespace();
64
+ const result = {};
65
+ const names = new Set();
66
+ if (this.text[this.#index] === "}") {
67
+ this.#index += 1;
68
+ return result;
69
+ }
70
+ while (true) {
71
+ if (this.text[this.#index] !== '"')
72
+ invalid();
73
+ const name = this.#string();
74
+ if (names.has(name))
75
+ invalid();
76
+ names.add(name);
77
+ this.#members += 1;
78
+ if (this.#members > 128)
79
+ invalid();
80
+ this.#whitespace();
81
+ if (this.text[this.#index] !== ":")
82
+ invalid();
83
+ this.#index += 1;
84
+ result[name] = this.#value(depth);
85
+ this.#whitespace();
86
+ const separator = this.text[this.#index];
87
+ if (separator === "}") {
88
+ this.#index += 1;
89
+ return result;
90
+ }
91
+ if (separator !== ",")
92
+ invalid();
93
+ this.#index += 1;
94
+ this.#whitespace();
95
+ }
96
+ }
97
+ #array(depth) {
98
+ this.#index += 1;
99
+ this.#whitespace();
100
+ const result = [];
101
+ if (this.text[this.#index] === "]") {
102
+ this.#index += 1;
103
+ return result;
104
+ }
105
+ while (true) {
106
+ result.push(this.#value(depth));
107
+ if (result.length > 128)
108
+ invalid();
109
+ this.#whitespace();
110
+ const separator = this.text[this.#index];
111
+ if (separator === "]") {
112
+ this.#index += 1;
113
+ return result;
114
+ }
115
+ if (separator !== ",")
116
+ invalid();
117
+ this.#index += 1;
118
+ }
119
+ }
120
+ #string() {
121
+ const start = this.#index;
122
+ this.#index += 1;
123
+ let escaped = false;
124
+ while (this.#index < this.text.length) {
125
+ const character = this.text[this.#index];
126
+ this.#index += 1;
127
+ if (escaped) {
128
+ escaped = false;
129
+ continue;
130
+ }
131
+ if (character === "\\") {
132
+ escaped = true;
133
+ continue;
134
+ }
135
+ if (character === '"') {
136
+ let value;
137
+ try {
138
+ value = JSON.parse(this.text.slice(start, this.#index));
139
+ }
140
+ catch {
141
+ invalid();
142
+ }
143
+ if (typeof value !== "string" || hasLoneSurrogate(value))
144
+ invalid();
145
+ return value;
146
+ }
147
+ if (character !== undefined && character.charCodeAt(0) < 0x20)
148
+ invalid();
149
+ }
150
+ return invalid();
151
+ }
152
+ #number() {
153
+ const match = /-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:[eE][+-]?[0-9]+)?/uy;
154
+ match.lastIndex = this.#index;
155
+ const parsed = match.exec(this.text);
156
+ if (parsed === null)
157
+ invalid();
158
+ this.#index = match.lastIndex;
159
+ const value = Number(parsed[0]);
160
+ if (!Number.isFinite(value))
161
+ invalid();
162
+ return value;
163
+ }
164
+ #whitespace() {
165
+ while ([9, 10, 13, 32].includes(this.text.charCodeAt(this.#index)))
166
+ this.#index += 1;
167
+ }
168
+ }
169
+ function hasLoneSurrogate(value) {
170
+ for (let index = 0; index < value.length; index += 1) {
171
+ const code = value.charCodeAt(index);
172
+ if (code >= 0xd800 && code <= 0xdbff) {
173
+ const next = value.charCodeAt(index + 1);
174
+ if (next < 0xdc00 || next > 0xdfff)
175
+ return true;
176
+ index += 1;
177
+ }
178
+ else if (code >= 0xdc00 && code <= 0xdfff)
179
+ return true;
180
+ }
181
+ return false;
182
+ }
183
+ function strictJson(text) {
184
+ return new StrictJsonParser(text).parse();
185
+ }
186
+ function decodeBase64url(value, maximumCharacters) {
187
+ if (typeof value !== "string" ||
188
+ value.length === 0 ||
189
+ (maximumCharacters !== undefined && value.length > maximumCharacters) ||
190
+ !BASE64URL.test(value)) {
191
+ invalid();
192
+ }
193
+ const decoded = Buffer.from(value, "base64url");
194
+ if (decoded.toString("base64url") !== value)
195
+ invalid();
196
+ return decoded;
197
+ }
198
+ function decodeJwtObject(segment) {
199
+ const bytes = decodeBase64url(segment, 6_000);
200
+ let text;
201
+ try {
202
+ text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
203
+ }
204
+ catch {
205
+ return invalid();
206
+ }
207
+ const value = strictJson(text);
208
+ if (!isRecord(value))
209
+ invalid();
210
+ return value;
211
+ }
212
+ export function exactCentralPublicJwk(value) {
213
+ if (!isRecord(value))
214
+ invalid();
215
+ const keys = Object.keys(value).sort();
216
+ if (keys.length !== 4 ||
217
+ !["crv", "kty", "x", "y"].every((name, index) => keys[index] === name) ||
218
+ value.kty !== "EC" ||
219
+ value.crv !== "P-256" ||
220
+ typeof value.x !== "string" ||
221
+ typeof value.y !== "string" ||
222
+ decodeBase64url(value.x).byteLength !== 32 ||
223
+ decodeBase64url(value.y).byteLength !== 32) {
224
+ invalid();
225
+ }
226
+ return { kty: "EC", crv: "P-256", x: value.x, y: value.y };
227
+ }
228
+ export function centralJwkThumbprint(jwk) {
229
+ const exact = exactCentralPublicJwk(jwk);
230
+ return createHash("sha256")
231
+ .update(JSON.stringify({ crv: exact.crv, kty: exact.kty, x: exact.x, y: exact.y }), "utf8")
232
+ .digest("base64url");
233
+ }
234
+ function importPrivateKey(value) {
235
+ const bytes = decodeBase64url(value, PRIVATE_KEY_MAX_CHARACTERS);
236
+ let privateKey;
237
+ try {
238
+ privateKey = createPrivateKey({ key: bytes, format: "der", type: "pkcs8" });
239
+ }
240
+ catch {
241
+ return invalid();
242
+ }
243
+ if (privateKey.asymmetricKeyType !== "ec" ||
244
+ privateKey.asymmetricKeyDetails?.namedCurve !== "prime256v1") {
245
+ invalid();
246
+ }
247
+ return privateKey;
248
+ }
249
+ function publicJwkFromPrivateKey(privateKey) {
250
+ let exported;
251
+ try {
252
+ exported = createPublicKey(privateKey).export({ format: "jwk" });
253
+ }
254
+ catch {
255
+ return invalid();
256
+ }
257
+ return exactCentralPublicJwk(exported);
258
+ }
259
+ function parseToken(accessToken, keyThumbprint, nowSeconds) {
260
+ if (!ASCII_TOKEN.test(accessToken) ||
261
+ Buffer.byteLength(accessToken, "ascii") > ACCESS_TOKEN_MAX_BYTES) {
262
+ invalid();
263
+ }
264
+ const parts = accessToken.split(".");
265
+ if (parts.length !== 3 || parts.some((part) => part.length === 0))
266
+ invalid();
267
+ const header = decodeJwtObject(parts[0]);
268
+ if (header.alg !== "HS256" || (header.typ !== undefined && header.typ !== "JWT"))
269
+ invalid();
270
+ const payload = decodeJwtObject(parts[1]);
271
+ if (typeof payload.sub !== "string" ||
272
+ payload.sub.length < 1 ||
273
+ payload.sub.length > 256 ||
274
+ typeof payload.email !== "string" ||
275
+ !EMAIL.test(payload.email) ||
276
+ !Number.isSafeInteger(payload.iat) ||
277
+ !Number.isSafeInteger(payload.exp) ||
278
+ !isRecord(payload.cnf) ||
279
+ typeof payload.cnf.jkt !== "string" ||
280
+ !BASE64URL.test(payload.cnf.jkt) ||
281
+ payload.cnf.jkt !== keyThumbprint) {
282
+ invalid();
283
+ }
284
+ const issuedAt = payload.iat;
285
+ const expiresAt = payload.exp;
286
+ const now = Math.floor(nowSeconds());
287
+ if (!Number.isSafeInteger(now) ||
288
+ now < 0 ||
289
+ issuedAt < 0 ||
290
+ expiresAt <= issuedAt ||
291
+ expiresAt <= now) {
292
+ invalid();
293
+ }
294
+ return {
295
+ subject: payload.sub,
296
+ email: payload.email,
297
+ issuedAt,
298
+ expiresAt,
299
+ keyThumbprint,
300
+ };
301
+ }
302
+ function recordFromUnknown(value) {
303
+ if (!isRecord(value))
304
+ invalid();
305
+ const keys = Object.keys(value).sort();
306
+ if (keys.length !== RECORD_KEYS.length ||
307
+ !RECORD_KEYS.every((name, index) => keys[index] === name) ||
308
+ value.credential_format !== 1 ||
309
+ typeof value.access_token !== "string" ||
310
+ typeof value.dpop_private_key_pkcs8 !== "string") {
311
+ invalid();
312
+ }
313
+ return {
314
+ credential_format: 1,
315
+ access_token: value.access_token,
316
+ dpop_private_key_pkcs8: value.dpop_private_key_pkcs8,
317
+ };
318
+ }
319
+ export function serializeCentralCredential(record) {
320
+ const exact = recordFromUnknown(record);
321
+ const serialized = JSON.stringify(exact);
322
+ if (Buffer.byteLength(serialized, "utf8") > CREDENTIAL_MAX_BYTES)
323
+ invalid();
324
+ return serialized;
325
+ }
326
+ export function parseCentralCredential(value, nowSeconds = () => Date.now() / 1_000) {
327
+ let parsed = value;
328
+ if (typeof value === "string") {
329
+ if (Buffer.byteLength(value, "utf8") > CREDENTIAL_MAX_BYTES)
330
+ invalid();
331
+ parsed = strictJson(value);
332
+ }
333
+ const record = recordFromUnknown(parsed);
334
+ const privateKey = importPrivateKey(record.dpop_private_key_pkcs8);
335
+ const publicJwk = publicJwkFromPrivateKey(privateKey);
336
+ const keyThumbprint = centralJwkThumbprint(publicJwk);
337
+ const token = parseToken(record.access_token, keyThumbprint, nowSeconds);
338
+ const serialized = serializeCentralCredential(record);
339
+ return { record, serialized, privateKey, publicJwk, keyThumbprint, token };
340
+ }
341
+ export function createCentralCredentialRecord(accessToken, key) {
342
+ const record = {
343
+ credential_format: 1,
344
+ access_token: accessToken,
345
+ dpop_private_key_pkcs8: key.privateKeyPkcs8,
346
+ };
347
+ const loaded = parseCentralCredential(record, () => {
348
+ const payload = decodeJwtObject(accessToken.split(".")[1] ?? "");
349
+ return typeof payload.iat === "number" ? payload.iat : 0;
350
+ });
351
+ if (loaded.keyThumbprint !== key.thumbprint)
352
+ invalid();
353
+ return record;
354
+ }
355
+ //# sourceMappingURL=central-credential.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"central-credential.js","sourceRoot":"","sources":["../src/central-credential.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EACV,gBAAgB,EAChB,eAAe,GAGhB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AACrC,MAAM,0BAA0B,GAAG,KAAK,CAAC;AACzC,MAAM,oBAAoB,GAAG,KAAK,CAAC;AACnC,MAAM,SAAS,GAAG,mBAAmB,CAAC;AACtC,MAAM,WAAW,GAAG,iBAAiB,CAAC;AACtC,MAAM,KAAK,GAAG,6BAA6B,CAAC;AAC5C,MAAM,WAAW,GAAG,CAAC,cAAc,EAAE,mBAAmB,EAAE,wBAAwB,CAAU,CAAC;AAuC7F,MAAM,OAAO,sBAAuB,SAAQ,KAAK;IAC/C;QACE,KAAK,CAAC,mCAAmC,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,wBAAwB,CAAC;IACvC,CAAC;CACF;AAED,SAAS,OAAO;IACd,MAAM,IAAI,sBAAsB,EAAE,CAAC;AACrC,CAAC;AAED,SAAS,QAAQ,CAAC,KAAc;IAC9B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;AAC9E,CAAC;AAED,MAAM,gBAAgB;IAIS,IAAI;IAHjC,MAAM,GAAG,CAAC,CAAC;IACX,QAAQ,GAAG,CAAC,CAAC;IAEb,YAA6B,IAAY;oBAAZ,IAAI;IAAW,CAAC;IAE7C,KAAK;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,IAAI,CAAC,MAAM;YAAE,OAAO,EAAE,CAAC;QAChD,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,IAAI,KAAK,GAAG,EAAE;YAAE,OAAO,EAAE,CAAC;QAC1B,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,IAAI,SAAS,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACtD,IAAI,SAAS,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QACrD,IAAI,SAAS,KAAK,GAAG;YAAE,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;QAC7C,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC/C,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;YAC9C,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,KAAa;QACnB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;QAChC,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,EAAE,CAAC;YACZ,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG;gBAAE,OAAO,EAAE,CAAC;YAC9C,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YAC5B,IAAI,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC;gBAAE,OAAO,EAAE,CAAC;YAC/B,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAChB,IAAI,CAAC,QAAQ,IAAI,CAAC,CAAC;YACnB,IAAI,IAAI,CAAC,QAAQ,GAAG,GAAG;gBAAE,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG;gBAAE,OAAO,EAAE,CAAC;YAC9C,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,MAAM,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YAClC,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBACtB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;gBACjB,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,IAAI,SAAS,KAAK,GAAG;gBAAE,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,IAAI,CAAC,WAAW,EAAE,CAAC;QACrB,CAAC;IACH,CAAC;IAED,MAAM,CAAC,KAAa;QAClB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QACjB,IAAI,CAAC,WAAW,EAAE,CAAC;QACnB,MAAM,MAAM,GAAc,EAAE,CAAC;QAC7B,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,EAAE,CAAC;YACnC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,OAAO,MAAM,CAAC;QAChB,CAAC;QACD,OAAO,IAAI,EAAE,CAAC;YACZ,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAChC,IAAI,MAAM,CAAC,MAAM,GAAG,GAAG;gBAAE,OAAO,EAAE,CAAC;YACnC,IAAI,CAAC,WAAW,EAAE,CAAC;YACnB,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBACtB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;gBACjB,OAAO,MAAM,CAAC;YAChB,CAAC;YACD,IAAI,SAAS,KAAK,GAAG;gBAAE,OAAO,EAAE,CAAC;YACjC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QACnB,CAAC;IACH,CAAC;IAED,OAAO;QACL,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC;QAC1B,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;QACjB,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,OAAO,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACtC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACzC,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;YACjB,IAAI,OAAO,EAAE,CAAC;gBACZ,OAAO,GAAG,KAAK,CAAC;gBAChB,SAAS;YACX,CAAC;YACD,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;gBACvB,OAAO,GAAG,IAAI,CAAC;gBACf,SAAS;YACX,CAAC;YACD,IAAI,SAAS,KAAK,GAAG,EAAE,CAAC;gBACtB,IAAI,KAAc,CAAC;gBACnB,IAAI,CAAC;oBACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;gBAC1D,CAAC;gBAAC,MAAM,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;gBACD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,gBAAgB,CAAC,KAAK,CAAC;oBAAE,OAAO,EAAE,CAAC;gBACpE,OAAO,KAAK,CAAC;YACf,CAAC;YACD,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,IAAI;gBAAE,OAAO,EAAE,CAAC;QAC3E,CAAC;QACD,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IAED,OAAO;QACL,MAAM,KAAK,GAAG,wDAAwD,CAAC;QACvE,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC;QAC9B,MAAM,MAAM,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,MAAM,KAAK,IAAI;YAAE,OAAO,EAAE,CAAC;QAC/B,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,SAAS,CAAC;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QAChC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACvC,OAAO,KAAK,CAAC;IACf,CAAC;IAED,WAAW;QACT,OAAO,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YAAE,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IACvF,CAAC;CACF;AAED,SAAS,gBAAgB,CAAC,KAAa;IACrC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;QACrC,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;YACrC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;YACzC,IAAI,IAAI,GAAG,MAAM,IAAI,IAAI,GAAG,MAAM;gBAAE,OAAO,IAAI,CAAC;YAChD,KAAK,IAAI,CAAC,CAAC;QACb,CAAC;aAAM,IAAI,IAAI,IAAI,MAAM,IAAI,IAAI,IAAI,MAAM;YAAE,OAAO,IAAI,CAAC;IAC3D,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,UAAU,CAAC,IAAY;IAC9B,OAAO,IAAI,gBAAgB,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;AAC5C,CAAC;AAED,SAAS,eAAe,CAAC,KAAc,EAAE,iBAA0B;IACjE,IACE,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,MAAM,KAAK,CAAC;QAClB,CAAC,iBAAiB,KAAK,SAAS,IAAI,KAAK,CAAC,MAAM,GAAG,iBAAiB,CAAC;QACrE,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,EACtB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC;IAChD,IAAI,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,KAAK,KAAK;QAAE,OAAO,EAAE,CAAC;IACvD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,eAAe,CAAC,OAAe;IACtC,MAAM,KAAK,GAAG,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IAC9C,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,WAAW,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACjE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IACD,MAAM,KAAK,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC;IAC/B,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAc;IAClD,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,IACE,IAAI,CAAC,MAAM,KAAK,CAAC;QACjB,CAAC,CAAC,KAAK,EAAE,KAAK,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;QACtE,KAAK,CAAC,GAAG,KAAK,IAAI;QAClB,KAAK,CAAC,GAAG,KAAK,OAAO;QACrB,OAAO,KAAK,CAAC,CAAC,KAAK,QAAQ;QAC3B,OAAO,KAAK,CAAC,CAAC,KAAK,QAAQ;QAC3B,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE;QAC1C,eAAe,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,EAC1C,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC;AAC7D,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,GAAqB;IACxD,MAAM,KAAK,GAAG,qBAAqB,CAAC,GAAG,CAAC,CAAC;IACzC,OAAO,UAAU,CAAC,QAAQ,CAAC;SACxB,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;SAC1F,MAAM,CAAC,WAAW,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;IACjE,IAAI,UAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,UAAU,GAAG,gBAAgB,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IACD,IACE,UAAU,CAAC,iBAAiB,KAAK,IAAI;QACrC,UAAU,CAAC,oBAAoB,EAAE,UAAU,KAAK,YAAY,EAC5D,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,SAAS,uBAAuB,CAAC,UAAqB;IACpD,IAAI,QAAoB,CAAC;IACzB,IAAI,CAAC;QACH,QAAQ,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,EAAE,CAAC;IACnB,CAAC;IACD,OAAO,qBAAqB,CAAC,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,SAAS,UAAU,CACjB,WAAmB,EACnB,aAAqB,EACrB,UAAwB;IAExB,IACE,CAAC,WAAW,CAAC,IAAI,CAAC,WAAW,CAAC;QAC9B,MAAM,CAAC,UAAU,CAAC,WAAW,EAAE,OAAO,CAAC,GAAG,sBAAsB,EAChE,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACrC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC;QAAE,OAAO,EAAE,CAAC;IAC7E,MAAM,MAAM,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAW,CAAC,CAAC;IACnD,IAAI,MAAM,CAAC,GAAG,KAAK,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,KAAK,SAAS,IAAI,MAAM,CAAC,GAAG,KAAK,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAC5F,MAAM,OAAO,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,CAAW,CAAC,CAAC;IACpD,IACE,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ;QAC/B,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,MAAM,GAAG,GAAG;QACxB,OAAO,OAAO,CAAC,KAAK,KAAK,QAAQ;QACjC,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC;QAC1B,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC;QAClC,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,CAAC;QAClC,CAAC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC;QACtB,OAAO,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,QAAQ;QACnC,CAAC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QAChC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,aAAa,EACjC,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAa,CAAC;IACvC,MAAM,SAAS,GAAG,OAAO,CAAC,GAAa,CAAC;IACxC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC;IACrC,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,GAAG,CAAC;QAC1B,GAAG,GAAG,CAAC;QACP,QAAQ,GAAG,CAAC;QACZ,SAAS,IAAI,QAAQ;QACrB,SAAS,IAAI,GAAG,EAChB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO;QACL,OAAO,EAAE,OAAO,CAAC,GAAG;QACpB,KAAK,EAAE,OAAO,CAAC,KAAK;QACpB,QAAQ;QACR,SAAS;QACT,aAAa;KACd,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,KAAc;IACvC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACvC,IACE,IAAI,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM;QAClC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC;QACzD,KAAK,CAAC,iBAAiB,KAAK,CAAC;QAC7B,OAAO,KAAK,CAAC,YAAY,KAAK,QAAQ;QACtC,OAAO,KAAK,CAAC,sBAAsB,KAAK,QAAQ,EAChD,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;IACD,OAAO;QACL,iBAAiB,EAAE,CAAC;QACpB,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,sBAAsB,EAAE,KAAK,CAAC,sBAAsB;KACrD,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,0BAA0B,CAAC,MAA+B;IACxE,MAAM,KAAK,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACzC,IAAI,MAAM,CAAC,UAAU,CAAC,UAAU,EAAE,MAAM,CAAC,GAAG,oBAAoB;QAAE,OAAO,EAAE,CAAC;IAC5E,OAAO,UAAU,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,KAAiD,EACjD,UAAU,GAAiB,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK;IAEnD,IAAI,MAAM,GAAY,KAAK,CAAC;IAC5B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,MAAM,CAAC,UAAU,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,oBAAoB;YAAE,OAAO,EAAE,CAAC;QACvE,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,UAAU,GAAG,gBAAgB,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC;IACnE,MAAM,SAAS,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,aAAa,GAAG,oBAAoB,CAAC,SAAS,CAAC,CAAC;IACtD,MAAM,KAAK,GAAG,UAAU,CAAC,MAAM,CAAC,YAAY,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC;IACzE,MAAM,UAAU,GAAG,0BAA0B,CAAC,MAAM,CAAC,CAAC;IACtD,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,KAAK,EAAE,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,6BAA6B,CAC3C,WAAmB,EACnB,GAAuB;IAEvB,MAAM,MAAM,GAA4B;QACtC,iBAAiB,EAAE,CAAC;QACpB,YAAY,EAAE,WAAW;QACzB,sBAAsB,EAAE,GAAG,CAAC,eAAe;KAC5C,CAAC;IACF,MAAM,MAAM,GAAG,sBAAsB,CAAC,MAAM,EAAE,GAAG,EAAE;QACjD,MAAM,OAAO,GAAG,eAAe,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACjE,OAAO,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IACH,IAAI,MAAM,CAAC,aAAa,KAAK,GAAG,CAAC,UAAU;QAAE,OAAO,EAAE,CAAC;IACvD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { type CentralCredentialRecord } from "./central-credential.js";
2
+ import type { CentralToolDefinition } from "./mcp-contract.js";
3
+ export type CentralEnrollmentErrorCode = "central_enrollment_contract_failed" | "central_enrollment_outcome_uncertain" | "central_rate_limited" | "central_verification_credential_invalid" | "central_verification_response_unsafe" | "registration_conflict" | "verification_failed";
4
+ export declare class CentralEnrollmentError extends Error {
5
+ readonly code: CentralEnrollmentErrorCode;
6
+ constructor(code: CentralEnrollmentErrorCode);
7
+ }
8
+ export interface CentralEnrollmentClientOptions {
9
+ readonly centralOrigin: string;
10
+ readonly fetch?: typeof fetch;
11
+ readonly deadlineMs?: number;
12
+ readonly deadlineSignal?: (milliseconds: number) => AbortSignal;
13
+ readonly nowSeconds?: () => number;
14
+ }
15
+ export interface VerificationEnrollmentSuccess {
16
+ readonly credential: CentralCredentialRecord;
17
+ readonly localResult: {
18
+ readonly verified: true;
19
+ readonly agent_id: string;
20
+ readonly email: string;
21
+ readonly message: "Email verified successfully.";
22
+ };
23
+ }
24
+ export declare const REST_BOOTSTRAP_TOOLS: readonly CentralToolDefinition[];
25
+ export declare class CentralEnrollmentClient {
26
+ #private;
27
+ constructor(options: CentralEnrollmentClientOptions);
28
+ register(arguments_: unknown, signal?: AbortSignal): Promise<Record<string, string>>;
29
+ resend(arguments_: unknown, signal?: AbortSignal): Promise<Record<string, string>>;
30
+ verify(arguments_: unknown, signal?: AbortSignal): Promise<VerificationEnrollmentSuccess>;
31
+ }
@@ -0,0 +1,278 @@
1
+ import { createCentralCredentialRecord, parseCentralCredential, } from "./central-credential.js";
2
+ import { assertNoCentralCredentialFields, CentralJsonError, isCentralRecord, readCentralJson, } from "./central-json.js";
3
+ import { generateDpopKeyMaterial } from "./dpop.js";
4
+ const DEFAULT_DEADLINE_MS = 30_000;
5
+ const RESPONSE_MAX_BYTES = 64 * 1024;
6
+ const EMAIL = /^[\w.-]+@[\w.-]+\.\w+$/u;
7
+ const CODE = /^\d{6}$/u;
8
+ const AGENT_ID = /^[A-Za-z0-9._~-]{1,256}$/u;
9
+ export class CentralEnrollmentError extends Error {
10
+ code;
11
+ constructor(code) {
12
+ super("Central enrollment failed");
13
+ this.code = code;
14
+ this.name = "CentralEnrollmentError";
15
+ }
16
+ }
17
+ function schema(properties, required) {
18
+ return { type: "object", properties, required: [...required], additionalProperties: false };
19
+ }
20
+ export const REST_BOOTSTRAP_TOOLS = [
21
+ {
22
+ name: "register_agent",
23
+ description: "Register an email identity with the central service.",
24
+ inputSchema: schema({
25
+ email: { type: "string", minLength: 3, maxLength: 254 },
26
+ display_name: { type: "string", minLength: 1, maxLength: 128 },
27
+ delivery: {
28
+ oneOf: [
29
+ {
30
+ type: "object",
31
+ properties: { mode: { const: "direct" } },
32
+ required: ["mode"],
33
+ additionalProperties: false,
34
+ },
35
+ {
36
+ type: "object",
37
+ properties: {
38
+ mode: { const: "webhook" },
39
+ url: { type: "string", minLength: 1, maxLength: 2_048 },
40
+ secret_env: {
41
+ type: "string",
42
+ pattern: "^[A-Za-z_][A-Za-z0-9_]*$",
43
+ },
44
+ },
45
+ required: ["mode", "url", "secret_env"],
46
+ additionalProperties: false,
47
+ },
48
+ ],
49
+ },
50
+ }, ["email"]),
51
+ },
52
+ {
53
+ name: "verify_email",
54
+ description: "Verify the six-digit code sent to the registered email.",
55
+ inputSchema: schema({
56
+ email: { type: "string", minLength: 3, maxLength: 254 },
57
+ code: { type: "string", pattern: "^[0-9]{6}$" },
58
+ }, ["email", "code"]),
59
+ },
60
+ {
61
+ name: "resend_verification",
62
+ description: "Send a new verification code to an unverified email identity.",
63
+ inputSchema: schema({ email: { type: "string", minLength: 3, maxLength: 254 } }, ["email"]),
64
+ },
65
+ ];
66
+ function failure(code) {
67
+ return new CentralEnrollmentError(code);
68
+ }
69
+ function exactOrigin(value) {
70
+ let origin;
71
+ try {
72
+ origin = new URL(value);
73
+ }
74
+ catch {
75
+ throw failure("central_enrollment_contract_failed");
76
+ }
77
+ const loopback = ["127.0.0.1", "::1", "localhost"].includes(origin.hostname);
78
+ if ((origin.protocol !== "https:" && !(origin.protocol === "http:" && loopback)) ||
79
+ origin.username !== "" ||
80
+ origin.password !== "" ||
81
+ origin.pathname !== "/" ||
82
+ origin.search !== "" ||
83
+ origin.hash !== "") {
84
+ throw failure("central_enrollment_contract_failed");
85
+ }
86
+ return origin;
87
+ }
88
+ function exactKeys(value, required, optional = []) {
89
+ if (!isCentralRecord(value))
90
+ return false;
91
+ const allowed = new Set([...required, ...optional]);
92
+ return (required.every((name) => Object.hasOwn(value, name)) &&
93
+ Object.keys(value).every((name) => allowed.has(name)));
94
+ }
95
+ function email(value) {
96
+ if (typeof value !== "string" || value.length > 254 || !EMAIL.test(value)) {
97
+ throw failure("central_enrollment_contract_failed");
98
+ }
99
+ return value;
100
+ }
101
+ function safeString(value, maximum) {
102
+ if (typeof value !== "string" || value.length < 1 || value.length > maximum) {
103
+ throw failure("central_enrollment_contract_failed");
104
+ }
105
+ return value;
106
+ }
107
+ function noStore(headers) {
108
+ return (headers
109
+ .get("cache-control")
110
+ ?.split(",")
111
+ .some((directive) => directive.trim().toLowerCase() === "no-store") === true);
112
+ }
113
+ async function cancel(response) {
114
+ await response.body?.cancel().catch(() => undefined);
115
+ }
116
+ export class CentralEnrollmentClient {
117
+ #origin;
118
+ #fetch;
119
+ #deadlineMs;
120
+ #deadlineSignal;
121
+ #nowSeconds;
122
+ constructor(options) {
123
+ this.#origin = exactOrigin(options.centralOrigin);
124
+ this.#fetch = options.fetch ?? globalThis.fetch;
125
+ this.#deadlineMs = options.deadlineMs ?? DEFAULT_DEADLINE_MS;
126
+ this.#deadlineSignal = options.deadlineSignal ?? AbortSignal.timeout;
127
+ this.#nowSeconds = options.nowSeconds ?? (() => Date.now() / 1_000);
128
+ if (!Number.isSafeInteger(this.#deadlineMs) || this.#deadlineMs < 1) {
129
+ throw failure("central_enrollment_contract_failed");
130
+ }
131
+ }
132
+ async register(arguments_, signal) {
133
+ if (!exactKeys(arguments_, ["email"], ["display_name"])) {
134
+ throw failure("central_enrollment_contract_failed");
135
+ }
136
+ const requestEmail = email(arguments_.email);
137
+ const displayName = arguments_.display_name === undefined ? undefined : safeString(arguments_.display_name, 128);
138
+ const response = await this.#post("/api/register_agent", { email: requestEmail, ...(displayName === undefined ? {} : { display_name: displayName }) }, signal);
139
+ if (response.status === 409) {
140
+ await cancel(response);
141
+ throw failure("registration_conflict");
142
+ }
143
+ const result = await this.#success(response);
144
+ if (!exactKeys(result, ["agent_id", "email", "message"]) ||
145
+ typeof result.agent_id !== "string" ||
146
+ !AGENT_ID.test(result.agent_id) ||
147
+ result.email !== requestEmail ||
148
+ typeof result.message !== "string" ||
149
+ result.message.length < 1 ||
150
+ result.message.length > 512) {
151
+ throw failure("central_enrollment_contract_failed");
152
+ }
153
+ assertNoCentralCredentialFields(result);
154
+ return { agent_id: result.agent_id, email: requestEmail, message: result.message };
155
+ }
156
+ async resend(arguments_, signal) {
157
+ if (!exactKeys(arguments_, ["email"])) {
158
+ throw failure("central_enrollment_contract_failed");
159
+ }
160
+ const response = await this.#post("/api/resend_verification", { email: email(arguments_.email) }, signal);
161
+ const result = await this.#success(response);
162
+ if (!exactKeys(result, ["message"]) ||
163
+ typeof result.message !== "string" ||
164
+ result.message.length < 1 ||
165
+ result.message.length > 512) {
166
+ throw failure("central_enrollment_contract_failed");
167
+ }
168
+ assertNoCentralCredentialFields(result);
169
+ return { message: result.message };
170
+ }
171
+ async verify(arguments_, signal) {
172
+ if (!exactKeys(arguments_, ["email", "code"])) {
173
+ throw failure("central_enrollment_contract_failed");
174
+ }
175
+ const requestEmail = email(arguments_.email);
176
+ if (typeof arguments_.code !== "string" || !CODE.test(arguments_.code)) {
177
+ throw failure("central_enrollment_contract_failed");
178
+ }
179
+ const key = generateDpopKeyMaterial();
180
+ const response = await this.#post("/api/verify_email", { email: requestEmail, code: arguments_.code, jwk: key.publicJwk }, signal);
181
+ if (response.status >= 400 && response.status < 500) {
182
+ await cancel(response);
183
+ throw failure(response.status === 429 ? "central_rate_limited" : "verification_failed");
184
+ }
185
+ if (!response.ok || !noStore(response.headers) || response.headers.has("set-cookie")) {
186
+ await cancel(response);
187
+ throw failure("central_verification_response_unsafe");
188
+ }
189
+ let result;
190
+ try {
191
+ result = await readCentralJson(response, RESPONSE_MAX_BYTES);
192
+ }
193
+ catch {
194
+ throw failure("central_verification_response_unsafe");
195
+ }
196
+ if (!exactKeys(result, ["agent_id", "email", "token", "message"], ["jkt"]) ||
197
+ typeof result.agent_id !== "string" ||
198
+ !AGENT_ID.test(result.agent_id) ||
199
+ result.email !== requestEmail ||
200
+ typeof result.token !== "string" ||
201
+ typeof result.message !== "string" ||
202
+ (result.jkt !== undefined && result.jkt !== key.thumbprint)) {
203
+ throw failure("central_verification_credential_invalid");
204
+ }
205
+ let credential;
206
+ try {
207
+ credential = createCentralCredentialRecord(result.token, key);
208
+ const loaded = parseCentralCredential(credential, this.#nowSeconds);
209
+ if (loaded.token.subject !== result.agent_id ||
210
+ loaded.token.email !== requestEmail ||
211
+ loaded.keyThumbprint !== key.thumbprint) {
212
+ throw new Error("binding mismatch");
213
+ }
214
+ assertNoCentralCredentialFields({
215
+ agent_id: result.agent_id,
216
+ email: result.email,
217
+ message: result.message,
218
+ });
219
+ }
220
+ catch {
221
+ throw failure("central_verification_credential_invalid");
222
+ }
223
+ return {
224
+ credential,
225
+ localResult: {
226
+ verified: true,
227
+ agent_id: result.agent_id,
228
+ email: requestEmail,
229
+ message: "Email verified successfully.",
230
+ },
231
+ };
232
+ }
233
+ async #post(path, body, signal) {
234
+ let deadline;
235
+ try {
236
+ deadline = this.#deadlineSignal(this.#deadlineMs);
237
+ }
238
+ catch {
239
+ throw failure("central_enrollment_contract_failed");
240
+ }
241
+ const requestSignal = signal === undefined ? deadline : AbortSignal.any([signal, deadline]);
242
+ try {
243
+ return await this.#fetch(new URL(path, this.#origin), {
244
+ method: "POST",
245
+ headers: { "accept-encoding": "identity", "content-type": "application/json" },
246
+ body: JSON.stringify(body),
247
+ credentials: "omit",
248
+ redirect: "manual",
249
+ signal: requestSignal,
250
+ });
251
+ }
252
+ catch {
253
+ throw failure("central_enrollment_outcome_uncertain");
254
+ }
255
+ }
256
+ async #success(response) {
257
+ if (response.status === 429) {
258
+ await cancel(response);
259
+ throw failure("central_rate_limited");
260
+ }
261
+ if (!response.ok ||
262
+ response.status < 200 ||
263
+ response.status >= 300 ||
264
+ response.headers.has("set-cookie")) {
265
+ await cancel(response);
266
+ throw failure("central_enrollment_contract_failed");
267
+ }
268
+ try {
269
+ return await readCentralJson(response, RESPONSE_MAX_BYTES);
270
+ }
271
+ catch (error) {
272
+ if (error instanceof CentralJsonError)
273
+ throw failure("central_enrollment_contract_failed");
274
+ throw failure("central_enrollment_contract_failed");
275
+ }
276
+ }
277
+ }
278
+ //# sourceMappingURL=central-enrollment.js.map