@astrasyncai/verification-gateway 4.6.0 → 5.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (135) hide show
  1. package/dist/adapter-interface/interface.d.mts +2 -2
  2. package/dist/adapter-interface/interface.d.ts +2 -2
  3. package/dist/adapters/express.d.mts +2 -2
  4. package/dist/adapters/express.d.ts +2 -2
  5. package/dist/adapters/express.js +25 -35
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +25 -35
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/mcp.d.mts +2 -2
  10. package/dist/adapters/mcp.d.ts +2 -2
  11. package/dist/adapters/mcp.js +42 -67
  12. package/dist/adapters/mcp.js.map +1 -1
  13. package/dist/adapters/mcp.mjs +41 -66
  14. package/dist/adapters/mcp.mjs.map +1 -1
  15. package/dist/adapters/nextjs.d.mts +2 -2
  16. package/dist/adapters/nextjs.d.ts +2 -2
  17. package/dist/adapters/nextjs.js +23 -32
  18. package/dist/adapters/nextjs.js.map +1 -1
  19. package/dist/adapters/nextjs.mjs +23 -32
  20. package/dist/adapters/nextjs.mjs.map +1 -1
  21. package/dist/adapters/sdk.d.mts +2 -2
  22. package/dist/adapters/sdk.d.ts +2 -2
  23. package/dist/adapters/sdk.js +22 -126
  24. package/dist/adapters/sdk.js.map +1 -1
  25. package/dist/adapters/sdk.mjs +22 -124
  26. package/dist/adapters/sdk.mjs.map +1 -1
  27. package/dist/agent/index.d.mts +2 -2
  28. package/dist/agent/index.d.ts +2 -2
  29. package/dist/agent/index.js +1 -1
  30. package/dist/agent/index.js.map +1 -1
  31. package/dist/agent/index.mjs +1 -1
  32. package/dist/agent/index.mjs.map +1 -1
  33. package/dist/bin/astrasync-claude-hook.js +23 -31
  34. package/dist/bin/astrasync-codex-hook.js +23 -31
  35. package/dist/bin/astrasync-guard.js +23 -31
  36. package/dist/bin/astrasync.js +28 -36
  37. package/dist/browser/background.js +23 -31
  38. package/dist/browser/background.js.map +1 -1
  39. package/dist/browser/background.mjs +23 -31
  40. package/dist/browser/background.mjs.map +1 -1
  41. package/dist/browser/browser-adapter.d.mts +2 -2
  42. package/dist/browser/browser-adapter.d.ts +2 -2
  43. package/dist/claude-code/claude-code-adapter.d.mts +2 -2
  44. package/dist/claude-code/claude-code-adapter.d.ts +2 -2
  45. package/dist/cli/index.d.mts +2 -2
  46. package/dist/cli/index.d.ts +2 -2
  47. package/dist/cli/index.js +1 -1
  48. package/dist/cli/index.js.map +1 -1
  49. package/dist/cli/index.mjs +1 -1
  50. package/dist/cli/index.mjs.map +1 -1
  51. package/dist/codex/index.d.mts +2 -2
  52. package/dist/codex/index.d.ts +2 -2
  53. package/dist/codex/index.js +23 -31
  54. package/dist/codex/index.js.map +1 -1
  55. package/dist/codex/index.mjs +23 -31
  56. package/dist/codex/index.mjs.map +1 -1
  57. package/dist/cursor/cursor-adapter.d.mts +2 -2
  58. package/dist/cursor/cursor-adapter.d.ts +2 -2
  59. package/dist/cursor/extension.d.mts +2 -2
  60. package/dist/cursor/extension.d.ts +2 -2
  61. package/dist/cursor/extension.js +23 -31
  62. package/dist/cursor/extension.js.map +1 -1
  63. package/dist/cursor/extension.mjs +23 -31
  64. package/dist/cursor/extension.mjs.map +1 -1
  65. package/dist/edge-config.d.mts +1 -1
  66. package/dist/edge-config.d.ts +1 -1
  67. package/dist/edge-config.js +1 -1
  68. package/dist/edge-config.js.map +1 -1
  69. package/dist/edge-config.mjs +1 -1
  70. package/dist/edge-config.mjs.map +1 -1
  71. package/dist/edge-core/index.d.mts +12 -3
  72. package/dist/edge-core/index.d.ts +12 -3
  73. package/dist/edge-core/index.js +42 -36
  74. package/dist/edge-core/index.js.map +1 -1
  75. package/dist/edge-core/index.mjs +42 -36
  76. package/dist/edge-core/index.mjs.map +1 -1
  77. package/dist/{express-DBtPKXOL.d.mts → express-KkBZBMqi.d.mts} +1 -1
  78. package/dist/{express-D-8Ks2Uo.d.ts → express-xK8pRrmj.d.ts} +1 -1
  79. package/dist/gateway/gateway.d.mts +2 -2
  80. package/dist/gateway/gateway.d.ts +2 -2
  81. package/dist/gateway/gateway.js +23 -31
  82. package/dist/gateway/gateway.js.map +1 -1
  83. package/dist/gateway/gateway.mjs +23 -31
  84. package/dist/gateway/gateway.mjs.map +1 -1
  85. package/dist/git-trigger/git-hooks.d.mts +2 -2
  86. package/dist/git-trigger/git-hooks.d.ts +2 -2
  87. package/dist/{index-kGCGWd5x.d.mts → index-DIRzR5IS.d.mts} +1 -1
  88. package/dist/{index-DlZORQsb.d.ts → index-DLQ4Rcuc.d.ts} +1 -1
  89. package/dist/{index-CUfmJ1Dq.d.mts → index-GPDn_EGI.d.mts} +1 -1
  90. package/dist/{index-BND3kQev.d.ts → index-Hnz5VyMR.d.ts} +1 -1
  91. package/dist/index.d.mts +14 -10
  92. package/dist/index.d.ts +14 -10
  93. package/dist/index.js +44 -219
  94. package/dist/index.js.map +1 -1
  95. package/dist/index.mjs +44 -212
  96. package/dist/index.mjs.map +1 -1
  97. package/dist/local-evaluator/evaluator.d.mts +2 -2
  98. package/dist/local-evaluator/evaluator.d.ts +2 -2
  99. package/dist/local-evaluator/evaluator.js.map +1 -1
  100. package/dist/local-evaluator/evaluator.mjs.map +1 -1
  101. package/dist/{mcp-DToTlwIn.d.ts → mcp-DPpu4xQz.d.ts} +53 -52
  102. package/dist/{mcp-ZRN4kY3b.d.mts → mcp-Dju_Sr1o.d.mts} +53 -52
  103. package/dist/{nextjs-C0KASOy_.d.mts → nextjs-BuoDBN4g.d.mts} +1 -1
  104. package/dist/{nextjs-lwNvWYWT.d.ts → nextjs-rZKzY_8o.d.ts} +1 -1
  105. package/dist/registration/index.js +1 -1
  106. package/dist/registration/index.js.map +1 -1
  107. package/dist/registration/index.mjs +1 -1
  108. package/dist/registration/index.mjs.map +1 -1
  109. package/dist/sdk-CdO6TIEf.d.mts +142 -0
  110. package/dist/sdk-DxHuIJBm.d.ts +142 -0
  111. package/dist/transport/index.d.mts +2 -2
  112. package/dist/transport/index.d.ts +2 -2
  113. package/dist/transport/index.js +1 -1
  114. package/dist/transport/index.js.map +1 -1
  115. package/dist/transport/index.mjs +1 -1
  116. package/dist/transport/index.mjs.map +1 -1
  117. package/dist/{types-DhhJxKIC.d.ts → types-3UV7IZx7.d.ts} +1 -3
  118. package/dist/{types-CGPU7HLi.d.ts → types-CNBaZKxY.d.ts} +24 -50
  119. package/dist/{types-Cx9hTpKI.d.mts → types-CSHcByFX.d.mts} +24 -50
  120. package/dist/{types-CfSJLS4i.d.mts → types-CoDjpbVY.d.mts} +1 -3
  121. package/dist/ui/index.d.mts +2 -17
  122. package/dist/ui/index.d.ts +2 -17
  123. package/dist/ui/index.js +1 -43
  124. package/dist/ui/index.js.map +1 -1
  125. package/dist/ui/index.mjs +1 -42
  126. package/dist/ui/index.mjs.map +1 -1
  127. package/dist/verify.d.mts +3 -4
  128. package/dist/verify.d.ts +3 -4
  129. package/dist/verify.js +22 -30
  130. package/dist/verify.js.map +1 -1
  131. package/dist/verify.mjs +22 -30
  132. package/dist/verify.mjs.map +1 -1
  133. package/package.json +1 -1
  134. package/dist/sdk-B4aodEwj.d.ts +0 -215
  135. package/dist/sdk-B9dSwum7.d.mts +0 -215
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from './types-CGPU7HLi.js';
2
+ import { G as GatewayConfig, w as VerificationResult } from './types-CNBaZKxY.js';
3
3
 
