@astrasyncai/verification-gateway 5.17.1 → 5.18.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 (103) hide show
  1. package/CHANGELOG.md +1849 -0
  2. package/README.md +141 -7
  3. package/dist/adapters/express.d.mts +1 -1
  4. package/dist/adapters/express.d.ts +1 -1
  5. package/dist/adapters/express.js +30 -12
  6. package/dist/adapters/express.js.map +1 -1
  7. package/dist/adapters/express.mjs +30 -12
  8. package/dist/adapters/express.mjs.map +1 -1
  9. package/dist/adapters/kit-express.d.mts +63 -0
  10. package/dist/adapters/kit-express.d.ts +63 -0
  11. package/dist/adapters/kit-express.js +88 -0
  12. package/dist/adapters/kit-express.js.map +1 -0
  13. package/dist/adapters/kit-express.mjs +61 -0
  14. package/dist/adapters/kit-express.mjs.map +1 -0
  15. package/dist/adapters/mcp.d.mts +1 -1
  16. package/dist/adapters/mcp.d.ts +1 -1
  17. package/dist/adapters/mcp.js +1 -1
  18. package/dist/adapters/mcp.js.map +1 -1
  19. package/dist/adapters/mcp.mjs +1 -1
  20. package/dist/adapters/mcp.mjs.map +1 -1
  21. package/dist/adapters/nextjs.d.mts +1 -1
  22. package/dist/adapters/nextjs.d.ts +1 -1
  23. package/dist/adapters/nextjs.js +18 -8
  24. package/dist/adapters/nextjs.js.map +1 -1
  25. package/dist/adapters/nextjs.mjs +18 -8
  26. package/dist/adapters/nextjs.mjs.map +1 -1
  27. package/dist/adapters/sdk.d.mts +1 -1
  28. package/dist/adapters/sdk.d.ts +1 -1
  29. package/dist/adapters/sdk.js +1 -1
  30. package/dist/adapters/sdk.js.map +1 -1
  31. package/dist/adapters/sdk.mjs +1 -1
  32. package/dist/adapters/sdk.mjs.map +1 -1
  33. package/dist/agent/index.js +1 -1
  34. package/dist/agent/index.js.map +1 -1
  35. package/dist/agent/index.mjs +1 -1
  36. package/dist/agent/index.mjs.map +1 -1
  37. package/dist/bin/astrasync-claude-hook.js +1 -1
  38. package/dist/bin/astrasync-codex-hook.js +1 -1
  39. package/dist/bin/astrasync-guard.js +3 -1
  40. package/dist/bin/astrasync.js +21 -1
  41. package/dist/browser/background.js +1 -1
  42. package/dist/browser/background.js.map +1 -1
  43. package/dist/browser/background.mjs +1 -1
  44. package/dist/browser/background.mjs.map +1 -1
  45. package/dist/cli/index.js +1 -1
  46. package/dist/cli/index.js.map +1 -1
  47. package/dist/cli/index.mjs +1 -1
  48. package/dist/cli/index.mjs.map +1 -1
  49. package/dist/codex/index.js +1 -1
  50. package/dist/codex/index.js.map +1 -1
  51. package/dist/codex/index.mjs +1 -1
  52. package/dist/codex/index.mjs.map +1 -1
  53. package/dist/cursor/extension.js +1 -1
  54. package/dist/cursor/extension.js.map +1 -1
  55. package/dist/cursor/extension.mjs +1 -1
  56. package/dist/cursor/extension.mjs.map +1 -1
  57. package/dist/edge-config.d.mts +1 -1
  58. package/dist/edge-config.d.ts +1 -1
  59. package/dist/edge-config.js +1 -1
  60. package/dist/edge-config.js.map +1 -1
  61. package/dist/edge-config.mjs +1 -1
  62. package/dist/edge-config.mjs.map +1 -1
  63. package/dist/edge-core/index.d.mts +5 -4
  64. package/dist/edge-core/index.d.ts +5 -4
  65. package/dist/edge-core/index.js +18 -8
  66. package/dist/edge-core/index.js.map +1 -1
  67. package/dist/edge-core/index.mjs +18 -8
  68. package/dist/edge-core/index.mjs.map +1 -1
  69. package/dist/gateway/gateway.js +1 -1
  70. package/dist/gateway/gateway.js.map +1 -1
  71. package/dist/gateway/gateway.mjs +1 -1
  72. package/dist/gateway/gateway.mjs.map +1 -1
  73. package/dist/git-trigger/git-hooks.d.mts +1 -1
  74. package/dist/git-trigger/git-hooks.d.ts +1 -1
  75. package/dist/index.d.mts +390 -12
  76. package/dist/index.d.ts +390 -12
  77. package/dist/index.js +766 -230
  78. package/dist/index.js.map +1 -1
  79. package/dist/index.mjs +749 -222
  80. package/dist/index.mjs.map +1 -1
  81. package/dist/registration/index.js +1 -1
  82. package/dist/registration/index.js.map +1 -1
  83. package/dist/registration/index.mjs +1 -1
  84. package/dist/registration/index.mjs.map +1 -1
  85. package/dist/transport/index.d.mts +4 -3
  86. package/dist/transport/index.d.ts +4 -3
  87. package/dist/transport/index.js +1 -1
  88. package/dist/transport/index.js.map +1 -1
  89. package/dist/transport/index.mjs +1 -1
  90. package/dist/transport/index.mjs.map +1 -1
  91. package/dist/{types-vNBvYD7Z.d.mts → types-3ObBpsnf.d.mts} +7 -0
  92. package/dist/{types-DA8LzAOB.d.ts → types-BoxZEYPS.d.ts} +7 -0
  93. package/dist/{types-DRb_plOh.d.mts → types-Cns4l8gX.d.mts} +17 -0
  94. package/dist/{types-DRb_plOh.d.ts → types-Cns4l8gX.d.ts} +17 -0
  95. package/dist/ui/index.d.mts +1 -1
  96. package/dist/ui/index.d.ts +1 -1
  97. package/dist/verify.d.mts +1 -1
  98. package/dist/verify.d.ts +1 -1
  99. package/dist/verify.js +1 -1
  100. package/dist/verify.js.map +1 -1
  101. package/dist/verify.mjs +1 -1
  102. package/dist/verify.mjs.map +1 -1
  103. package/package.json +8 -2