4
4
  /**
5
5
  * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
@@ -58,10 +58,10 @@ declare function isVerifiedHopValidFor(marker: VerifiedHopMarker | null, expecte
58
58
  * - `mcpToPdlss(parsed)` — canonical mapping JSON-RPC method → PDLSS
59
59
  * purpose / action / resource. Doc-stable
60
60
  * so audits can correlate.
61
- * - `mcpRiskTier(parsed)` — recommended `minAccessLevel` per method
61
+ * - `mcpDefaultEnforced(parsed)` — whether a method is enforced by default
62
62
  * so a single MCP middleware can split
63
- * `initialize` / `tools/list` (low gate)
64
- * from `tools/call` (high gate).
63
+ * `initialize` / `tools/list` (pass-through)
64
+ * from `tools/call` (enforced).
65
65
  * - `MCP_VERIFIED_HOP_HEADER` — header convention for the dedupe pattern
66
66
  * when an MCP tool calls an inner REST hop.
67
67
  * - `serialize/parseVerifiedHop` helpers.
@@ -185,18 +185,19 @@ declare function mcpToPdlss(parsed: ParsedMcpRequest, requestPath: string, heade
185
185
  resource?: string;
186
186
  }): McpPdlssMapping;
187
187
  /**
188
- * Recommended minimum access level per method type. The MCP middleware uses
189
- * this to split low-risk handshake / introspection traffic from high-risk
190
- * tool execution.
188
+ * Whether a method is enforced (calls verify-access + gates on the server
189
+ * decision) by default. The MCP middleware uses this to split low-risk
190
+ * handshake / introspection traffic (pass-through) from high-risk tool
191
+ * execution (enforced). Per-tool / per-method overrides win over this default.
191
192
  *
192
- * - `initialize` / `notifications/initialized` → `none` (handshake must work for unregistered probes)
193
- * - `tools/list` / `prompts/list` / `resources/list` → `none` (introspection is public-surface)
194
- * - `ping` → `none`
195
- * - `resources/read` → `read-only`
196
- * - `tools/call` → `standard` (default — overridable per-tool)
197
- * - everything else → `standard` (least-privilege fallback)
193
+ * - `initialize` / `notifications/initialized` → false (handshake must work for unregistered probes)
194
+ * - `tools/list` / `prompts/list` / `resources/list` → false (introspection is public-surface)
195
+ * - `ping` → false
196
+ * - `resources/read` → true
197
+ * - `tools/call` → true (default — overridable per-tool)
198
+ * - everything else → true (least-privilege fallback)
198
199
  */
199
- declare function mcpRiskTier(parsed: ParsedMcpRequest): AccessLevel;
200
+ declare function mcpDefaultEnforced(parsed: ParsedMcpRequest): boolean;
200
201
 
201
202
  /**
202
203
  * AstraSync Universal Verification Gateway — MCP middleware
@@ -238,16 +239,14 @@ declare function mcpRiskTier(parsed: ParsedMcpRequest): AccessLevel;
238
239
  * createMcpMiddleware({
239
240
  * apiBaseUrl: 'https://astrasync.ai/api',
240
241
  * apiKey: process.env.ASTRASYNC_API_KEY,
241
- * // Per-tool gates — tools not listed get the default tier from
242
- * // `mcpRiskTier` (`tools/call` → 'standard'). Use the object form:
243
- * // gated tools need a PDLSS purpose (and ideally an action).
242
+ * // Per-tool gates — `tools/call` is enforced by default; introspection /
243
+ * // handshake pass through. A gated tool needs a PDLSS purpose (and ideally
244
+ * // an action). Set a tool/method to `'observe'` to pass it through
245
+ * // unenforced (still evaluated when `evaluateAlwaysIfCredentialed`).
244
246
  * toolGates: {
245
- * browse_catalog: { minAccessLevel: 'read-only', purpose: 'shopping' },
246
- * start_checkout: {
247
- * minAccessLevel: 'standard',
248
- * purpose: 'shopping',
249
- * action: 'shopping.purchase',
250
- * },
247
+ * browse_catalog: { purpose: 'shopping', action: 'shopping.search' },
248
+ * start_checkout: { purpose: 'shopping', action: 'shopping.purchase' },
249
+ * health_check: 'observe',
251
250
  * },
252
251
  * }),
253
252
  * yourMcpServerHandler,
@@ -280,45 +279,45 @@ declare global {
280
279
  * tool's verify-access call — e.g. mapping `list_products` to `/api/catalog`.
281
280
  */
282
281
  interface ToolGateConfig {
283
- minAccessLevel: AccessLevel;
284
282
  purpose?: string;
285
283
  action?: string;
286
284
  resource?: string;
287
285
  }