@@ -0,0 +1,63 @@
1
+ /** Per-request context a host adapter (e.g. `expressHandler`) passes to `kit.handle`. */
2
+ interface KitRequestContext {
3
+ /**
4
+ * The caller's VERIFIED ASTRA-id (e.g. from `req.agentVerification` after
5
+ * the AstraSync middleware ran). Sessions and idempotency keys are scoped
6
+ * to it; without it the kit falls back to Authorization, then X-Astra-Id.
7
+ */
8
+ callerId?: string;
9
+ }
10
+
11
+ /**
12
+ * 5.18.0 — mount a fetch-style checkout kit (`createUcpCheckoutKit`,
13
+ * `createAcpCheckoutKit`) on Express.
14
+ *
15
+ * app.use('/ucp/v1', express.raw({ type: '*\/*' }), expressHandler(ucpKit));
16
+ *
17
+ * The kit checks RFC 9421 signatures and Content-Digest / idempotency
18
+ * fingerprints over the EXACT request bytes, so give it the raw body: mount
19
+ * `express.raw()` on the kit's routes (req.body is a Buffer), or keep a copy
20
+ * on `req.rawBody` (Buffer or string) in your JSON parser's `verify` hook.
21
+ * A body that was already parsed to an object is re-serialised with
22
+ * JSON.stringify — fine for unsigned traffic, but signatures won't verify.
23
+ *
24
+ * When the AstraSync middleware ran first, the caller's verified ASTRA-id
25
+ * (`req.agentVerification.agent.astraId`) scopes sessions and idempotency
26
+ * keys; override with `callerId`.
27
+ */
28
+
29
+ /** Anything with a fetch-style `handle` (both checkout kits). */
30
+ interface FetchKit {
31
+ handle(req: Request, ctx?: KitRequestContext): Promise<Response>;
32
+ }
33
+ /** The parts of an Express request this adapter reads. */
34
+ interface KitExpressRequest {
35
+ method: string;
36
+ protocol?: string;
37
+ originalUrl?: string;
38
+ url: string;
39
+ headers: Record<string, string | string[] | undefined>;
40
+ body?: unknown;
41
+ rawBody?: unknown;
42
+ get?(name: string): string | undefined;
43
+ agentVerification?: {
44
+ identityVerified?: boolean;
45
+ agent?: {
46
+ astraId?: string;
47
+ };
48
+ };
49
+ }
50
+ /** The parts of an Express response this adapter writes. */
51
+ interface KitExpressResponse {
52
+ status(code: number): unknown;
53
+ setHeader(name: string, value: string | string[]): unknown;
54
+ end(body?: unknown): unknown;
55
+ }
56
+ interface ExpressHandlerOptions {
57
+ /** The caller's verified ASTRA-id (default: from `req.agentVerification` when identity-verified). */
58
+ callerId?: (req: KitExpressRequest) => string | undefined;
59
+ }
60
+ /** An Express handler that runs a checkout kit and writes its Response back. */
61
+ declare function expressHandler(kit: FetchKit, options?: ExpressHandlerOptions): (req: KitExpressRequest, res: KitExpressResponse, next: (err?: unknown) => void) => Promise<void>;
62
+
63
+ export { type ExpressHandlerOptions, type FetchKit, type KitExpressRequest, type KitExpressResponse, expressHandler };
@@ -0,0 +1,63 @@
1
+ /** Per-request context a host adapter (e.g. `expressHandler`) passes to `kit.handle`. */
2
+ interface KitRequestContext {
3
+ /**
4
+ * The caller's VERIFIED ASTRA-id (e.g. from `req.agentVerification` after
5
+ * the AstraSync middleware ran). Sessions and idempotency keys are scoped
6
+ * to it; without it the kit falls back to Authorization, then X-Astra-Id.
7
+ */
8
+ callerId?: string;
9
+ }
10
+
11
+ /**
12
+ * 5.18.0 — mount a fetch-style checkout kit (`createUcpCheckoutKit`,
13
+ * `createAcpCheckoutKit`) on Express.
14
+ *
15
+ * app.use('/ucp/v1', express.raw({ type: '*\/*' }), expressHandler(ucpKit));
16
+ *
17
+ * The kit checks RFC 9421 signatures and Content-Digest / idempotency
18
+ * fingerprints over the EXACT request bytes, so give it the raw body: mount
19
+ * `express.raw()` on the kit's routes (req.body is a Buffer), or keep a copy
20
+ * on `req.rawBody` (Buffer or string) in your JSON parser's `verify` hook.
21
+ * A body that was already parsed to an object is re-serialised with
22
+ * JSON.stringify — fine for unsigned traffic, but signatures won't verify.
23
+ *
24
+ * When the AstraSync middleware ran first, the caller's verified ASTRA-id
25
+ * (`req.agentVerification.agent.astraId`) scopes sessions and idempotency
26
+ * keys; override with `callerId`.
27
+ */
28
+
29
+ /** Anything with a fetch-style `handle` (both checkout kits). */
30
+ interface FetchKit {
31
+ handle(req: Request, ctx?: KitRequestContext): Promise<Response>;
32
+ }
33
+ /** The parts of an Express request this adapter reads. */
34
+ interface KitExpressRequest {
35
+ method: string;
36
+ protocol?: string;
37
+ originalUrl?: string;
38
+ url: string;
39
+ headers: Record<string, string | string[] | undefined>;
40
+ body?: unknown;
41
+ rawBody?: unknown;
42
+ get?(name: string): string | undefined;
43
+ agentVerification?: {
44
+ identityVerified?: boolean;
45
+ agent?: {
46
+ astraId?: string;
47
+ };
48
+ };
49
+ }
50
+ /** The parts of an Express response this adapter writes. */
51
+ interface KitExpressResponse {
52
+ status(code: number): unknown;
53
+ setHeader(name: string, value: string | string[]): unknown;
54
+ end(body?: unknown): unknown;
55
+ }
56
+ interface ExpressHandlerOptions {
57
+ /** The caller's verified ASTRA-id (default: from `req.agentVerification` when identity-verified). */
58
+ callerId?: (req: KitExpressRequest) => string | undefined;
59
+ }
60
+ /** An Express handler that runs a checkout kit and writes its Response back. */
61
+ declare function expressHandler(kit: FetchKit, options?: ExpressHandlerOptions): (req: KitExpressRequest, res: KitExpressResponse, next: (err?: unknown) => void) => Promise<void>;
62
+
63
+ export { type ExpressHandlerOptions, type FetchKit, type KitExpressRequest, type KitExpressResponse, expressHandler };
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/adapters/kit-express.ts
21
+ var kit_express_exports = {};
22
+ __export(kit_express_exports, {
23
+ expressHandler: () => expressHandler
24
+ });
25
+ module.exports = __toCommonJS(kit_express_exports);
26
+
27
+ // src/ucp/kit-shared.ts
28
+ var warned = /* @__PURE__ */ new Set();
29
+ function warnOnce(key, message) {
30
+ if (warned.has(key) || process.env.NODE_ENV === "test") return;
31
+ warned.add(key);
32
+ console.warn(message);
33
+ }
34
+
35
+ // src/adapters/kit-express.ts
36
+ var bytes = (b) => b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
37
+ function rawBodyOf(req) {
38
+ if (req.method === "GET" || req.method === "HEAD") return void 0;
39
+ const raw = req.rawBody;
40
+ if (Buffer.isBuffer(raw)) return bytes(raw);
41
+ if (typeof raw === "string") return raw;
42
+ if (Buffer.isBuffer(req.body)) return bytes(req.body);
43
+ if (typeof req.body === "string") return req.body;
44
+ if (req.body !== void 0 && req.body !== null && typeof req.body === "object") {
45
+ if (Object.keys(req.body).length === 0) return void 0;
46
+ warnOnce(
47
+ "kit-express-parsed-body",
48
+ "[astrasync] expressHandler: the request body was already parsed \u2014 re-serialising it. Mount express.raw() on the checkout routes (or keep req.rawBody) so signatures and idempotency fingerprints see the exact bytes."
49
+ );
50
+ return JSON.stringify(req.body);
51
+ }
52
+ return void 0;
53
+ }
54
+ function expressHandler(kit, options = {}) {
55
+ return async (req, res, next) => {
56
+ try {
57
+ const host = req.get?.("host") ?? req.headers.host ?? "localhost";
58
+ const url = `${req.protocol ?? "http"}://${host}${req.originalUrl ?? req.url}`;
59
+ const headers = new Headers();
60
+ for (const [k, v] of Object.entries(req.headers)) {
61
+ if (v === void 0) continue;
62
+ if (Array.isArray(v)) v.forEach((x) => headers.append(k, x));
63
+ else headers.set(k, v);
64
+ }
65
+ const body = rawBodyOf(req);
66
+ const request = new Request(url, {
67
+ method: req.method,
68
+ headers,
69
+ ...body !== void 0 && { body }
70
+ });
71
+ const verified = req.agentVerification?.identityVerified ? req.agentVerification.agent?.astraId : void 0;
72
+ const callerId = options.callerId ? options.callerId(req) : verified;
73
+ const response = await kit.handle(request, callerId ? { callerId } : void 0);
74
+ res.status(response.status);
75
+ response.headers.forEach((value, name) => {
76
+ res.setHeader(name, value);
77
+ });
78
+ res.end(Buffer.from(await response.arrayBuffer()));
79
+ } catch (err) {
80
+ next(err);
81
+ }
82
+ };
83
+ }
84
+ // Annotate the CommonJS export names for ESM import in node:
85
+ 0 && (module.exports = {
86
+ expressHandler
87
+ });
88
+ //# sourceMappingURL=kit-express.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/adapters/kit-express.ts","../../src/ucp/kit-shared.ts"],"sourcesContent":["/**\n * 5.18.0 — mount a fetch-style checkout kit (`createUcpCheckoutKit`,\n * `createAcpCheckoutKit`) on Express.\n *\n * app.use('/ucp/v1', express.raw({ type: '*\\/*' }), expressHandler(ucpKit));\n *\n * The kit checks RFC 9421 signatures and Content-Digest / idempotency\n * fingerprints over the EXACT request bytes, so give it the raw body: mount\n * `express.raw()` on the kit's routes (req.body is a Buffer), or keep a copy\n * on `req.rawBody` (Buffer or string) in your JSON parser's `verify` hook.\n * A body that was already parsed to an object is re-serialised with\n * JSON.stringify — fine for unsigned traffic, but signatures won't verify.\n *\n * When the AstraSync middleware ran first, the caller's verified ASTRA-id\n * (`req.agentVerification.agent.astraId`) scopes sessions and idempotency\n * keys; override with `callerId`.\n */\nimport type { KitRequestContext } from '../ucp/kit-shared';\nimport { warnOnce } from '../ucp/kit-shared';\n\n/** Anything with a fetch-style `handle` (both checkout kits). */\nexport interface FetchKit {\n handle(req: Request, ctx?: KitRequestContext): Promise<Response>;\n}\n\n/** The parts of an Express request this adapter reads. */\nexport interface KitExpressRequest {\n method: string;\n protocol?: string;\n originalUrl?: string;\n url: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: unknown;\n get?(name: string): string | undefined;\n agentVerification?: {\n identityVerified?: boolean;\n agent?: { astraId?: string };\n };\n}\n\n/** The parts of an Express response this adapter writes. */\nexport interface KitExpressResponse {\n status(code: number): unknown;\n setHeader(name: string, value: string | string[]): unknown;\n end(body?: unknown): unknown;\n}\n\nexport interface ExpressHandlerOptions {\n /** The caller's verified ASTRA-id (default: from `req.agentVerification` when identity-verified). */\n callerId?: (req: KitExpressRequest) => string | undefined;\n}\n\nconst bytes = (b: Buffer): ArrayBuffer =>\n b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength) as ArrayBuffer;\n\nfunction rawBodyOf(req: KitExpressRequest): string | ArrayBuffer | undefined {\n if (req.method === 'GET' || req.method === 'HEAD') return undefined;\n const raw = req.rawBody;\n if (Buffer.isBuffer(raw)) return bytes(raw);\n if (typeof raw === 'string') return raw;\n if (Buffer.isBuffer(req.body)) return bytes(req.body);\n if (typeof req.body === 'string') return req.body;\n if (req.body !== undefined && req.body !== null && typeof req.body === 'object') {\n if (Object.keys(req.body as object).length === 0) return undefined;\n warnOnce(\n 'kit-express-parsed-body',\n '[astrasync] expressHandler: the request body was already parsed — re-serialising it. ' +\n 'Mount express.raw() on the checkout routes (or keep req.rawBody) so signatures and ' +\n 'idempotency fingerprints see the exact bytes.'\n );\n return JSON.stringify(req.body);\n }\n return undefined;\n}\n\n/** An Express handler that runs a checkout kit and writes its Response back. */\nexport function expressHandler(kit: FetchKit, options: ExpressHandlerOptions = {}) {\n return async (\n req: KitExpressRequest,\n res: KitExpressResponse,\n next: (err?: unknown) => void\n ): Promise<void> => {\n try {\n const host = req.get?.('host') ?? (req.headers.host as string | undefined) ?? 'localhost';\n const url = `${req.protocol ?? 'http'}://${host}${req.originalUrl ?? req.url}`;\n const headers = new Headers();\n for (const [k, v] of Object.entries(req.headers)) {\n if (v === undefined) continue;\n if (Array.isArray(v)) v.forEach((x) => headers.append(k, x));\n else headers.set(k, v);\n }\n const body = rawBodyOf(req);\n const request = new Request(url, {\n method: req.method,\n headers,\n ...(body !== undefined && { body }),\n });\n const verified = req.agentVerification?.identityVerified\n ? req.agentVerification.agent?.astraId\n : undefined;\n const callerId = options.callerId ? options.callerId(req) : verified;\n const response = await kit.handle(request, callerId ? { callerId } : undefined);\n res.status(response.status);\n response.headers.forEach((value, name) => {\n res.setHeader(name, value);\n });\n res.end(Buffer.from(await response.arrayBuffer()));\n } catch (err) {\n next(err);\n }\n };\n}\n","/**\n * 5.18.0 — logic the UCP and ACP checkout kits share: the hold test, caller\n * scoping, the result kept for a pending settlement, and one-time warnings.\n */\nimport { createHash } from 'crypto';\nimport type { VerificationResult } from '../types';\n\n/** Per-request context a host adapter (e.g. `expressHandler`) passes to `kit.handle`. */\nexport interface KitRequestContext {\n /**\n * The caller's VERIFIED ASTRA-id (e.g. from `req.agentVerification` after\n * the AstraSync middleware ran). Sessions and idempotency keys are scoped\n * to it; without it the kit falls back to Authorization, then X-Astra-Id.\n */\n callerId?: string;\n}\n\n/**\n * True when AstraSync held the purchase for the buyer's approval. Any step-up\n * signal counts; an approval that was just redeemed (`status: 'consumed'`)\n * does not. A held purchase must never reach settle or fulfil.\n */\nexport function isHeld(result: VerificationResult): boolean {\n const r = result as VerificationResult & { recommendation?: string };\n return Boolean(\n r.requiresStepUp ||\n r.requiresApproval ||\n r.recommendation === 'step_up_required' ||\n r.settlementOutcome?.status === 'requires_approval' ||\n (r.stepUpApproval && r.stepUpApproval.status !== 'consumed')\n );\n}\n\nconst scopeHash = (kind: string, value: string) =>\n `${kind}:${createHash('sha256').update(`${kind}\\n${value}`).digest('hex').slice(0, 32)}`;\n\n/**\n * The scope a checkout session and its idempotency keys belong to: the\n * verified ASTRA-id when known, else the Authorization header, else the\n * X-Astra-Id header. Hashed, so no bearer token is ever written to a store.\n * Undefined when the request carries none of them.\n */\nexport async function resolveCallerScope(\n req: Request,\n ctx: KitRequestContext | undefined,\n resolve?: (req: Request) => string | undefined | Promise<string | undefined>\n): Promise<string | undefined> {\n const verified = ctx?.callerId ?? (resolve ? await resolve(req) : undefined);\n if (verified) return scopeHash('astra', verified);\n const auth = req.headers.get('authorization');\n if (auth) return scopeHash('auth', auth);\n const astraId = req.headers.get('x-astra-id');\n if (astraId) return scopeHash('astra-header', astraId);\n return undefined;\n}\n\n/** A scope for a fallback identity (e.g. the UCP platform profile). */\nexport const fallbackScope = (kind: string, value: string) => scopeHash(kind, value);\n\n/**\n * The verification result kept with a pending settlement, minus the\n * merchant-lane secrets (card settlement token, voucher, mandates, KYAPay\n * token, AEP payloads): a store must never hold payment material.\n */\nexport function pendingResult(result: VerificationResult): VerificationResult {\n const {\n settlementToken: _t,\n settlement: _s,\n mandates: _m,\n kyaToken: _k,\n aep: _a,\n ...rest\n } = result;\n return rest;\n}\n\nconst warned = new Set<string>();\n\n/** console.warn once per process per key (never under NODE_ENV=test). */\nexport function warnOnce(key: string, message: string): void {\n if (warned.has(key) || process.env.NODE_ENV === 'test') return;\n warned.add(key);\n // eslint-disable-next-line no-console\n console.warn(message);\n}\n\n/** Warn when a kit runs on its in-memory defaults outside tests. */\nexport function warnInMemoryStores(kit: 'UCP' | 'ACP', missing: string[]): void {\n if (!missing.length || process.env.NODE_ENV === 'test') return;\n // eslint-disable-next-line no-console\n console.warn(\n `[astrasync] ${kit} checkout kit is using the in-memory ${missing.join(' and ')} ` +\n '(sessions are lost on restart and not shared across instances). ' +\n `Pass ${missing.map((m) => (m.startsWith('idempotency') ? 'idempotencyStore' : 'store')).join(' and ')} in production.`\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;AC4EA,IAAM,SAAS,oBAAI,IAAY;AAGxB,SAAS,SAAS,KAAa,SAAuB;AAC3D,MAAI,OAAO,IAAI,GAAG,KAAK,QAAQ,IAAI,aAAa,OAAQ;AACxD,SAAO,IAAI,GAAG;AAEd,UAAQ,KAAK,OAAO;AACtB;;;AD/BA,IAAM,QAAQ,CAAC,MACb,EAAE,OAAO,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU;AAE1D,SAAS,UAAU,KAA0D;AAC3E,MAAI,IAAI,WAAW,SAAS,IAAI,WAAW,OAAQ,QAAO;AAC1D,QAAM,MAAM,IAAI;AAChB,MAAI,OAAO,SAAS,GAAG,EAAG,QAAO,MAAM,GAAG;AAC1C,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,MAAI,OAAO,SAAS,IAAI,IAAI,EAAG,QAAO,MAAM,IAAI,IAAI;AACpD,MAAI,OAAO,IAAI,SAAS,SAAU,QAAO,IAAI;AAC7C,MAAI,IAAI,SAAS,UAAa,IAAI,SAAS,QAAQ,OAAO,IAAI,SAAS,UAAU;AAC/E,QAAI,OAAO,KAAK,IAAI,IAAc,EAAE,WAAW,EAAG,QAAO;AACzD;AAAA,MACE;AAAA,MACA;AAAA,IAGF;AACA,WAAO,KAAK,UAAU,IAAI,IAAI;AAAA,EAChC;AACA,SAAO;AACT;AAGO,SAAS,eAAe,KAAe,UAAiC,CAAC,GAAG;AACjF,SAAO,OACL,KACA,KACA,SACkB;AAClB,QAAI;AACF,YAAM,OAAO,IAAI,MAAM,MAAM,KAAM,IAAI,QAAQ,QAA+B;AAC9E,YAAM,MAAM,GAAG,IAAI,YAAY,MAAM,MAAM,IAAI,GAAG,IAAI,eAAe,IAAI,GAAG;AAC5E,YAAM,UAAU,IAAI,QAAQ;AAC5B,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AAChD,YAAI,MAAM,OAAW;AACrB,YAAI,MAAM,QAAQ,CAAC,EAAG,GAAE,QAAQ,CAAC,MAAM,QAAQ,OAAO,GAAG,CAAC,CAAC;AAAA,YACtD,SAAQ,IAAI,GAAG,CAAC;AAAA,MACvB;AACA,YAAM,OAAO,UAAU,GAAG;AAC1B,YAAM,UAAU,IAAI,QAAQ,KAAK;AAAA,QAC/B,QAAQ,IAAI;AAAA,QACZ;AAAA,QACA,GAAI,SAAS,UAAa,EAAE,KAAK;AAAA,MACnC,CAAC;AACD,YAAM,WAAW,IAAI,mBAAmB,mBACpC,IAAI,kBAAkB,OAAO,UAC7B;AACJ,YAAM,WAAW,QAAQ,WAAW,QAAQ,SAAS,GAAG,IAAI;AAC5D,YAAM,WAAW,MAAM,IAAI,OAAO,SAAS,WAAW,EAAE,SAAS,IAAI,MAAS;AAC9E,UAAI,OAAO,SAAS,MAAM;AAC1B,eAAS,QAAQ,QAAQ,CAAC,OAAO,SAAS;AACxC,YAAI,UAAU,MAAM,KAAK;AAAA,MAC3B,CAAC;AACD,UAAI,IAAI,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,WAAK,GAAG;AAAA,IACV;AAAA,EACF;AACF;","names":[]}
@@ -0,0 +1,61 @@
1
+ // src/ucp/kit-shared.ts
2
+ var warned = /* @__PURE__ */ new Set();
3
+ function warnOnce(key, message) {
4
+ if (warned.has(key) || process.env.NODE_ENV === "test") return;
5
+ warned.add(key);
6
+ console.warn(message);
7
+ }
8
+
9
+ // src/adapters/kit-express.ts
10
+ var bytes = (b) => b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
11
+ function rawBodyOf(req) {
12
+ if (req.method === "GET" || req.method === "HEAD") return void 0;
13
+ const raw = req.rawBody;
14
+ if (Buffer.isBuffer(raw)) return bytes(raw);
15
+ if (typeof raw === "string") return raw;
16
+ if (Buffer.isBuffer(req.body)) return bytes(req.body);
17
+ if (typeof req.body === "string") return req.body;
18
+ if (req.body !== void 0 && req.body !== null && typeof req.body === "object") {
19
+ if (Object.keys(req.body).length === 0) return void 0;
20
+ warnOnce(
21
+ "kit-express-parsed-body",
22
+ "[astrasync] expressHandler: the request body was already parsed \u2014 re-serialising it. Mount express.raw() on the checkout routes (or keep req.rawBody) so signatures and idempotency fingerprints see the exact bytes."
23
+ );
24
+ return JSON.stringify(req.body);
25
+ }
26
+ return void 0;
27
+ }
28
+ function expressHandler(kit, options = {}) {
29
+ return async (req, res, next) => {
30
+ try {
31
+ const host = req.get?.("host") ?? req.headers.host ?? "localhost";
32
+ const url = `${req.protocol ?? "http"}://${host}${req.originalUrl ?? req.url}`;
33
+ const headers = new Headers();
34
+ for (const [k, v] of Object.entries(req.headers)) {
35
+ if (v === void 0) continue;
36
+ if (Array.isArray(v)) v.forEach((x) => headers.append(k, x));
37
+ else headers.set(k, v);
38
+ }
39
+ const body = rawBodyOf(req);
40
+ const request = new Request(url, {
41
+ method: req.method,
42
+ headers,
43
+ ...body !== void 0 && { body }
44
+ });
45
+ const verified = req.agentVerification?.identityVerified ? req.agentVerification.agent?.astraId : void 0;
46
+ const callerId = options.callerId ? options.callerId(req) : verified;
47
+ const response = await kit.handle(request, callerId ? { callerId } : void 0);
48
+ res.status(response.status);
49
+ response.headers.forEach((value, name) => {
50
+ res.setHeader(name, value);
51
+ });
52
+ res.end(Buffer.from(await response.arrayBuffer()));
53
+ } catch (err) {
54
+ next(err);
55
+ }
56
+ };
57
+ }
58
+ export {
59
+ expressHandler
60
+ };
61
+ //# sourceMappingURL=kit-express.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/ucp/kit-shared.ts","../../src/adapters/kit-express.ts"],"sourcesContent":["/**\n * 5.18.0 — logic the UCP and ACP checkout kits share: the hold test, caller\n * scoping, the result kept for a pending settlement, and one-time warnings.\n */\nimport { createHash } from 'crypto';\nimport type { VerificationResult } from '../types';\n\n/** Per-request context a host adapter (e.g. `expressHandler`) passes to `kit.handle`. */\nexport interface KitRequestContext {\n /**\n * The caller's VERIFIED ASTRA-id (e.g. from `req.agentVerification` after\n * the AstraSync middleware ran). Sessions and idempotency keys are scoped\n * to it; without it the kit falls back to Authorization, then X-Astra-Id.\n */\n callerId?: string;\n}\n\n/**\n * True when AstraSync held the purchase for the buyer's approval. Any step-up\n * signal counts; an approval that was just redeemed (`status: 'consumed'`)\n * does not. A held purchase must never reach settle or fulfil.\n */\nexport function isHeld(result: VerificationResult): boolean {\n const r = result as VerificationResult & { recommendation?: string };\n return Boolean(\n r.requiresStepUp ||\n r.requiresApproval ||\n r.recommendation === 'step_up_required' ||\n r.settlementOutcome?.status === 'requires_approval' ||\n (r.stepUpApproval && r.stepUpApproval.status !== 'consumed')\n );\n}\n\nconst scopeHash = (kind: string, value: string) =>\n `${kind}:${createHash('sha256').update(`${kind}\\n${value}`).digest('hex').slice(0, 32)}`;\n\n/**\n * The scope a checkout session and its idempotency keys belong to: the\n * verified ASTRA-id when known, else the Authorization header, else the\n * X-Astra-Id header. Hashed, so no bearer token is ever written to a store.\n * Undefined when the request carries none of them.\n */\nexport async function resolveCallerScope(\n req: Request,\n ctx: KitRequestContext | undefined,\n resolve?: (req: Request) => string | undefined | Promise<string | undefined>\n): Promise<string | undefined> {\n const verified = ctx?.callerId ?? (resolve ? await resolve(req) : undefined);\n if (verified) return scopeHash('astra', verified);\n const auth = req.headers.get('authorization');\n if (auth) return scopeHash('auth', auth);\n const astraId = req.headers.get('x-astra-id');\n if (astraId) return scopeHash('astra-header', astraId);\n return undefined;\n}\n\n/** A scope for a fallback identity (e.g. the UCP platform profile). */\nexport const fallbackScope = (kind: string, value: string) => scopeHash(kind, value);\n\n/**\n * The verification result kept with a pending settlement, minus the\n * merchant-lane secrets (card settlement token, voucher, mandates, KYAPay\n * token, AEP payloads): a store must never hold payment material.\n */\nexport function pendingResult(result: VerificationResult): VerificationResult {\n const {\n settlementToken: _t,\n settlement: _s,\n mandates: _m,\n kyaToken: _k,\n aep: _a,\n ...rest\n } = result;\n return rest;\n}\n\nconst warned = new Set<string>();\n\n/** console.warn once per process per key (never under NODE_ENV=test). */\nexport function warnOnce(key: string, message: string): void {\n if (warned.has(key) || process.env.NODE_ENV === 'test') return;\n warned.add(key);\n // eslint-disable-next-line no-console\n console.warn(message);\n}\n\n/** Warn when a kit runs on its in-memory defaults outside tests. */\nexport function warnInMemoryStores(kit: 'UCP' | 'ACP', missing: string[]): void {\n if (!missing.length || process.env.NODE_ENV === 'test') return;\n // eslint-disable-next-line no-console\n console.warn(\n `[astrasync] ${kit} checkout kit is using the in-memory ${missing.join(' and ')} ` +\n '(sessions are lost on restart and not shared across instances). ' +\n `Pass ${missing.map((m) => (m.startsWith('idempotency') ? 'idempotencyStore' : 'store')).join(' and ')} in production.`\n );\n}\n","/**\n * 5.18.0 — mount a fetch-style checkout kit (`createUcpCheckoutKit`,\n * `createAcpCheckoutKit`) on Express.\n *\n * app.use('/ucp/v1', express.raw({ type: '*\\/*' }), expressHandler(ucpKit));\n *\n * The kit checks RFC 9421 signatures and Content-Digest / idempotency\n * fingerprints over the EXACT request bytes, so give it the raw body: mount\n * `express.raw()` on the kit's routes (req.body is a Buffer), or keep a copy\n * on `req.rawBody` (Buffer or string) in your JSON parser's `verify` hook.\n * A body that was already parsed to an object is re-serialised with\n * JSON.stringify — fine for unsigned traffic, but signatures won't verify.\n *\n * When the AstraSync middleware ran first, the caller's verified ASTRA-id\n * (`req.agentVerification.agent.astraId`) scopes sessions and idempotency\n * keys; override with `callerId`.\n */\nimport type { KitRequestContext } from '../ucp/kit-shared';\nimport { warnOnce } from '../ucp/kit-shared';\n\n/** Anything with a fetch-style `handle` (both checkout kits). */\nexport interface FetchKit {\n handle(req: Request, ctx?: KitRequestContext): Promise<Response>;\n}\n\n/** The parts of an Express request this adapter reads. */\nexport interface KitExpressRequest {\n method: string;\n protocol?: string;\n originalUrl?: string;\n url: string;\n headers: Record<string, string | string[] | undefined>;\n body?: unknown;\n rawBody?: unknown;\n get?(name: string): string | undefined;\n agentVerification?: {\n identityVerified?: boolean;\n agent?: { astraId?: string };\n };\n}\n\n/** The parts of an Express response this adapter writes. */\nexport interface KitExpressResponse {\n status(code: number): unknown;\n setHeader(name: string, value: string | string[]): unknown;\n end(body?: unknown): unknown;\n}\n\nexport interface ExpressHandlerOptions {\n /** The caller's verified ASTRA-id (default: from `req.agentVerification` when identity-verified). */\n callerId?: (req: KitExpressRequest) => string | undefined;\n}\n\nconst bytes = (b: Buffer): ArrayBuffer =>\n b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength) as ArrayBuffer;\n\nfunction rawBodyOf(req: KitExpressRequest): string | ArrayBuffer | undefined {\n if (req.method === 'GET' || req.method === 'HEAD') return undefined;\n const raw = req.rawBody;\n if (Buffer.isBuffer(raw)) return bytes(raw);\n if (typeof raw === 'string') return raw;\n if (Buffer.isBuffer(req.body)) return bytes(req.body);\n if (typeof req.body === 'string') return req.body;\n if (req.body !== undefined && req.body !== null && typeof req.body === 'object') {\n if (Object.keys(req.body as object).length === 0) return undefined;\n warnOnce(\n 'kit-express-parsed-body',\n '[astrasync] expressHandler: the request body was already parsed — re-serialising it. ' +\n 'Mount express.raw() on the checkout routes (or keep req.rawBody) so signatures and ' +\n 'idempotency fingerprints see the exact bytes.'\n );\n return JSON.stringify(req.body);\n }\n return undefined;\n}\n\n/** An Express handler that runs a checkout kit and writes its Response back. */\nexport function expressHandler(kit: FetchKit, options: ExpressHandlerOptions = {}) {\n return async (\n req: KitExpressRequest,\n res: KitExpressResponse,\n next: (err?: unknown) => void\n ): Promise<void> => {\n try {\n const host = req.get?.('host') ?? (req.headers.host as string | undefined) ?? 'localhost';\n const url = `${req.protocol ?? 'http'}://${host}${req.originalUrl ?? req.url}`;\n const headers = new Headers();\n for (const [k, v] of Object.entries(req.headers)) {\n if (v === undefined) continue;\n if (Array.isArray(v)) v.forEach((x) => headers.append(k, x));\n else headers.set(k, v);\n }\n const body = rawBodyOf(req);\n const request = new Request(url, {\n method: req.method,\n headers,\n ...(body !== undefined && { body }),\n });\n const verified = req.agentVerification?.identityVerified\n ? req.agentVerification.agent?.astraId\n : undefined;\n const callerId = options.callerId ? options.callerId(req) : verified;\n const response = await kit.handle(request, callerId ? { callerId } : undefined);\n res.status(response.status);\n response.headers.forEach((value, name) => {\n res.setHeader(name, value);\n });\n res.end(Buffer.from(await response.arrayBuffer()));\n } catch (err) {\n next(err);\n }\n };\n}\n"],"mappings":";AA4EA,IAAM,SAAS,oBAAI,IAAY;AAGxB,SAAS,SAAS,KAAa,SAAuB;AAC3D,MAAI,OAAO,IAAI,GAAG,KAAK,QAAQ,IAAI,aAAa,OAAQ;AACxD,SAAO,IAAI,GAAG;AAEd,UAAQ,KAAK,OAAO;AACtB;;;AC/BA,IAAM,QAAQ,CAAC,MACb,EAAE,OAAO,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU;AAE1D,SAAS,UAAU,KAA0D;AAC3E,MAAI,IAAI,WAAW,SAAS,IAAI,WAAW,OAAQ,QAAO;AAC1D,QAAM,MAAM,IAAI;AAChB,MAAI,OAAO,SAAS,GAAG,EAAG,QAAO,MAAM,GAAG;AAC1C,MAAI,OAAO,QAAQ,SAAU,QAAO;AACpC,MAAI,OAAO,SAAS,IAAI,IAAI,EAAG,QAAO,MAAM,IAAI,IAAI;AACpD,MAAI,OAAO,IAAI,SAAS,SAAU,QAAO,IAAI;AAC7C,MAAI,IAAI,SAAS,UAAa,IAAI,SAAS,QAAQ,OAAO,IAAI,SAAS,UAAU;AAC/E,QAAI,OAAO,KAAK,IAAI,IAAc,EAAE,WAAW,EAAG,QAAO;AACzD;AAAA,MACE;AAAA,MACA;AAAA,IAGF;AACA,WAAO,KAAK,UAAU,IAAI,IAAI;AAAA,EAChC;AACA,SAAO;AACT;AAGO,SAAS,eAAe,KAAe,UAAiC,CAAC,GAAG;AACjF,SAAO,OACL,KACA,KACA,SACkB;AAClB,QAAI;AACF,YAAM,OAAO,IAAI,MAAM,MAAM,KAAM,IAAI,QAAQ,QAA+B;AAC9E,YAAM,MAAM,GAAG,IAAI,YAAY,MAAM,MAAM,IAAI,GAAG,IAAI,eAAe,IAAI,GAAG;AAC5E,YAAM,UAAU,IAAI,QAAQ;AAC5B,iBAAW,CAAC,GAAG,CAAC,KAAK,OAAO,QAAQ,IAAI,OAAO,GAAG;AAChD,YAAI,MAAM,OAAW;AACrB,YAAI,MAAM,QAAQ,CAAC,EAAG,GAAE,QAAQ,CAAC,MAAM,QAAQ,OAAO,GAAG,CAAC,CAAC;AAAA,YACtD,SAAQ,IAAI,GAAG,CAAC;AAAA,MACvB;AACA,YAAM,OAAO,UAAU,GAAG;AAC1B,YAAM,UAAU,IAAI,QAAQ,KAAK;AAAA,QAC/B,QAAQ,IAAI;AAAA,QACZ;AAAA,QACA,GAAI,SAAS,UAAa,EAAE,KAAK;AAAA,MACnC,CAAC;AACD,YAAM,WAAW,IAAI,mBAAmB,mBACpC,IAAI,kBAAkB,OAAO,UAC7B;AACJ,YAAM,WAAW,QAAQ,WAAW,QAAQ,SAAS,GAAG,IAAI;AAC5D,YAAM,WAAW,MAAM,IAAI,OAAO,SAAS,WAAW,EAAE,SAAS,IAAI,MAAS;AAC9E,UAAI,OAAO,SAAS,MAAM;AAC1B,eAAS,QAAQ,QAAQ,CAAC,OAAO,SAAS;AACxC,YAAI,UAAU,MAAM,KAAK;AAAA,MAC3B,CAAC;AACD,UAAI,IAAI,OAAO,KAAK,MAAM,SAAS,YAAY,CAAC,CAAC;AAAA,IACnD,SAAS,KAAK;AACZ,WAAK,GAAG;AAAA,IACV;AAAA,EACF;AACF;","names":[]}
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { d as VerificationResult, G as GatewayConfig } from '../types-DRb_plOh.mjs';
2
+ import { d as VerificationResult, G as GatewayConfig } from '../types-Cns4l8gX.mjs';
3
3
 
4
4
  /**
5
5
  * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
@@ -1,5 +1,5 @@
1
1
  import { Request, Response, RequestHandler } from 'express';
2
- import { d as VerificationResult, G as GatewayConfig } from '../types-DRb_plOh.js';
2
+ import { d as VerificationResult, G as GatewayConfig } from '../types-Cns4l8gX.js';
3
3
 
4
4
  /**
5
5
  * X-Astra-Verified-Hop — cross-hop verify-access dedupe marker.
@@ -32,7 +32,7 @@ __export(mcp_exports, {
32
32
  module.exports = __toCommonJS(mcp_exports);
33
33
 
34
34
  // src/version.ts
35
- var SDK_VERSION = "5.17.1";
35
+ var SDK_VERSION = "5.18.0";
36
36
 
37
37
  // src/http.ts
38
38
  var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;