286
+ /**
287
+ * A tool/method gate is either a {@link ToolGateConfig} (enforced — calls
288
+ * verify-access and gates on the server decision, using the declared PDLSS
289
+ * purpose/action) or the literal `'observe'` (passed through unenforced;
290
+ * still evaluated when `evaluateAlwaysIfCredentialed` is set). SDK 5.0.0
291
+ * removed the access-level band, so a gate no longer carries a tier — its
292
+ * only decision is enforce vs observe.
293
+ */
294
+ type ToolGate = ToolGateConfig | 'observe';
288
295
  interface McpMiddlewareOptions extends GatewayConfig {
289
296
  /**
290
- * Per-tool gating for `tools/call` invocations. Tools not listed inherit
291
- * the default tier from `mcpRiskTier` (`tools/call` → `'standard'`).
297
+ * Per-tool gating for `tools/call` invocations. Tools not listed are
298
+ * enforced by default (`tools/call` calls verify-access and gates on the
299
+ * server decision).
292
300
  *
293
- * Use the **object form** — it lets the merchant declare the PDLSS
294
- * `purpose` (required for any gated tool: the backend rejects gated calls
295
- * with no resolvable purpose) and pin a dotted-verb `action`:
301
+ * A gated tool declares its PDLSS `purpose` (required: the backend rejects
302
+ * gated calls with no resolvable purpose) and ideally a dotted-verb
303
+ * `action`:
296
304
  * ```typescript
297
305
  * toolGates: {
298
- * list_products: { minAccessLevel: 'read-only',
299
- * purpose: 'shopping',
306
+ * list_products: { purpose: 'shopping',
300
307
  * action: 'shopping.search',
301
308
  * resource: '/api/catalog' },
302
- * start_checkout: { minAccessLevel: 'standard',
303
- * purpose: 'shopping',
309
+ * start_checkout: { purpose: 'shopping',
304
310
  * action: 'shopping.purchase',
305
311
  * resource: '/api/checkout/*' },
312
+ * health_check: 'observe', // pass through unenforced
306
313
  * }
307
314
  * ```
308
315
  *
309
- * The bare access-level string shorthand (`browse_catalog: 'read-only'`)
310
- * is a legacy form and a known footgun: it carries no purpose, so the call
311
- * only succeeds when the AGENT declares one (an `X-Astra-Purpose` header
312
- * or `params._meta.astrasync.purpose`) — otherwise it fails fast with a
313
- * `PDLSS_PURPOSE_REQUIRED` 400. It also declares no action, so evaluation
314
- * is purpose-only (the SDK never sends the raw tool name as the PDLSS
315
- * action). `createMcpMiddleware` logs a warning at construction for every
316
- * bare-string gate.
317
- *
318
- * When `tools/call` arrives for a tool not declared in `toolGates`, the SDK
319
- * falls back to a risk-tier default based on the method classification
320
- * (`mcpRiskTier`). For `tools/call` the fallback is `'standard'`. Best
321
- * practice: declare every tool you expose explicitly.
316
+ * Set a tool to `'observe'` to pass it through without enforcement (it is
317
+ * still evaluated for the audit trail when `evaluateAlwaysIfCredentialed`
318
+ * is set). A gated object form with no resolvable purpose fails fast with a
319
+ * `PDLSS_PURPOSE_REQUIRED` 400 (the SDK never sends the raw tool name as
320
+ * the PDLSS action).
322
321
  *
323
322
  * The action axis for non-tools/call MCP methods (`tools/list`,
324
323
  * `resources/list`, `prompts/list`, etc.) is the literal JSON-RPC method
@@ -326,13 +325,15 @@ interface McpMiddlewareOptions extends GatewayConfig {
326
325
  * declare per-tool gates in `toolGates`, not endpoint-level `allowedActions`
327
326
  * — the latter applies to REST-style action values, not MCP method strings.
328
327
  */
329
- toolGates?: Record<string, AccessLevel | ToolGateConfig>;
328
+ toolGates?: Record<string, ToolGate>;
330
329
  /**
331
- * Per-method override (e.g. tighten `tools/list` to `'read-only'` if you
332
- * don't want unregistered probes seeing your tool catalogue). Matches by
333
- * exact JSON-RPC method string.
330
+ * Per-method override. By default introspection / handshake methods
331
+ * (`tools/list`, `initialize`, `ping`, …) pass through and `tools/call` is
332
+ * enforced; declare a method here to enforce it (object form, with a PDLSS
333
+ * purpose) or set it to `'observe'` to pass it through. Matches by exact
334
+ * JSON-RPC method string.
334
335
  */
335
- methodGates?: Record<string, AccessLevel>;
336
+ methodGates?: Record<string, ToolGate>;
336
337
  /**
337
338
  * What to do when the agent id supplied in the X-Astra-Id header
338
339
  * disagrees with the agent id in the JSON-RPC body
@@ -393,4 +394,4 @@ interface McpMiddlewareOptions extends GatewayConfig {
393
394
  */
394
395
  declare function createMcpMiddleware(options: McpMiddlewareOptions): RequestHandler;
395
396
 
396
- export { MCP_VERIFIED_HOP_HEADER as M, type ParsedMcpRequest as P, type ToolGateConfig as T, type VerifiedHopMarker as V, MCP_VERIFIED_HOP_MAX_AGE_MS as a, type McpMiddlewareOptions as b, createMcpMiddleware as c, mcpToPdlss as d, parseVerifiedHop as e, isVerifiedHopValidFor as i, mcpRiskTier as m, parseMcpJsonRpc as p, serializeVerifiedHop as s };
397
+ export { MCP_VERIFIED_HOP_HEADER as M, type ParsedMcpRequest as P, type ToolGate as T, type VerifiedHopMarker as V, MCP_VERIFIED_HOP_MAX_AGE_MS as a, type McpMiddlewareOptions as b, type ToolGateConfig as c, createMcpMiddleware as d, mcpToPdlss as e, parseVerifiedHop as f, isVerifiedHopValidFor as i, mcpDefaultEnforced as m, parseMcpJsonRpc as p, serializeVerifiedHop as s };
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { a as AccessLevel, G as GatewayConfig, x as VerificationResult } from './types-Cx9hTpKI.mjs';
2
+ import { G as GatewayConfig, w as VerificationResult } from './types-CSHcByFX.mjs';
3
3
 
4
4
  /**
5
5
  * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
@@ -58,10 +58,10 @@ declare function isVerifiedHopValidFor(marker: VerifiedHopMarker | null, expecte
58
58
  * - `mcpToPdlss(parsed)` — canonical mapping JSON-RPC method → PDLSS
59
59
  * purpose / action / resource. Doc-stable
60
60
  * so audits can correlate.
61
- * - `mcpRiskTier(parsed)` — recommended `minAccessLevel` per method
61
+ * - `mcpDefaultEnforced(parsed)` — whether a method is enforced by default
62
62
  * so a single MCP middleware can split
63
- * `initialize` / `tools/list` (low gate)
64
- * from `tools/call` (high gate).
63
+ * `initialize` / `tools/list` (pass-through)
64
+ * from `tools/call` (enforced).
65
65
  * - `MCP_VERIFIED_HOP_HEADER` — header convention for the dedupe pattern
66
66
  * when an MCP tool calls an inner REST hop.
67
67
  * - `serialize/parseVerifiedHop` helpers.
@@ -185,18 +185,19 @@ declare function mcpToPdlss(parsed: ParsedMcpRequest, requestPath: string, heade
185
185
  resource?: string;
186
186
  }): McpPdlssMapping;
187
187
  /**
188
- * Recommended minimum access level per method type. The MCP middleware uses
189
- * this to split low-risk handshake / introspection traffic from high-risk
190
- * tool execution.
188
+ * Whether a method is enforced (calls verify-access + gates on the server
189
+ * decision) by default. The MCP middleware uses this to split low-risk
190
+ * handshake / introspection traffic (pass-through) from high-risk tool
191
+ * execution (enforced). Per-tool / per-method overrides win over this default.
191
192
  *
192
- * - `initialize` / `notifications/initialized` → `none` (handshake must work for unregistered probes)
193
- * - `tools/list` / `prompts/list` / `resources/list` → `none` (introspection is public-surface)
194
- * - `ping` → `none`
195
- * - `resources/read` → `read-only`
196
- * - `tools/call` → `standard` (default — overridable per-tool)
197
- * - everything else → `standard` (least-privilege fallback)
193
+ * - `initialize` / `notifications/initialized` → false (handshake must work for unregistered probes)
194
+ * - `tools/list` / `prompts/list` / `resources/list` → false (introspection is public-surface)
195
+ * - `ping` → false
196
+ * - `resources/read` → true
197
+ * - `tools/call` → true (default — overridable per-tool)
198
+ * - everything else → true (least-privilege fallback)
198
199
  */
199
- declare function mcpRiskTier(parsed: ParsedMcpRequest): AccessLevel;
200
+ declare function mcpDefaultEnforced(parsed: ParsedMcpRequest): boolean;
200
201
 
201
202
  /**
202
203
  * AstraSync Universal Verification Gateway — MCP middleware
@@ -238,16 +239,14 @@ declare function mcpRiskTier(parsed: ParsedMcpRequest): AccessLevel;
238
239
  * createMcpMiddleware({
239
240
  * apiBaseUrl: 'https://astrasync.ai/api',
240
241
  * apiKey: process.env.ASTRASYNC_API_KEY,
241
- * // Per-tool gates — tools not listed get the default tier from
242
- * // `mcpRiskTier` (`tools/call` → 'standard'). Use the object form:
243
- * // gated tools need a PDLSS purpose (and ideally an action).
242
+ * // Per-tool gates — `tools/call` is enforced by default; introspection /
243
+ * // handshake pass through. A gated tool needs a PDLSS purpose (and ideally
244
+ * // an action). Set a tool/method to `'observe'` to pass it through
245
+ * // unenforced (still evaluated when `evaluateAlwaysIfCredentialed`).
244
246
  * toolGates: {
245
- * browse_catalog: { minAccessLevel: 'read-only', purpose: 'shopping' },
246
- * start_checkout: {
247
- * minAccessLevel: 'standard',
248
- * purpose: 'shopping',
249
- * action: 'shopping.purchase',
250
- * },
247
+ * browse_catalog: { purpose: 'shopping', action: 'shopping.search' },
248
+ * start_checkout: { purpose: 'shopping', action: 'shopping.purchase' },
249
+ * health_check: 'observe',
251
250
  * },
252
251
  * }),
253
252
  * yourMcpServerHandler,
@@ -280,45 +279,45 @@ declare global {
280
279
  * tool's verify-access call — e.g. mapping `list_products` to `/api/catalog`.
281
280
  */
282
281
  interface ToolGateConfig {
283
- minAccessLevel: AccessLevel;
284
282
  purpose?: string;
285
283
  action?: string;
286
284
  resource?: string;
287
285
  }
286
+ /**
287
+ * A tool/method gate is either a {@link ToolGateConfig} (enforced — calls
288
+ * verify-access and gates on the server decision, using the declared PDLSS
289
+ * purpose/action) or the literal `'observe'` (passed through unenforced;
290
+ * still evaluated when `evaluateAlwaysIfCredentialed` is set). SDK 5.0.0
291
+ * removed the access-level band, so a gate no longer carries a tier — its
292
+ * only decision is enforce vs observe.
293
+ */
294
+ type ToolGate = ToolGateConfig | 'observe';
288
295
  interface McpMiddlewareOptions extends GatewayConfig {
289
296
  /**
290
- * Per-tool gating for `tools/call` invocations. Tools not listed inherit
291
- * the default tier from `mcpRiskTier` (`tools/call` → `'standard'`).
297
+ * Per-tool gating for `tools/call` invocations. Tools not listed are
298
+ * enforced by default (`tools/call` calls verify-access and gates on the
299
+ * server decision).
292
300
  *
293
- * Use the **object form** — it lets the merchant declare the PDLSS
294
- * `purpose` (required for any gated tool: the backend rejects gated calls
295
- * with no resolvable purpose) and pin a dotted-verb `action`:
301
+ * A gated tool declares its PDLSS `purpose` (required: the backend rejects
302
+ * gated calls with no resolvable purpose) and ideally a dotted-verb
303
+ * `action`:
296
304
  * ```typescript
297
305
  * toolGates: {
298
- * list_products: { minAccessLevel: 'read-only',
299
- * purpose: 'shopping',
306
+ * list_products: { purpose: 'shopping',
300
307
  * action: 'shopping.search',
301
308
  * resource: '/api/catalog' },
302
- * start_checkout: { minAccessLevel: 'standard',
303
- * purpose: 'shopping',
309
+ * start_checkout: { purpose: 'shopping',
304
310
  * action: 'shopping.purchase',
305
311
  * resource: '/api/checkout/*' },
312
+ * health_check: 'observe', // pass through unenforced
306
313
  * }
307
314
  * ```
308
315
  *
309
- * The bare access-level string shorthand (`browse_catalog: 'read-only'`)
310
- * is a legacy form and a known footgun: it carries no purpose, so the call
311
- * only succeeds when the AGENT declares one (an `X-Astra-Purpose` header
312
- * or `params._meta.astrasync.purpose`) — otherwise it fails fast with a
313
- * `PDLSS_PURPOSE_REQUIRED` 400. It also declares no action, so evaluation
314
- * is purpose-only (the SDK never sends the raw tool name as the PDLSS
315
- * action). `createMcpMiddleware` logs a warning at construction for every
316
- * bare-string gate.
317
- *
318
- * When `tools/call` arrives for a tool not declared in `toolGates`, the SDK
319
- * falls back to a risk-tier default based on the method classification
320
- * (`mcpRiskTier`). For `tools/call` the fallback is `'standard'`. Best
321
- * practice: declare every tool you expose explicitly.
316
+ * Set a tool to `'observe'` to pass it through without enforcement (it is
317
+ * still evaluated for the audit trail when `evaluateAlwaysIfCredentialed`
318
+ * is set). A gated object form with no resolvable purpose fails fast with a
319
+ * `PDLSS_PURPOSE_REQUIRED` 400 (the SDK never sends the raw tool name as
320
+ * the PDLSS action).
322
321
  *
323
322
  * The action axis for non-tools/call MCP methods (`tools/list`,
324
323
  * `resources/list`, `prompts/list`, etc.) is the literal JSON-RPC method
@@ -326,13 +325,15 @@ interface McpMiddlewareOptions extends GatewayConfig {
326
325
  * declare per-tool gates in `toolGates`, not endpoint-level `allowedActions`
327
326
  * — the latter applies to REST-style action values, not MCP method strings.
328
327
  */
329
- toolGates?: Record<string, AccessLevel | ToolGateConfig>;
328
+ toolGates?: Record<string, ToolGate>;
330
329
  /**
331
- * Per-method override (e.g. tighten `tools/list` to `'read-only'` if you
332
- * don't want unregistered probes seeing your tool catalogue). Matches by
333
- * exact JSON-RPC method string.
330
+ * Per-method override. By default introspection / handshake methods
331
+ * (`tools/list`, `initialize`, `ping`, …) pass through and `tools/call` is
332
+ * enforced; declare a method here to enforce it (object form, with a PDLSS
333
+ * purpose) or set it to `'observe'` to pass it through. Matches by exact
334
+ * JSON-RPC method string.
334
335
  */
335
- methodGates?: Record<string, AccessLevel>;
336
+ methodGates?: Record<string, ToolGate>;
336
337
  /**
337
338
  * What to do when the agent id supplied in the X-Astra-Id header
338
339
  * disagrees with the agent id in the JSON-RPC body
@@ -393,4 +394,4 @@ interface McpMiddlewareOptions extends GatewayConfig {
393
394
  */
394
395
  declare function createMcpMiddleware(options: McpMiddlewareOptions): RequestHandler;
395
396
 
396
- export { MCP_VERIFIED_HOP_HEADER as M, type ParsedMcpRequest as P, type ToolGateConfig as T, type VerifiedHopMarker as V, MCP_VERIFIED_HOP_MAX_AGE_MS as a, type McpMiddlewareOptions as b, createMcpMiddleware as c, mcpToPdlss as d, parseVerifiedHop as e, isVerifiedHopValidFor as i, mcpRiskTier as m, parseMcpJsonRpc as p, serializeVerifiedHop as s };
397
+ export { MCP_VERIFIED_HOP_HEADER as M, type ParsedMcpRequest as P, type ToolGate as T, type VerifiedHopMarker as V, MCP_VERIFIED_HOP_MAX_AGE_MS as a, type McpMiddlewareOptions as b, type ToolGateConfig as c, createMcpMiddleware as d, mcpToPdlss as e, parseVerifiedHop as f, isVerifiedHopValidFor as i, mcpDefaultEnforced as m, parseMcpJsonRpc as p, serializeVerifiedHop as s };
@@ -1,6 +1,6 @@
1
1
  import * as next_server from 'next/server';
2
2
  import { NextRequest } from 'next/server';
3
- import { N as NextJsMiddlewareOptions } from './types-Cx9hTpKI.mjs';
3
+ import { N as NextJsMiddlewareOptions } from './types-CSHcByFX.mjs';
4
4
 
5
5
  /**
6
6
  * Create Next.js middleware for agent verification.
@@ -1,6 +1,6 @@
1
1
  import * as next_server from 'next/server';
2
2
  import { NextRequest } from 'next/server';
3
- import { N as NextJsMiddlewareOptions } from './types-CGPU7HLi.js';
3
+ import { N as NextJsMiddlewareOptions } from './types-CNBaZKxY.js';
4
4
 
5
5
  /**
6
6
  * Create Next.js middleware for agent verification.
@@ -42,7 +42,7 @@ __export(registration_exports, {
42
42
  module.exports = __toCommonJS(registration_exports);
43
43
 
44
44
  // src/version.ts
45
- var SDK_VERSION = "4.6.0";
45
+ var SDK_VERSION = "5.0.0";
46
46
 
47
47
  // src/http.ts
48
48
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/registration/index.ts","../../src/version.ts","../../src/http.ts","../../src/registration/errors.ts","../../src/registration/api.ts","../../src/registration/guidance.ts"],"sourcesContent":["export { AstraSync } from './api';\nexport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\nexport { buildGuidance } from './guidance';\nexport type { GuidanceEnvelope, BuildGuidanceParams } from './guidance';\nexport type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n AgentRecord,\n VerifyResponse,\n HealthResponse,\n PDLSSConfig,\n PDLSSPurpose,\n PDLSSDuration,\n PDLSSLimits,\n PDLSSScope,\n PDLSSSelfInstantiation,\n ModelConfig,\n FrameworkConfig,\n AgentProtocol,\n} from './types';\n","/**\n * Single source-of-truth for the SDK's\n * package version emitted on verify-access bodies (and any future\n * telemetry). Bumped alongside `package.json#version` on every release.\n *\n * Why a constant rather than `import pkg from '../package.json'`:\n * - `tsconfig.json` sets `rootDir: ./src`; importing the sibling\n * package.json fails the build with \"outside rootDir\".\n * - Build-time string replacement (tsup `define`, esbuild banner, etc.)\n * adds toolchain coupling for a trivial gain.\n * - Embedded readonly constant works in every environment (Node, browser,\n * bundlers, Deno) without runtime fs / network access.\n *\n * Release discipline: a CI lint can grep `package.json#version` against\n * this constant if the two ever diverge in the wild. A manual bump\n * is fine — bumping both in the release-ceremony commit keeps them\n * lockstep.\n */\nexport const SDK_VERSION = '4.6.0';\n","/**\n * Shared outbound-HTTP wrapper — every request the SDK makes to the\n * AstraSync backend (or anywhere else) goes through `sdkFetch` so it\n * carries an identifying User-Agent.\n *\n * Why: Node's global fetch defaults to `user-agent: node`, which is\n * indistinguishable from every other Node client on the wire. Visit\n * Intelligence observed our own SDK/beacon traffic as anonymous \"node\"\n * visits. Self-identification is the platform's own medicine.\n *\n * Browser note: some browsers filter the User-Agent request header\n * silently (never throwing), so this is a no-op there — which is correct:\n * in a browser the page's real UA is the honest identity.\n */\n\nimport { SDK_VERSION } from './version';\n\nexport const SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;\n\n/**\n * Add the SDK User-Agent without changing the SHAPE of the caller's headers\n * (plain records stay plain records) — interceptors, adapters, and tests\n * read `init.headers` as a record, and `Headers` would also lowercase names.\n */\nfunction withUserAgent(initHeaders: HeadersInit | undefined): HeadersInit {\n if (!initHeaders) return { 'user-agent': SDK_USER_AGENT };\n if (initHeaders instanceof Headers) {\n const copy = new Headers(initHeaders);\n if (!copy.has('user-agent')) copy.set('user-agent', SDK_USER_AGENT);\n return copy;\n }\n if (Array.isArray(initHeaders)) {\n const has = initHeaders.some(([name]) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : [...initHeaders, ['user-agent', SDK_USER_AGENT]];\n }\n const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : { 'user-agent': SDK_USER_AGENT, ...initHeaders };\n}\n\nexport const sdkFetch: typeof fetch = (input, init) =>\n fetch(input, { ...init, headers: withUserAgent(init?.headers) });\n","import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the owner denies the\n * pending registration request. The `reason` field, when present, mirrors the\n * deny note the owner left in the dashboard.\n */\nexport class RegistrationDeniedError extends AstraSyncError {\n public readonly requestId: string;\n public readonly reason?: string;\n\n constructor(requestId: string, reason?: string) {\n super(\n `Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ''}`,\n 403,\n 'REGISTRATION_DENIED'\n );\n this.name = 'RegistrationDeniedError';\n this.requestId = requestId;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the pending request\n * passes its 14-day TTL with no owner decision. The agent must re-submit.\n */\nexport class RegistrationExpiredError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,\n 410,\n 'REGISTRATION_EXPIRED'\n );\n this.name = 'RegistrationExpiredError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the caller's local\n * `timeoutMs` elapses before the owner makes a decision. The request is still\n * live server-side — poll `pollRegistration(requestId)` to resume waiting, or\n * call `waitForApproval` again with a longer timeout.\n */\nexport class RegistrationTimeoutError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,\n 408,\n 'REGISTRATION_TIMEOUT'\n );\n this.name = 'RegistrationTimeoutError';\n this.requestId = requestId;\n }\n}\n","import { sdkFetch } from '../http';\nimport type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n AgentRecord,\n} from './types';\nimport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n let raw = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n // Round-10 (O2): tolerate the verify-side convention. `GatewayConfig.apiBaseUrl`\n // is documented as `https://astrasync.ai/api` (with /api), but\n // `AstraSyncConfig.baseUrl` is documented as the bare origin. Partners\n // passing the verify-style URL to the registration client hit a 404\n // because we'd then append `/api/agents/register` → double /api. Strip\n // a trailing `/api` and warn once so the partner can fix the source.\n if (raw.toLowerCase().endsWith('/api')) {\n raw = raw.slice(0, -'/api'.length);\n if (config.baseUrl && !config.silent) {\n // eslint-disable-next-line no-console\n console.warn(\n `[AstraSync] baseUrl '${config.baseUrl}' had a trailing /api — stripped to '${raw}'. ` +\n `Pass the bare origin (e.g. 'https://astrasync.ai' or 'https://staging.astrasync.ai') ` +\n `to AstraSync(). The /api suffix is the verify-gateway (GatewayConfig.apiBaseUrl) convention.`\n );\n }\n }\n this.baseUrl = raw;\n\n // Env fallback is opt-OUT: server-side wrappers (MCP tool handlers,\n // gateway adapters) pass `disableEnvFallback: true` so a no-credentials\n // call from a user-facing flow cannot silently authenticate as the host\n // process's platform-attribution key. CLIs / scripts that legitimately\n // rely on ASTRASYNC_API_KEY keep working under the default.\n this.apiKey = config.disableEnvFallback\n ? config.apiKey\n : config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n // Defense-in-depth: warn when env fallback actually fires under the\n // default (non-strict) config. Surfaces the \"I'm running as platform\"\n // foot-gun before it becomes a security bug. Gated by !silent.\n if (\n !config.apiKey &&\n !config.disableEnvFallback &&\n process.env.ASTRASYNC_API_KEY &&\n !config.silent\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n '[AstraSync] No apiKey passed to constructor; using process.env.ASTRASYNC_API_KEY. ' +\n 'If this code wraps user-facing flows (e.g. MCP tool handlers), pass ' +\n 'disableEnvFallback: true to prevent ambient credentials from impersonating callers. ' +\n 'See https://astrasync.ai/docs/agent-access#disableenvfallback for details.'\n );\n }\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n *\n * The backend response depends on auth context:\n * - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,\n * returns `{ status: 'active', agent }`.\n * - **API-key only** (no signature): 202 pending, returns\n * `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The\n * owner is notified by email and a dashboard alert is emitted; the agent\n * becomes active only after the owner approves.\n *\n * Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the\n * request until it resolves, then return the live agent record. The promise\n * rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or\n * `RegistrationTimeoutError` on the corresponding terminal states.\n *\n * @example Non-blocking (default — best for serverless / scheduled agents):\n * ```typescript\n * const result = await sdk.register({ name, pdlss });\n * if (result.status === 'pending_approval') {\n * storeRequestId(result.requestId);\n * return; // function exits; resume later via pollRegistration()\n * }\n * ```\n *\n * @example Blocking (best for long-running services + CLI):\n * ```typescript\n * const agent = await sdk.register({\n * name, pdlss, waitForApproval: true, timeoutMs: 600_000,\n * onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),\n * });\n * ```\n */\n async register(\n options: RegisterOptions & WaitForApprovalOptions\n ): Promise<RegisterResult | AgentRecord> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n const { status, body: raw } = await this.requestWithStatus<\n RegistrationResponse | PendingRegistrationResponse\n >('POST', '/api/agents/register', body);\n\n if (status === 201) {\n const activeBody = raw as RegistrationResponse;\n const active: RegisterResult = {\n status: 'active',\n agent: activeBody.data.agent,\n // Round-12 (F16): pass backend advisories through verbatim.\n // Pre-fix the SDK whitelisted five fields and silently dropped\n // `warnings`, which left partners with no signal that\n // `no_callback_endpoint` (or future advisories) had fired.\n ...(activeBody.warnings && { warnings: activeBody.warnings }),\n };\n return active;\n }\n\n // 202 Accepted — owner approval required.\n const pendingBody = raw as PendingRegistrationResponse;\n const pending: RegisterResult = {\n status: 'pending_approval',\n requestId: pendingBody.requestId,\n expiresAt: pendingBody.expiresAt,\n pollUrl: pendingBody.pollUrl,\n message: pendingBody.message,\n // Round-12 (F16): same pass-through on the pending path.\n ...(pendingBody.warnings && { warnings: pendingBody.warnings }),\n };\n\n if (!options.waitForApproval) return pending;\n\n return this.waitForApproval(pendingBody.requestId, options);\n }\n\n /**\n * Poll the current state of a pending-approval registration request.\n *\n * Useful for caller-driven polling when `waitForApproval: false` (the\n * default). The endpoint is unauthenticated — pass the `requestId` that\n * was returned from the 202 response.\n *\n * @returns `state: 'pending'` while awaiting; `'approved'` carries the\n * minted agent in `agent`; `'denied'` may carry the owner's\n * `reason`; `'expired'` is terminal after 14 days.\n */\n async pollRegistration(requestId: string): Promise<PollRegistrationResult> {\n const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;\n const res = await sdkFetch(url, { headers: { Accept: 'application/json' } });\n if (!res.ok) {\n const errBody = (await res.json().catch(() => ({}))) as ApiErrorResponse;\n throw new AstraSyncError(\n errBody.error || `pollRegistration failed: ${res.status}`,\n res.status,\n errBody.code\n );\n }\n return (await res.json()) as PollRegistrationResult;\n }\n\n /**\n * Block until a pending registration request resolves to a terminal state.\n * Resolves to the live `AgentRecord` on approval; rejects with the matching\n * Registration*Error on deny/expire/timeout. Usually called via\n * `register({ waitForApproval: true })`, but exposed for callers that want\n * to fire-and-forget the initial register call and resume waiting later\n * (e.g. after restoring a stored `requestId` on cold start).\n */\n async waitForApproval(\n requestId: string,\n options: WaitForApprovalOptions = {}\n ): Promise<AgentRecord> {\n const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;\n const pollIntervalMs = options.pollIntervalMs ?? 5_000;\n const start = Date.now();\n const deadline = start + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await this.pollRegistration(requestId);\n const ageMs = Date.now() - start;\n options.onPending?.({ requestId, ageMs });\n\n if (result.state === 'approved') {\n if (!result.agent) {\n throw new AstraSyncError(\n `Registration ${requestId} reported approved but no agent payload returned.`,\n 500\n );\n }\n return result.agent;\n }\n if (result.state === 'denied') {\n throw new RegistrationDeniedError(requestId, result.reason);\n }\n if (result.state === 'expired') {\n throw new RegistrationExpiredError(requestId);\n }\n await sleep(pollIntervalMs);\n }\n throw new RegistrationTimeoutError(requestId);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await sdkFetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const { body: parsed } = await this.requestWithStatus<T>(method, endpoint, body);\n return parsed;\n }\n\n /**\n * Variant of {@link request} that also returns the HTTP status code, so\n * callers can branch on 201 vs 202 (or other success codes) without losing\n * type information about the response body.\n */\n private async requestWithStatus<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await sdkFetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return { status: res.status, body: (await res.json()) as T };\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await sdkFetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n","/**\n * Guidance envelope for credentials-required cases.\n *\n * A single shared source of truth so partners writing their own wrappers\n * (custom MCP servers, Express middleware around registration, gateway\n * adapters) consume a single source of truth instead of re-implementing the\n * five-step boilerplate.\n *\n * The envelope is what an agent (or wrapping MCP client) sees when it calls\n * `register_agent` with no AstraSync credentials. It tells the calling agent\n * (a) what failed (`status: 'credentials_required'`), (b) the keyless\n * registration ACTION endpoint (`registrationUrl` — POST-able, not the human\n * dashboard), (c) where the relevant docs are (`documentationUrl`), and (d) the\n * ordered next-actions (`steps`).\n */\n\nexport interface GuidanceEnvelope {\n /**\n * Single-literal today. Expand to a union (e.g.\n * `'credentials_required' | 'kyd_required' | …`) when a second guidance\n * status emerges. Don't pre-emptively widen — the literal pins the shape.\n */\n status: 'credentials_required';\n message: string;\n guidance: {\n message: string;\n registrationUrl: string;\n documentationUrl: string;\n steps: string[];\n };\n}\n\nexport interface BuildGuidanceParams {\n /**\n * Bare origin of the AstraSync deployment the caller should register at,\n * e.g. `https://astrasync.ai` or `https://staging.astrasync.ai`. No\n * trailing slash, no `/api` suffix — registrationUrl and documentationUrl\n * are templated relative to this origin.\n */\n origin: string;\n /**\n * Overrides the top-level `message` (the short summary the agent sees).\n * Defaults to the error message from the SDK's `AuthenticationError`\n * when present, else a generic \"credentials required\" line.\n */\n message?: string;\n /**\n * Overrides the documentation path. Defaults to `/docs/agent-access`.\n */\n documentationPath?: string;\n}\n\n/**\n * Build the credentials-required guidance envelope.\n *\n * This is the canonical builder — MCP wrappers (`agent-registration.ts`),\n * Express middleware in custom integrations, and any other partner-side\n * wrapper that needs to surface \"you need to register\" should call this\n * rather than reconstructing the shape inline. Inline reconstruction\n * historically led to drift between wrappers; this consolidates it.\n *\n * @example\n * ```ts\n * import { buildGuidance } from '@astrasyncai/verification-gateway';\n *\n * try {\n * const sdk = new AstraSync({ apiKey: callerApiKey, disableEnvFallback: true });\n * // ...\n * } catch (err) {\n * if (err instanceof AuthenticationError) {\n * return buildGuidance({ origin: 'https://astrasync.ai', message: err.message });\n * }\n * throw err;\n * }\n * ```\n */\nexport function buildGuidance(params: BuildGuidanceParams): GuidanceEnvelope {\n const origin = params.origin.replace(/\\/+$/, '');\n const docsPath = params.documentationPath ?? '/docs/agent-access';\n const message = params.message ?? 'AstraSync registration requires credentials.';\n\n return {\n status: 'credentials_required',\n message,\n guidance: {\n message:\n \"Register either with an agent-scoped API key (the recommended credentialed path) OR, if you hold no credentials, via the owner's email using request_registration. Never send a password or private key over the wire.\",\n // 3.0.0: registrationUrl is the agent-actionable KEYLESS endpoint, not the\n // human dashboard `/agents/register` (an auth-walled page an agent can't\n // use). documentationUrl carries the machine-readable contract.\n registrationUrl: `${origin}/api/agents/request-registration`,\n documentationUrl: `${origin}${docsPath.startsWith('/') ? docsPath : `/${docsPath}`}`,\n steps: [\n 'Credentialed path (recommended): have your human mint an agent-scoped API key at Settings → API Keys, then re-call register_agent with apiKey set. An agent holding its own scoped kya_ key is fine and intended.',\n \"No-credentials path: call request_registration({ name, ownerEmail, ... }) with the human owner's email — the only bootstrap credential. No API key is involved.\",\n 'Include as much metadata as you can in the registration — especially model ({ modelName, modelProvider }) and framework ({ frameworkName, frameworkVersion }). Declared platform/model metadata directly improves your trust score and attributes your traffic correctly.',\n 'The owner approves via an emailed link (first time, they create an account and complete a quick verification).',\n 'Use poll_registration({ requestId }) once the owner confirms approval to retrieve the astraId.',\n 'Never transmit a password or private key over the MCP wire — those are never required.',\n ],\n },\n };\n}\n"],"mappings":"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","names":["has"]}
1
+ {"version":3,"sources":["../../src/registration/index.ts","../../src/version.ts","../../src/http.ts","../../src/registration/errors.ts","../../src/registration/api.ts","../../src/registration/guidance.ts"],"sourcesContent":["export { AstraSync } from './api';\nexport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\nexport { buildGuidance } from './guidance';\nexport type { GuidanceEnvelope, BuildGuidanceParams } from './guidance';\nexport type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n AgentRecord,\n VerifyResponse,\n HealthResponse,\n PDLSSConfig,\n PDLSSPurpose,\n PDLSSDuration,\n PDLSSLimits,\n PDLSSScope,\n PDLSSSelfInstantiation,\n ModelConfig,\n FrameworkConfig,\n AgentProtocol,\n} from './types';\n","/**\n * Single source-of-truth for the SDK's\n * package version emitted on verify-access bodies (and any future\n * telemetry). Bumped alongside `package.json#version` on every release.\n *\n * Why a constant rather than `import pkg from '../package.json'`:\n * - `tsconfig.json` sets `rootDir: ./src`; importing the sibling\n * package.json fails the build with \"outside rootDir\".\n * - Build-time string replacement (tsup `define`, esbuild banner, etc.)\n * adds toolchain coupling for a trivial gain.\n * - Embedded readonly constant works in every environment (Node, browser,\n * bundlers, Deno) without runtime fs / network access.\n *\n * Release discipline: a CI lint can grep `package.json#version` against\n * this constant if the two ever diverge in the wild. A manual bump\n * is fine — bumping both in the release-ceremony commit keeps them\n * lockstep.\n */\nexport const SDK_VERSION = '5.0.0';\n","/**\n * Shared outbound-HTTP wrapper — every request the SDK makes to the\n * AstraSync backend (or anywhere else) goes through `sdkFetch` so it\n * carries an identifying User-Agent.\n *\n * Why: Node's global fetch defaults to `user-agent: node`, which is\n * indistinguishable from every other Node client on the wire. Visit\n * Intelligence observed our own SDK/beacon traffic as anonymous \"node\"\n * visits. Self-identification is the platform's own medicine.\n *\n * Browser note: some browsers filter the User-Agent request header\n * silently (never throwing), so this is a no-op there — which is correct:\n * in a browser the page's real UA is the honest identity.\n */\n\nimport { SDK_VERSION } from './version';\n\nexport const SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;\n\n/**\n * Add the SDK User-Agent without changing the SHAPE of the caller's headers\n * (plain records stay plain records) — interceptors, adapters, and tests\n * read `init.headers` as a record, and `Headers` would also lowercase names.\n */\nfunction withUserAgent(initHeaders: HeadersInit | undefined): HeadersInit {\n if (!initHeaders) return { 'user-agent': SDK_USER_AGENT };\n if (initHeaders instanceof Headers) {\n const copy = new Headers(initHeaders);\n if (!copy.has('user-agent')) copy.set('user-agent', SDK_USER_AGENT);\n return copy;\n }\n if (Array.isArray(initHeaders)) {\n const has = initHeaders.some(([name]) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : [...initHeaders, ['user-agent', SDK_USER_AGENT]];\n }\n const has = Object.keys(initHeaders).some((name) => name.toLowerCase() === 'user-agent');\n return has ? initHeaders : { 'user-agent': SDK_USER_AGENT, ...initHeaders };\n}\n\nexport const sdkFetch: typeof fetch = (input, init) =>\n fetch(input, { ...init, headers: withUserAgent(init?.headers) });\n","import type { ApiErrorResponse } from './types';\n\n/** Base error class for AstraSync SDK errors. */\nexport class AstraSyncError extends Error {\n public readonly code?: string;\n public readonly statusCode: number;\n\n constructor(message: string, statusCode: number, code?: string) {\n super(message);\n this.name = 'AstraSyncError';\n this.statusCode = statusCode;\n this.code = code;\n }\n}\n\n/** Thrown when KYD verification is required before agent registration. */\nexport class KYDRequiredError extends AstraSyncError {\n public readonly kydUrl: string;\n public readonly ownerNotified: boolean;\n\n constructor(response: ApiErrorResponse) {\n const kydUrl = response.kydUrl || 'https://astrasync.ai/developer-profile';\n super(\n `KYD verification required before registering agents.\\nComplete your KYD profile at: ${kydUrl}`,\n 403,\n 'KYD_REQUIRED'\n );\n this.name = 'KYDRequiredError';\n this.kydUrl = kydUrl;\n this.ownerNotified = response.ownerNotified || false;\n }\n}\n\n/** Thrown when authentication fails. */\nexport class AuthenticationError extends AstraSyncError {\n constructor(message: string) {\n super(message, 401, 'AUTH_FAILED');\n this.name = 'AuthenticationError';\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the owner denies the\n * pending registration request. The `reason` field, when present, mirrors the\n * deny note the owner left in the dashboard.\n */\nexport class RegistrationDeniedError extends AstraSyncError {\n public readonly requestId: string;\n public readonly reason?: string;\n\n constructor(requestId: string, reason?: string) {\n super(\n `Registration request ${requestId} was denied by the account owner.${reason ? ` Reason: ${reason}` : ''}`,\n 403,\n 'REGISTRATION_DENIED'\n );\n this.name = 'RegistrationDeniedError';\n this.requestId = requestId;\n this.reason = reason;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the pending request\n * passes its 14-day TTL with no owner decision. The agent must re-submit.\n */\nexport class RegistrationExpiredError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Registration request ${requestId} expired before the owner approved it. Submit a new registration request.`,\n 410,\n 'REGISTRATION_EXPIRED'\n );\n this.name = 'RegistrationExpiredError';\n this.requestId = requestId;\n }\n}\n\n/**\n * Thrown by `register({ waitForApproval: true })` when the caller's local\n * `timeoutMs` elapses before the owner makes a decision. The request is still\n * live server-side — poll `pollRegistration(requestId)` to resume waiting, or\n * call `waitForApproval` again with a longer timeout.\n */\nexport class RegistrationTimeoutError extends AstraSyncError {\n public readonly requestId: string;\n\n constructor(requestId: string) {\n super(\n `Timed out waiting for owner approval of registration request ${requestId}. The request is still active server-side; poll the request to resume waiting.`,\n 408,\n 'REGISTRATION_TIMEOUT'\n );\n this.name = 'RegistrationTimeoutError';\n this.requestId = requestId;\n }\n}\n","import { sdkFetch } from '../http';\nimport type {\n AstraSyncConfig,\n RegisterOptions,\n RegisterResult,\n WaitForApprovalOptions,\n PendingRegistrationResponse,\n PollRegistrationResult,\n RegistrationResponse,\n VerifyResponse,\n HealthResponse,\n ApiErrorResponse,\n AgentRecord,\n} from './types';\nimport {\n AstraSyncError,\n KYDRequiredError,\n AuthenticationError,\n RegistrationDeniedError,\n RegistrationExpiredError,\n RegistrationTimeoutError,\n} from './errors';\n\nconst DEFAULT_BASE_URL = 'https://astrasync.ai';\n\nconst sleep = (ms: number): Promise<void> => new Promise((r) => setTimeout(r, ms));\n\n/**\n * AstraSync SDK client for registering and managing AI agents.\n *\n * @example\n * ```typescript\n * const client = new AstraSync({ apiKey: 'kya_your_api_key' });\n * const result = await client.register({\n * name: 'My Agent',\n * model: { modelName: 'gpt-4o', modelProvider: 'openai', modelType: 'llm' },\n * });\n * ```\n *\n * For staging, pass `baseUrl: 'https://staging.astrasync.ai'`.\n */\nexport class AstraSync {\n private readonly baseUrl: string;\n private readonly apiKey?: string;\n private readonly email?: string;\n private readonly password?: string;\n private readonly privateKey?: string;\n private cachedJwt?: string;\n private jwtExpiresAt?: number;\n\n constructor(config: AstraSyncConfig = {}) {\n let raw = (config.baseUrl || process.env.ASTRASYNC_API_URL || DEFAULT_BASE_URL).replace(\n /\\/+$/,\n ''\n );\n // Round-10 (O2): tolerate the verify-side convention. `GatewayConfig.apiBaseUrl`\n // is documented as `https://astrasync.ai/api` (with /api), but\n // `AstraSyncConfig.baseUrl` is documented as the bare origin. Partners\n // passing the verify-style URL to the registration client hit a 404\n // because we'd then append `/api/agents/register` → double /api. Strip\n // a trailing `/api` and warn once so the partner can fix the source.\n if (raw.toLowerCase().endsWith('/api')) {\n raw = raw.slice(0, -'/api'.length);\n if (config.baseUrl && !config.silent) {\n // eslint-disable-next-line no-console\n console.warn(\n `[AstraSync] baseUrl '${config.baseUrl}' had a trailing /api — stripped to '${raw}'. ` +\n `Pass the bare origin (e.g. 'https://astrasync.ai' or 'https://staging.astrasync.ai') ` +\n `to AstraSync(). The /api suffix is the verify-gateway (GatewayConfig.apiBaseUrl) convention.`\n );\n }\n }\n this.baseUrl = raw;\n\n // Env fallback is opt-OUT: server-side wrappers (MCP tool handlers,\n // gateway adapters) pass `disableEnvFallback: true` so a no-credentials\n // call from a user-facing flow cannot silently authenticate as the host\n // process's platform-attribution key. CLIs / scripts that legitimately\n // rely on ASTRASYNC_API_KEY keep working under the default.\n this.apiKey = config.disableEnvFallback\n ? config.apiKey\n : config.apiKey || process.env.ASTRASYNC_API_KEY;\n this.email = config.email;\n this.password = config.password;\n this.privateKey = config.privateKey;\n\n // Defense-in-depth: warn when env fallback actually fires under the\n // default (non-strict) config. Surfaces the \"I'm running as platform\"\n // foot-gun before it becomes a security bug. Gated by !silent.\n if (\n !config.apiKey &&\n !config.disableEnvFallback &&\n process.env.ASTRASYNC_API_KEY &&\n !config.silent\n ) {\n // eslint-disable-next-line no-console\n console.warn(\n '[AstraSync] No apiKey passed to constructor; using process.env.ASTRASYNC_API_KEY. ' +\n 'If this code wraps user-facing flows (e.g. MCP tool handlers), pass ' +\n 'disableEnvFallback: true to prevent ambient credentials from impersonating callers. ' +\n 'See https://astrasync.ai/docs/agent-access#disableenvfallback for details.'\n );\n }\n\n if (!this.apiKey && !this.email) {\n throw new AuthenticationError(\n 'Authentication required. Provide apiKey, or email+password. ' +\n 'Set ASTRASYNC_API_KEY env var or pass config to constructor.'\n );\n }\n\n if (this.email && !this.password) {\n throw new AuthenticationError('Password is required when using email authentication.');\n }\n }\n\n /**\n * Register a new AI agent on the AstraSync KYA Platform.\n *\n * The backend response depends on auth context:\n * - **Crypto-keypair signed** (`privateKey` configured): synchronous 201,\n * returns `{ status: 'active', agent }`.\n * - **API-key only** (no signature): 202 pending, returns\n * `{ status: 'pending_approval', requestId, pollUrl, expiresAt }`. The\n * owner is notified by email and a dashboard alert is emitted; the agent\n * becomes active only after the owner approves.\n *\n * Blocking mode: pass `{ waitForApproval: true }` to have the SDK poll the\n * request until it resolves, then return the live agent record. The promise\n * rejects with `RegistrationDeniedError`, `RegistrationExpiredError`, or\n * `RegistrationTimeoutError` on the corresponding terminal states.\n *\n * @example Non-blocking (default — best for serverless / scheduled agents):\n * ```typescript\n * const result = await sdk.register({ name, pdlss });\n * if (result.status === 'pending_approval') {\n * storeRequestId(result.requestId);\n * return; // function exits; resume later via pollRegistration()\n * }\n * ```\n *\n * @example Blocking (best for long-running services + CLI):\n * ```typescript\n * const agent = await sdk.register({\n * name, pdlss, waitForApproval: true, timeoutMs: 600_000,\n * onPending: ({ ageMs }) => console.log(`waiting ${ageMs}ms`),\n * });\n * ```\n */\n async register(\n options: RegisterOptions & WaitForApprovalOptions\n ): Promise<RegisterResult | AgentRecord> {\n const body: Record<string, unknown> = {\n name: options.name,\n ...(options.description && { description: options.description }),\n ...(options.agentType && { agentType: options.agentType }),\n ...(options.apiEndpoint && { apiEndpoint: options.apiEndpoint }),\n ...(options.model && { model: options.model }),\n ...(options.framework && { framework: options.framework }),\n ...(options.protocols && { protocols: options.protocols }),\n ...(options.metadata && { metadata: options.metadata }),\n ...(options.pdlss && { pdlss: options.pdlss }),\n };\n\n const { status, body: raw } = await this.requestWithStatus<\n RegistrationResponse | PendingRegistrationResponse\n >('POST', '/api/agents/register', body);\n\n if (status === 201) {\n const activeBody = raw as RegistrationResponse;\n const active: RegisterResult = {\n status: 'active',\n agent: activeBody.data.agent,\n // Round-12 (F16): pass backend advisories through verbatim.\n // Pre-fix the SDK whitelisted five fields and silently dropped\n // `warnings`, which left partners with no signal that\n // `no_callback_endpoint` (or future advisories) had fired.\n ...(activeBody.warnings && { warnings: activeBody.warnings }),\n };\n return active;\n }\n\n // 202 Accepted — owner approval required.\n const pendingBody = raw as PendingRegistrationResponse;\n const pending: RegisterResult = {\n status: 'pending_approval',\n requestId: pendingBody.requestId,\n expiresAt: pendingBody.expiresAt,\n pollUrl: pendingBody.pollUrl,\n message: pendingBody.message,\n // Round-12 (F16): same pass-through on the pending path.\n ...(pendingBody.warnings && { warnings: pendingBody.warnings }),\n };\n\n if (!options.waitForApproval) return pending;\n\n return this.waitForApproval(pendingBody.requestId, options);\n }\n\n /**\n * Poll the current state of a pending-approval registration request.\n *\n * Useful for caller-driven polling when `waitForApproval: false` (the\n * default). The endpoint is unauthenticated — pass the `requestId` that\n * was returned from the 202 response.\n *\n * @returns `state: 'pending'` while awaiting; `'approved'` carries the\n * minted agent in `agent`; `'denied'` may carry the owner's\n * `reason`; `'expired'` is terminal after 14 days.\n */\n async pollRegistration(requestId: string): Promise<PollRegistrationResult> {\n const url = `${this.baseUrl}/api/agents/request-registration/${requestId}`;\n const res = await sdkFetch(url, { headers: { Accept: 'application/json' } });\n if (!res.ok) {\n const errBody = (await res.json().catch(() => ({}))) as ApiErrorResponse;\n throw new AstraSyncError(\n errBody.error || `pollRegistration failed: ${res.status}`,\n res.status,\n errBody.code\n );\n }\n return (await res.json()) as PollRegistrationResult;\n }\n\n /**\n * Block until a pending registration request resolves to a terminal state.\n * Resolves to the live `AgentRecord` on approval; rejects with the matching\n * Registration*Error on deny/expire/timeout. Usually called via\n * `register({ waitForApproval: true })`, but exposed for callers that want\n * to fire-and-forget the initial register call and resume waiting later\n * (e.g. after restoring a stored `requestId` on cold start).\n */\n async waitForApproval(\n requestId: string,\n options: WaitForApprovalOptions = {}\n ): Promise<AgentRecord> {\n const timeoutMs = options.timeoutMs ?? 10 * 60 * 1000;\n const pollIntervalMs = options.pollIntervalMs ?? 5_000;\n const start = Date.now();\n const deadline = start + timeoutMs;\n\n while (Date.now() < deadline) {\n const result = await this.pollRegistration(requestId);\n const ageMs = Date.now() - start;\n options.onPending?.({ requestId, ageMs });\n\n if (result.state === 'approved') {\n if (!result.agent) {\n throw new AstraSyncError(\n `Registration ${requestId} reported approved but no agent payload returned.`,\n 500\n );\n }\n return result.agent;\n }\n if (result.state === 'denied') {\n throw new RegistrationDeniedError(requestId, result.reason);\n }\n if (result.state === 'expired') {\n throw new RegistrationExpiredError(requestId);\n }\n await sleep(pollIntervalMs);\n }\n throw new RegistrationTimeoutError(requestId);\n }\n\n /**\n * Look up an agent's public profile by ASTRA ID or UUID.\n */\n async verify(agentId: string): Promise<VerifyResponse> {\n return this.request<VerifyResponse>('GET', `/api/agents/verify/${agentId}`);\n }\n\n /**\n * Check API health.\n */\n async health(): Promise<HealthResponse> {\n const res = await sdkFetch(`${this.baseUrl}/api/health/`);\n if (!res.ok) {\n throw new AstraSyncError(`Health check failed: ${res.status}`, res.status);\n }\n return res.json() as Promise<HealthResponse>;\n }\n\n // ── Private helpers ──────────────────────────────────────────────\n\n private async request<T>(method: string, endpoint: string, body?: unknown): Promise<T> {\n const { body: parsed } = await this.requestWithStatus<T>(method, endpoint, body);\n return parsed;\n }\n\n /**\n * Variant of {@link request} that also returns the HTTP status code, so\n * callers can branch on 201 vs 202 (or other success codes) without losing\n * type information about the response body.\n */\n private async requestWithStatus<T>(\n method: string,\n endpoint: string,\n body?: unknown\n ): Promise<{ status: number; body: T }> {\n const url = `${this.baseUrl}${endpoint}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n };\n\n // Set auth header\n const token = await this.getAuthToken();\n headers['Authorization'] = `Bearer ${token}`;\n\n // Sign request if private key is configured\n if (this.privateKey) {\n const signature = await this.signRequest(method, endpoint, body || {});\n headers['X-AstraSync-Signature'] = signature;\n }\n\n const res = await sdkFetch(url, {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n });\n\n if (!res.ok) {\n const errorBody = (await res\n .json()\n .catch(() => ({ error: res.statusText }))) as ApiErrorResponse;\n\n // Handle KYD_REQUIRED specifically\n if (res.status === 403 && errorBody.code === 'KYD_REQUIRED') {\n throw new KYDRequiredError(errorBody);\n }\n\n throw new AstraSyncError(\n errorBody.error || `Request failed: ${res.status}`,\n res.status,\n errorBody.code\n );\n }\n\n return { status: res.status, body: (await res.json()) as T };\n }\n\n private async getAuthToken(): Promise<string> {\n // API key auth — use directly\n if (this.apiKey) {\n return this.apiKey;\n }\n\n // Email+password — login and cache JWT\n if (this.cachedJwt && this.jwtExpiresAt && Date.now() < this.jwtExpiresAt) {\n return this.cachedJwt;\n }\n\n const res = await sdkFetch(`${this.baseUrl}/api/auth/login`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ email: this.email, password: this.password }),\n });\n\n if (!res.ok) {\n const errorBody = (await res.json().catch(() => ({}))) as Record<string, unknown>;\n throw new AuthenticationError(\n (errorBody.message as string) || (errorBody.error as string) || 'Login failed'\n );\n }\n\n const data = (await res.json()) as { data: { token: string } };\n this.cachedJwt = data.data.token;\n // Cache for 6 days (tokens expire in 7)\n this.jwtExpiresAt = Date.now() + 6 * 24 * 60 * 60 * 1000;\n\n return this.cachedJwt;\n }\n\n /**\n * Sign a request using secp256k1 (ethers.js).\n * Canonical message format: METHOD:ENDPOINT:SORTED_JSON_BODY\n * Must match apps/backend/src/services/signature-verify.service.ts exactly.\n */\n private async signRequest(method: string, endpoint: string, body: unknown): Promise<string> {\n const { Wallet } = await import('ethers');\n const sorted = this.sortObjectKeys(body);\n const canonical = `${method}:${endpoint}:${JSON.stringify(sorted)}`;\n const wallet = new Wallet(this.privateKey!);\n return wallet.signMessage(canonical);\n }\n\n /** Recursively sort object keys for canonical JSON representation. */\n private sortObjectKeys(obj: unknown): unknown {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n if (Array.isArray(obj)) {\n return obj.map((item) => this.sortObjectKeys(item));\n }\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(obj).sort()) {\n sorted[key] = this.sortObjectKeys((obj as Record<string, unknown>)[key]);\n }\n return sorted;\n }\n}\n","/**\n * Guidance envelope for credentials-required cases.\n *\n * A single shared source of truth so partners writing their own wrappers\n * (custom MCP servers, Express middleware around registration, gateway\n * adapters) consume a single source of truth instead of re-implementing the\n * five-step boilerplate.\n *\n * The envelope is what an agent (or wrapping MCP client) sees when it calls\n * `register_agent` with no AstraSync credentials. It tells the calling agent\n * (a) what failed (`status: 'credentials_required'`), (b) the keyless\n * registration ACTION endpoint (`registrationUrl` — POST-able, not the human\n * dashboard), (c) where the relevant docs are (`documentationUrl`), and (d) the\n * ordered next-actions (`steps`).\n */\n\nexport interface GuidanceEnvelope {\n /**\n * Single-literal today. Expand to a union (e.g.\n * `'credentials_required' | 'kyd_required' | …`) when a second guidance\n * status emerges. Don't pre-emptively widen — the literal pins the shape.\n */\n status: 'credentials_required';\n message: string;\n guidance: {\n message: string;\n registrationUrl: string;\n documentationUrl: string;\n steps: string[];\n };\n}\n\nexport interface BuildGuidanceParams {\n /**\n * Bare origin of the AstraSync deployment the caller should register at,\n * e.g. `https://astrasync.ai` or `https://staging.astrasync.ai`. No\n * trailing slash, no `/api` suffix — registrationUrl and documentationUrl\n * are templated relative to this origin.\n */\n origin: string;\n /**\n * Overrides the top-level `message` (the short summary the agent sees).\n * Defaults to the error message from the SDK's `AuthenticationError`\n * when present, else a generic \"credentials required\" line.\n */\n message?: string;\n /**\n * Overrides the documentation path. Defaults to `/docs/agent-access`.\n */\n documentationPath?: string;\n}\n\n/**\n * Build the credentials-required guidance envelope.\n *\n * This is the canonical builder — MCP wrappers (`agent-registration.ts`),\n * Express middleware in custom integrations, and any other partner-side\n * wrapper that needs to surface \"you need to register\" should call this\n * rather than reconstructing the shape inline. Inline reconstruction\n * historically led to drift between wrappers; this consolidates it.\n *\n * @example\n * ```ts\n * import { buildGuidance } from '@astrasyncai/verification-gateway';\n *\n * try {\n * const sdk = new AstraSync({ apiKey: callerApiKey, disableEnvFallback: true });\n * // ...\n * } catch (err) {\n * if (err instanceof AuthenticationError) {\n * return buildGuidance({ origin: 'https://astrasync.ai', message: err.message });\n * }\n * throw err;\n * }\n * ```\n */\nexport function buildGuidance(params: BuildGuidanceParams): GuidanceEnvelope {\n const origin = params.origin.replace(/\\/+$/, '');\n const docsPath = params.documentationPath ?? '/docs/agent-access';\n const message = params.message ?? 'AstraSync registration requires credentials.';\n\n return {\n status: 'credentials_required',\n message,\n guidance: {\n message:\n \"Register either with an agent-scoped API key (the recommended credentialed path) OR, if you hold no credentials, via the owner's email using request_registration. Never send a password or private key over the wire.\",\n // 3.0.0: registrationUrl is the agent-actionable KEYLESS endpoint, not the\n // human dashboard `/agents/register` (an auth-walled page an agent can't\n // use). documentationUrl carries the machine-readable contract.\n registrationUrl: `${origin}/api/agents/request-registration`,\n documentationUrl: `${origin}${docsPath.startsWith('/') ? docsPath : `/${docsPath}`}`,\n steps: [\n 'Credentialed path (recommended): have your human mint an agent-scoped API key at Settings → API Keys, then re-call register_agent with apiKey set. An agent holding its own scoped kya_ key is fine and intended.',\n \"No-credentials path: call request_registration({ name, ownerEmail, ... }) with the human owner's email — the only bootstrap credential. No API key is involved.\",\n 'Include as much metadata as you can in the registration — especially model ({ modelName, modelProvider }) and framework ({ frameworkName, frameworkVersion }). Declared platform/model metadata directly improves your trust score and attributes your traffic correctly.',\n 'The owner approves via an emailed link (first time, they create an account and complete a quick verification).',\n 'Use poll_registration({ requestId }) once the owner confirms approval to retrieve the astraId.',\n 'Never transmit a password or private key over the MCP wire — those are never required.',\n ],\n },\n };\n}\n"],"mappings":"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","names":["has"]}
@@ -1,5 +1,5 @@
1
1
  // src/version.ts
2
- var SDK_VERSION = "4.6.0";
2
+ var SDK_VERSION = "5.0.0";
3
3
 
4
4
  // src/http.ts
5
5
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;