@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.
- package/CHANGELOG.md +1849 -0
- package/README.md +141 -7
- package/dist/adapters/express.d.mts +1 -1
- package/dist/adapters/express.d.ts +1 -1
- package/dist/adapters/express.js +30 -12
- package/dist/adapters/express.js.map +1 -1
- package/dist/adapters/express.mjs +30 -12
- package/dist/adapters/express.mjs.map +1 -1
- package/dist/adapters/kit-express.d.mts +63 -0
- package/dist/adapters/kit-express.d.ts +63 -0
- package/dist/adapters/kit-express.js +88 -0
- package/dist/adapters/kit-express.js.map +1 -0
- package/dist/adapters/kit-express.mjs +61 -0
- package/dist/adapters/kit-express.mjs.map +1 -0
- package/dist/adapters/mcp.d.mts +1 -1
- package/dist/adapters/mcp.d.ts +1 -1
- package/dist/adapters/mcp.js +1 -1
- package/dist/adapters/mcp.js.map +1 -1
- package/dist/adapters/mcp.mjs +1 -1
- package/dist/adapters/mcp.mjs.map +1 -1
- package/dist/adapters/nextjs.d.mts +1 -1
- package/dist/adapters/nextjs.d.ts +1 -1
- package/dist/adapters/nextjs.js +18 -8
- package/dist/adapters/nextjs.js.map +1 -1
- package/dist/adapters/nextjs.mjs +18 -8
- package/dist/adapters/nextjs.mjs.map +1 -1
- package/dist/adapters/sdk.d.mts +1 -1
- package/dist/adapters/sdk.d.ts +1 -1
- package/dist/adapters/sdk.js +1 -1
- package/dist/adapters/sdk.js.map +1 -1
- package/dist/adapters/sdk.mjs +1 -1
- package/dist/adapters/sdk.mjs.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/index.mjs +1 -1
- package/dist/agent/index.mjs.map +1 -1
- package/dist/bin/astrasync-claude-hook.js +1 -1
- package/dist/bin/astrasync-codex-hook.js +1 -1
- package/dist/bin/astrasync-guard.js +3 -1
- package/dist/bin/astrasync.js +21 -1
- package/dist/browser/background.js +1 -1
- package/dist/browser/background.js.map +1 -1
- package/dist/browser/background.mjs +1 -1
- package/dist/browser/background.mjs.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +1 -1
- package/dist/cli/index.mjs.map +1 -1
- package/dist/codex/index.js +1 -1
- package/dist/codex/index.js.map +1 -1
- package/dist/codex/index.mjs +1 -1
- package/dist/codex/index.mjs.map +1 -1
- package/dist/cursor/extension.js +1 -1
- package/dist/cursor/extension.js.map +1 -1
- package/dist/cursor/extension.mjs +1 -1
- package/dist/cursor/extension.mjs.map +1 -1
- package/dist/edge-config.d.mts +1 -1
- package/dist/edge-config.d.ts +1 -1
- package/dist/edge-config.js +1 -1
- package/dist/edge-config.js.map +1 -1
- package/dist/edge-config.mjs +1 -1
- package/dist/edge-config.mjs.map +1 -1
- package/dist/edge-core/index.d.mts +5 -4
- package/dist/edge-core/index.d.ts +5 -4
- package/dist/edge-core/index.js +18 -8
- package/dist/edge-core/index.js.map +1 -1
- package/dist/edge-core/index.mjs +18 -8
- package/dist/edge-core/index.mjs.map +1 -1
- package/dist/gateway/gateway.js +1 -1
- package/dist/gateway/gateway.js.map +1 -1
- package/dist/gateway/gateway.mjs +1 -1
- package/dist/gateway/gateway.mjs.map +1 -1
- package/dist/git-trigger/git-hooks.d.mts +1 -1
- package/dist/git-trigger/git-hooks.d.ts +1 -1
- package/dist/index.d.mts +390 -12
- package/dist/index.d.ts +390 -12
- package/dist/index.js +766 -230
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +749 -222
- package/dist/index.mjs.map +1 -1
- package/dist/registration/index.js +1 -1
- package/dist/registration/index.js.map +1 -1
- package/dist/registration/index.mjs +1 -1
- package/dist/registration/index.mjs.map +1 -1
- package/dist/transport/index.d.mts +4 -3
- package/dist/transport/index.d.ts +4 -3
- package/dist/transport/index.js +1 -1
- package/dist/transport/index.js.map +1 -1
- package/dist/transport/index.mjs +1 -1
- package/dist/transport/index.mjs.map +1 -1
- package/dist/{types-vNBvYD7Z.d.mts → types-3ObBpsnf.d.mts} +7 -0
- package/dist/{types-DA8LzAOB.d.ts → types-BoxZEYPS.d.ts} +7 -0
- package/dist/{types-DRb_plOh.d.mts → types-Cns4l8gX.d.mts} +17 -0
- package/dist/{types-DRb_plOh.d.ts → types-Cns4l8gX.d.ts} +17 -0
- package/dist/ui/index.d.mts +1 -1
- package/dist/ui/index.d.ts +1 -1
- package/dist/verify.d.mts +1 -1
- package/dist/verify.d.ts +1 -1
- package/dist/verify.js +1 -1
- package/dist/verify.js.map +1 -1
- package/dist/verify.mjs +1 -1
- package/dist/verify.mjs.map +1 -1
- package/package.json +8 -2
package/dist/index.js
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
33
|
ACP_API_VERSION: () => ACP_API_VERSION,
|
|
34
|
+
ACP_SUPPORTED_API_VERSIONS: () => ACP_SUPPORTED_API_VERSIONS,
|
|
34
35
|
AEP_SPEC_VERSION: () => AEP_SPEC_VERSION,
|
|
35
36
|
AP2_VCT: () => AP2_VCT,
|
|
36
37
|
AepChain: () => AepChain,
|
|
@@ -51,6 +52,7 @@ __export(src_exports, {
|
|
|
51
52
|
MCP_VERIFIED_HOP_MAX_AGE_MS: () => MCP_VERIFIED_HOP_MAX_AGE_MS,
|
|
52
53
|
MemoryCheckoutStore: () => MemoryCheckoutStore,
|
|
53
54
|
MemoryIdempotencyStore: () => MemoryIdempotencyStore,
|
|
55
|
+
MemoryMppChallengeStore: () => MemoryMppChallengeStore,
|
|
54
56
|
PLATFORM_AGENT_SIGNATURES: () => PLATFORM_AGENT_SIGNATURES,
|
|
55
57
|
RUNTIME_SIGNATURES: () => RUNTIME_SIGNATURES,
|
|
56
58
|
RedisIdempotencyStore: () => RedisIdempotencyStore,
|
|
@@ -60,10 +62,12 @@ __export(src_exports, {
|
|
|
60
62
|
SDK_USER_AGENT: () => SDK_USER_AGENT,
|
|
61
63
|
SettlementReportError: () => SettlementReportError,
|
|
62
64
|
TRUST_LEVEL_RANGES: () => TRUST_LEVEL_RANGES,
|
|
65
|
+
UCP_ORDER_CAPABILITY: () => UCP_ORDER_CAPABILITY,
|
|
63
66
|
UCP_VERSION: () => UCP_VERSION,
|
|
64
67
|
VERIFICATION_STATUS_HEADER: () => VERIFICATION_STATUS_HEADER,
|
|
65
68
|
VERSION: () => SDK_VERSION,
|
|
66
69
|
_resetEdgeConfigCache: () => _resetEdgeConfigCache,
|
|
70
|
+
acpPaymentHandlers: () => acpPaymentHandlers,
|
|
67
71
|
aepCanonicalJson: () => aepCanonicalJson,
|
|
68
72
|
aepHash: () => aepHash,
|
|
69
73
|
aepPrivateKeyFromSeed: () => aepPrivateKeyFromSeed,
|
|
@@ -78,9 +82,12 @@ __export(src_exports, {
|
|
|
78
82
|
authorizeSettlement: () => authorizeSettlement,
|
|
79
83
|
awaitStepUpApproval: () => awaitStepUpApproval,
|
|
80
84
|
beginIdempotent: () => beginIdempotent,
|
|
85
|
+
buildAcpWellKnown: () => buildAcpWellKnown,
|
|
81
86
|
buildGuidance: () => buildGuidance,
|
|
87
|
+
buildMpp402Response: () => buildMpp402Response,
|
|
82
88
|
buildMppChallenge: () => buildMppChallenge,
|
|
83
89
|
buildSdkObservedMetadata: () => buildSdkObservedMetadata,
|
|
90
|
+
buildUcpOrder: () => buildUcpOrder,
|
|
84
91
|
buildUcpProfile: () => buildUcpProfile,
|
|
85
92
|
buildVerificationUnavailableBody: () => buildVerificationUnavailableBody,
|
|
86
93
|
buildX402Challenge: () => buildX402Challenge,
|
|
@@ -104,6 +111,7 @@ __export(src_exports, {
|
|
|
104
111
|
encodeMppReceipt: () => encodeMppReceipt,
|
|
105
112
|
encodeX402SettlementResponse: () => encodeX402SettlementResponse,
|
|
106
113
|
express: () => express_exports,
|
|
114
|
+
expressHandler: () => expressHandler,
|
|
107
115
|
extractApiKeyFormat: () => extractApiKeyFormat,
|
|
108
116
|
extractCredentials: () => extractCredentials,
|
|
109
117
|
extractMcpCredentials: () => extractMcpCredentials,
|
|
@@ -128,6 +136,7 @@ __export(src_exports, {
|
|
|
128
136
|
matchEdgePathRule: () => matchEdgePathRule,
|
|
129
137
|
matchPlatformSignature: () => matchPlatformSignature,
|
|
130
138
|
matchRoutePattern: () => matchRoutePattern,
|
|
139
|
+
mppBodyDigest: () => mppBodyDigest,
|
|
131
140
|
negotiateUcp: () => negotiateUcp,
|
|
132
141
|
nextjs: () => nextjs_exports,
|
|
133
142
|
normalizeDeclaredSource: () => normalizeDeclaredSource,
|
|
@@ -205,7 +214,7 @@ function getTrustLevel(score) {
|
|
|
205
214
|
}
|
|
206
215
|
|
|
207
216
|
// src/version.ts
|
|
208
|
-
var SDK_VERSION = "5.
|
|
217
|
+
var SDK_VERSION = "5.18.0";
|
|
209
218
|
|
|
210
219
|
// src/http.ts
|
|
211
220
|
var SDK_USER_AGENT = `astrasync-sdk/${SDK_VERSION}`;
|
|
@@ -1347,17 +1356,17 @@ function normalizeDeclaredSource(value) {
|
|
|
1347
1356
|
return trimmed && DECLARED_SOURCE_PATTERN.test(trimmed) ? trimmed : void 0;
|
|
1348
1357
|
}
|
|
1349
1358
|
function byteLength(s) {
|
|
1350
|
-
let
|
|
1359
|
+
let bytes2 = 0;
|
|
1351
1360
|
for (let i = 0; i < s.length; i++) {
|
|
1352
1361
|
const code = s.charCodeAt(i);
|
|
1353
|
-
if (code < 128)
|
|
1354
|
-
else if (code < 2048)
|
|
1362
|
+
if (code < 128) bytes2 += 1;
|
|
1363
|
+
else if (code < 2048) bytes2 += 2;
|
|
1355
1364
|
else if (code >= 55296 && code <= 56319) {
|
|
1356
|
-
|
|
1365
|
+
bytes2 += 4;
|
|
1357
1366
|
i++;
|
|
1358
|
-
} else
|
|
1367
|
+
} else bytes2 += 3;
|
|
1359
1368
|
}
|
|
1360
|
-
return
|
|
1369
|
+
return bytes2;
|
|
1361
1370
|
}
|
|
1362
1371
|
function extractApiKeyFormat(rawValue) {
|
|
1363
1372
|
if (!rawValue) return void 0;
|
|
@@ -1534,9 +1543,9 @@ function decodeBase64Url(seg) {
|
|
|
1534
1543
|
const b642 = seg.replace(/-/g, "+").replace(/_/g, "/");
|
|
1535
1544
|
const padded = b642 + "=".repeat((4 - b642.length % 4) % 4);
|
|
1536
1545
|
const binary2 = atob(padded);
|
|
1537
|
-
const
|
|
1538
|
-
for (let i = 0; i < binary2.length; i++)
|
|
1539
|
-
return new TextDecoder().decode(
|
|
1546
|
+
const bytes2 = new Uint8Array(binary2.length);
|
|
1547
|
+
for (let i = 0; i < binary2.length; i++) bytes2[i] = binary2.charCodeAt(i);
|
|
1548
|
+
return new TextDecoder().decode(bytes2);
|
|
1540
1549
|
}
|
|
1541
1550
|
function sniffJwtHeader(compact) {
|
|
1542
1551
|
try {
|
|
@@ -1575,6 +1584,23 @@ function detectCommerce(req, host) {
|
|
|
1575
1584
|
}
|
|
1576
1585
|
const signature = headerValue(req, "signature");
|
|
1577
1586
|
const signatureInput = headerValue(req, "signature-input");
|
|
1587
|
+
if (/\/checkout[-_]sessions(\/|$)/.test(req.uri) && headerValue(req, "ucp-agent")) {
|
|
1588
|
+
const signed = Boolean(signature && signatureInput);
|
|
1589
|
+
return {
|
|
1590
|
+
protocol: "ucp",
|
|
1591
|
+
artifacts: {
|
|
1592
|
+
ucpRequest: { method, url, ...jsonBody && { body: jsonBody } },
|
|
1593
|
+
...signed && {
|
|
1594
|
+
rfc9421: { headers, method, url, ...req.bodyText && { body: req.bodyText } }
|
|
1595
|
+
}
|
|
1596
|
+
},
|
|
1597
|
+
evidence: {
|
|
1598
|
+
path: req.uri,
|
|
1599
|
+
...signed && { keyid: signatureInput.match(/keyid="([^"]+)"/)?.[1] },
|
|
1600
|
+
...truncated
|
|
1601
|
+
}
|
|
1602
|
+
};
|
|
1603
|
+
}
|
|
1578
1604
|
if (signature && signatureInput) {
|
|
1579
1605
|
const signatureAgent = headerValue(req, "signature-agent");
|
|
1580
1606
|
const registryHint = headerValue(req, "x-agent-registry");
|
|
@@ -1609,13 +1635,6 @@ function detectCommerce(req, host) {
|
|
|
1609
1635
|
evidence: { hasTimestamp: Boolean(acpTimestamp), ...truncated }
|
|
1610
1636
|
};
|
|
1611
1637
|
}
|
|
1612
|
-
if (/\/checkout[-_]sessions(\/|$)/.test(req.uri) && headerValue(req, "ucp-agent")) {
|
|
1613
|
-
return {
|
|
1614
|
-
protocol: "ucp",
|
|
1615
|
-
artifacts: { ucpRequest: { method, url, ...jsonBody && { body: jsonBody } } },
|
|
1616
|
-
evidence: { path: req.uri, ...truncated }
|
|
1617
|
-
};
|
|
1618
|
-
}
|
|
1619
1638
|
if (jsonBody) {
|
|
1620
1639
|
const intent = jsonBody.intent_mandate ?? jsonBody.intentMandate;
|
|
1621
1640
|
const cart = jsonBody.cart_mandate ?? jsonBody.cartMandate;
|
|
@@ -2714,6 +2733,7 @@ function createMiddleware(options) {
|
|
|
2714
2733
|
anonymousBeacon = true,
|
|
2715
2734
|
trustVerifiedHop = false,
|
|
2716
2735
|
verifiedHopMaxAgeMs,
|
|
2736
|
+
defaultRoutePolicy = "pass",
|
|
2717
2737
|
...config
|
|
2718
2738
|
} = options;
|
|
2719
2739
|
if (config.apiBaseUrl) {
|
|
@@ -2779,12 +2799,15 @@ function createMiddleware(options) {
|
|
|
2779
2799
|
});
|
|
2780
2800
|
}
|
|
2781
2801
|
const correlationId = req.headers["x-request-id"] || req.headers["x-correlation-id"];
|
|
2782
|
-
const
|
|
2802
|
+
const matchedRoute = findRouteConfig(cachedRoutes, req.path, req.method, {
|
|
2783
2803
|
caseInsensitive: caseInsensitiveRouteMatch,
|
|
2784
2804
|
logShadowDivergence: true,
|
|
2785
2805
|
correlationId
|
|
2786
2806
|
});
|
|
2787
|
-
|
|
2807
|
+
const credentials = customExtractCredentials ? customExtractCredentials(req) : defaultExtractCredentials(req);
|
|
2808
|
+
const credentialed = Boolean(credentials.astraId || credentials.apiKey || credentials.jwt);
|
|
2809
|
+
const observeUnmatched = !matchedRoute && (config.evaluateAlwaysIfCredentialed === true && Boolean(credentials.astraId) || defaultRoutePolicy === "observe" && credentialed);
|
|
2810
|
+
if (!matchedRoute && !observeUnmatched) {
|
|
2788
2811
|
if (config.setPassThroughHeader) {
|
|
2789
2812
|
res.setHeader("X-Astra-Gateway-Mode", "unenforced");
|
|
2790
2813
|
res.setHeader(
|
|
@@ -2795,10 +2818,14 @@ function createMiddleware(options) {
|
|
|
2795
2818
|
beaconPassThrough?.(req);
|
|
2796
2819
|
return next();
|
|
2797
2820
|
}
|
|
2821
|
+
const routeConfig = matchedRoute ?? {
|
|
2822
|
+
pattern: req.path,
|
|
2823
|
+
method: req.method,
|
|
2824
|
+
observe: true
|
|
2825
|
+
};
|
|
2798
2826
|
const wellKnownUrls = config.apiBaseUrl ? await getWellKnownUrls(config.apiBaseUrl).catch(() => void 0) : void 0;
|
|
2799
|
-
const credentials = customExtractCredentials ? customExtractCredentials(req) : defaultExtractCredentials(req);
|
|
2800
2827
|
const shouldEnforce = !routeConfig.observe;
|
|
2801
|
-
if (routeConfig.observe && (!config.evaluateAlwaysIfCredentialed || !credentials.astraId)) {
|
|
2828
|
+
if (routeConfig.observe && !observeUnmatched && (!config.evaluateAlwaysIfCredentialed || !credentials.astraId)) {
|
|
2802
2829
|
if (config.setPassThroughHeader) {
|
|
2803
2830
|
res.setHeader("X-Astra-Gateway-Mode", "unenforced");
|
|
2804
2831
|
res.setHeader("X-Astra-Gateway-Reason", "route-observe");
|
|
@@ -4280,8 +4307,8 @@ function extractBase64(value) {
|
|
|
4280
4307
|
}
|
|
4281
4308
|
return null;
|
|
4282
4309
|
}
|
|
4283
|
-
function bufferToBase64(
|
|
4284
|
-
return Buffer.from(
|
|
4310
|
+
function bufferToBase64(bytes2) {
|
|
4311
|
+
return Buffer.from(bytes2).toString("base64");
|
|
4285
4312
|
}
|
|
4286
4313
|
|
|
4287
4314
|
// src/transport/rfc9421-verify.ts
|
|
@@ -5448,9 +5475,9 @@ async function tryVerify(subtle, jwk, signature, body, alg) {
|
|
|
5448
5475
|
}
|
|
5449
5476
|
return false;
|
|
5450
5477
|
}
|
|
5451
|
-
function toBuf(
|
|
5452
|
-
const out = new ArrayBuffer(
|
|
5453
|
-
new Uint8Array(out).set(
|
|
5478
|
+
function toBuf(bytes2) {
|
|
5479
|
+
const out = new ArrayBuffer(bytes2.byteLength);
|
|
5480
|
+
new Uint8Array(out).set(bytes2);
|
|
5454
5481
|
return out;
|
|
5455
5482
|
}
|
|
5456
5483
|
function checkTimestamp(headerValue3, toleranceSec, nowFn) {
|
|
@@ -5973,11 +6000,11 @@ async function thumbprintsMatch(a, b) {
|
|
|
5973
6000
|
}
|
|
5974
6001
|
async function jwkThumbprint(jwk) {
|
|
5975
6002
|
const canonical2 = canonicalJwk(jwk);
|
|
5976
|
-
const
|
|
6003
|
+
const bytes2 = new TextEncoder().encode(JSON.stringify(canonical2));
|
|
5977
6004
|
const subtle = import_node_crypto4.webcrypto.subtle;
|
|
5978
6005
|
const buffer = await new Promise((resolve, reject) => {
|
|
5979
|
-
const source = new ArrayBuffer(
|
|
5980
|
-
new Uint8Array(source).set(
|
|
6006
|
+
const source = new ArrayBuffer(bytes2.byteLength);
|
|
6007
|
+
new Uint8Array(source).set(bytes2);
|
|
5981
6008
|
subtle.digest("SHA-256", source).then(resolve).catch(reject);
|
|
5982
6009
|
});
|
|
5983
6010
|
return Buffer.from(new Uint8Array(buffer)).toString("base64url").replace(/=+$/, "");
|
|
@@ -6370,14 +6397,14 @@ function createMastercardRegistry(options = {}) {
|
|
|
6370
6397
|
const cache4 = /* @__PURE__ */ new Map();
|
|
6371
6398
|
const ttlSec = options.cacheTtlSec ?? 3600;
|
|
6372
6399
|
const fetchFn = options.fetch ?? globalThis.fetch;
|
|
6373
|
-
let
|
|
6400
|
+
let warned2 = false;
|
|
6374
6401
|
return {
|
|
6375
6402
|
name: "mastercard",
|
|
6376
6403
|
async resolve(kid) {
|
|
6377
6404
|
if (!kid) return null;
|
|
6378
6405
|
if (!options.registryUrl) {
|
|
6379
|
-
if (!
|
|
6380
|
-
|
|
6406
|
+
if (!warned2 && !options.silent) {
|
|
6407
|
+
warned2 = true;
|
|
6381
6408
|
console.warn(
|
|
6382
6409
|
"[mastercard-registry] registryUrl not configured \u2014 key resolution disabled. Kid lookups will return null until a partnership registry is supplied."
|
|
6383
6410
|
);
|
|
@@ -10930,6 +10957,7 @@ function astrasyncPaymentHandlers(handlers, specBase = "https://astrasync.ai/ucp
|
|
|
10930
10957
|
}
|
|
10931
10958
|
return out;
|
|
10932
10959
|
}
|
|
10960
|
+
var UCP_ORDER_CAPABILITY = "dev.ucp.shopping.order";
|
|
10933
10961
|
function buildUcpProfile(opts) {
|
|
10934
10962
|
const capabilities = {
|
|
10935
10963
|
"dev.ucp.shopping.checkout": [
|
|
@@ -10950,6 +10978,15 @@ function buildUcpProfile(opts) {
|
|
|
10950
10978
|
}
|
|
10951
10979
|
]
|
|
10952
10980
|
},
|
|
10981
|
+
...opts.orders && {
|
|
10982
|
+
[UCP_ORDER_CAPABILITY]: [
|
|
10983
|
+
{
|
|
10984
|
+
version: UCP_VERSION,
|
|
10985
|
+
spec: `${SPEC}/shopping/order`,
|
|
10986
|
+
schema: `${SCHEMAS}/shopping/order.json`
|
|
10987
|
+
}
|
|
10988
|
+
]
|
|
10989
|
+
},
|
|
10953
10990
|
...opts.capabilities ?? {}
|
|
10954
10991
|
};
|
|
10955
10992
|
return {
|
|
@@ -11326,7 +11363,7 @@ async function sendUcpWebhook(opts) {
|
|
|
11326
11363
|
}
|
|
11327
11364
|
|
|
11328
11365
|
// src/ucp/checkout-kit.ts
|
|
11329
|
-
var
|
|
11366
|
+
var import_crypto8 = require("crypto");
|
|
11330
11367
|
var import_jose3 = require("jose");
|
|
11331
11368
|
|
|
11332
11369
|
// src/mandates/sd-jwt.ts
|
|
@@ -11726,8 +11763,8 @@ function requestFingerprint(body, profile = "ucp") {
|
|
|
11726
11763
|
}
|
|
11727
11764
|
return (0, import_crypto6.createHash)("sha256").update(text).digest("hex");
|
|
11728
11765
|
}
|
|
11729
|
-
function scopeOf(
|
|
11730
|
-
return
|
|
11766
|
+
function scopeOf(caller) {
|
|
11767
|
+
return caller ? (0, import_crypto6.createHash)("sha256").update(caller).digest("hex").slice(0, 16) : null;
|
|
11731
11768
|
}
|
|
11732
11769
|
async function beginIdempotent(opts, req) {
|
|
11733
11770
|
const methods = opts.methods ?? ["POST", "PUT", "PATCH", "DELETE"];
|
|
@@ -11748,7 +11785,16 @@ async function beginIdempotent(opts, req) {
|
|
|
11748
11785
|
message: `Idempotency-Key must be at most ${MAX_KEY_LENGTH} characters.`
|
|
11749
11786
|
};
|
|
11750
11787
|
}
|
|
11751
|
-
const
|
|
11788
|
+
const scope = scopeOf(req.auth);
|
|
11789
|
+
if (!scope) {
|
|
11790
|
+
return opts.required ? {
|
|
11791
|
+
kind: "reject",
|
|
11792
|
+
status: 401,
|
|
11793
|
+
code: "idempotency_caller_required",
|
|
11794
|
+
message: "Idempotency keys are scoped to the caller: send Authorization."
|
|
11795
|
+
} : { kind: "skip" };
|
|
11796
|
+
}
|
|
11797
|
+
const storeKey = `${scope}:${req.method.toUpperCase()} ${req.path}:${req.key}`;
|
|
11752
11798
|
const requestHash = requestFingerprint(req.body, opts.profile ?? "ucp");
|
|
11753
11799
|
const ttl = opts.ttlMs ?? DEFAULT_IDEMPOTENCY_TTL_MS;
|
|
11754
11800
|
try {
|
|
@@ -11824,7 +11870,7 @@ function idempotencyMiddleware(opts) {
|
|
|
11824
11870
|
path: (req.originalUrl ?? req.url).split("?")[0],
|
|
11825
11871
|
body,
|
|
11826
11872
|
key: headerOf(req.headers[header]),
|
|
11827
|
-
auth: headerOf(req.headers.authorization) ?? headerOf(req.headers["x-api-key"])
|
|
11873
|
+
auth: headerOf(req.headers.authorization) ?? headerOf(req.headers["x-api-key"]) ?? headerOf(req.headers["x-astra-id"])
|
|
11828
11874
|
});
|
|
11829
11875
|
if (decision.kind === "skip") return next();
|
|
11830
11876
|
const key = headerOf(req.headers[header]);
|
|
@@ -11863,7 +11909,7 @@ function withIdempotency(opts, handler) {
|
|
|
11863
11909
|
path: new URL(req.url).pathname,
|
|
11864
11910
|
body,
|
|
11865
11911
|
key: req.headers.get(header) ?? void 0,
|
|
11866
|
-
auth: req.headers.get("authorization") ?? req.headers.get("x-api-key") ?? void 0
|
|
11912
|
+
auth: req.headers.get("authorization") ?? req.headers.get("x-api-key") ?? req.headers.get("x-astra-id") ?? void 0
|
|
11867
11913
|
});
|
|
11868
11914
|
if (decision.kind === "skip") return handler(req);
|
|
11869
11915
|
const key = req.headers.get(header) ?? void 0;
|
|
@@ -11920,18 +11966,95 @@ function orderReportAmount(result, fallback) {
|
|
|
11920
11966
|
return fallback;
|
|
11921
11967
|
}
|
|
11922
11968
|
|
|
11969
|
+
// src/ucp/kit-shared.ts
|
|
11970
|
+
var import_crypto7 = require("crypto");
|
|
11971
|
+
function isHeld(result) {
|
|
11972
|
+
const r = result;
|
|
11973
|
+
return Boolean(
|
|
11974
|
+
r.requiresStepUp || r.requiresApproval || r.recommendation === "step_up_required" || r.settlementOutcome?.status === "requires_approval" || r.stepUpApproval && r.stepUpApproval.status !== "consumed"
|
|
11975
|
+
);
|
|
11976
|
+
}
|
|
11977
|
+
var scopeHash = (kind, value) => `${kind}:${(0, import_crypto7.createHash)("sha256").update(`${kind}
|
|
11978
|
+
${value}`).digest("hex").slice(0, 32)}`;
|
|
11979
|
+
async function resolveCallerScope(req, ctx, resolve) {
|
|
11980
|
+
const verified = ctx?.callerId ?? (resolve ? await resolve(req) : void 0);
|
|
11981
|
+
if (verified) return scopeHash("astra", verified);
|
|
11982
|
+
const auth = req.headers.get("authorization");
|
|
11983
|
+
if (auth) return scopeHash("auth", auth);
|
|
11984
|
+
const astraId = req.headers.get("x-astra-id");
|
|
11985
|
+
if (astraId) return scopeHash("astra-header", astraId);
|
|
11986
|
+
return void 0;
|
|
11987
|
+
}
|
|
11988
|
+
var fallbackScope = (kind, value) => scopeHash(kind, value);
|
|
11989
|
+
function pendingResult(result) {
|
|
11990
|
+
const {
|
|
11991
|
+
settlementToken: _t,
|
|
11992
|
+
settlement: _s,
|
|
11993
|
+
mandates: _m,
|
|
11994
|
+
kyaToken: _k,
|
|
11995
|
+
aep: _a,
|
|
11996
|
+
...rest
|
|
11997
|
+
} = result;
|
|
11998
|
+
return rest;
|
|
11999
|
+
}
|
|
12000
|
+
var warned = /* @__PURE__ */ new Set();
|
|
12001
|
+
function warnOnce(key, message) {
|
|
12002
|
+
if (warned.has(key) || process.env.NODE_ENV === "test") return;
|
|
12003
|
+
warned.add(key);
|
|
12004
|
+
console.warn(message);
|
|
12005
|
+
}
|
|
12006
|
+
function warnInMemoryStores(kit, missing) {
|
|
12007
|
+
if (!missing.length || process.env.NODE_ENV === "test") return;
|
|
12008
|
+
console.warn(
|
|
12009
|
+
`[astrasync] ${kit} checkout kit is using the in-memory ${missing.join(" and ")} (sessions are lost on restart and not shared across instances). Pass ${missing.map((m) => m.startsWith("idempotency") ? "idempotencyStore" : "store").join(" and ")} in production.`
|
|
12010
|
+
);
|
|
12011
|
+
}
|
|
12012
|
+
|
|
11923
12013
|
// src/ucp/checkout-kit.ts
|
|
11924
12014
|
var MemoryCheckoutStore = class {
|
|
11925
12015
|
constructor() {
|
|
11926
12016
|
this.m = /* @__PURE__ */ new Map();
|
|
12017
|
+
this.orders = /* @__PURE__ */ new Map();
|
|
11927
12018
|
}
|
|
11928
12019
|
async get(id) {
|
|
11929
12020
|
return this.m.get(id) ?? null;
|
|
11930
12021
|
}
|
|
11931
12022
|
async put(s) {
|
|
11932
12023
|
this.m.set(s.id, s);
|
|
12024
|
+
if (s.order) this.orders.set(s.order.id, s.id);
|
|
12025
|
+
}
|
|
12026
|
+
async claim(id, from, to) {
|
|
12027
|
+
const s = this.m.get(id);
|
|
12028
|
+
if (!s || s.status !== from) return false;
|
|
12029
|
+
s.status = to;
|
|
12030
|
+
return true;
|
|
12031
|
+
}
|
|
12032
|
+
async findByOrderId(orderId) {
|
|
12033
|
+
const id = this.orders.get(orderId);
|
|
12034
|
+
return id ? this.m.get(id) ?? null : null;
|
|
11933
12035
|
}
|
|
11934
12036
|
};
|
|
12037
|
+
function buildUcpOrder(session, opts = {}) {
|
|
12038
|
+
if (!session.order) return null;
|
|
12039
|
+
const version = opts.version ?? UCP_VERSION;
|
|
12040
|
+
return {
|
|
12041
|
+
ucp: { version, capabilities: { [UCP_ORDER_CAPABILITY]: [{ version }] } },
|
|
12042
|
+
id: session.order.id,
|
|
12043
|
+
checkout_id: session.id,
|
|
12044
|
+
...session.order.permalink_url && { permalink_url: session.order.permalink_url },
|
|
12045
|
+
currency: session.currency,
|
|
12046
|
+
line_items: session.line_items.map((l) => ({
|
|
12047
|
+
id: l.id,
|
|
12048
|
+
item: l.item,
|
|
12049
|
+
quantity: { total: l.quantity, fulfilled: 0 },
|
|
12050
|
+
totals: l.totals,
|
|
12051
|
+
status: "processing"
|
|
12052
|
+
})),
|
|
12053
|
+
fulfillment: { expectations: [], events: [] },
|
|
12054
|
+
adjustments: [],
|
|
12055
|
+
totals: session.totals
|
|
12056
|
+
};
|
|
12057
|
+
}
|
|
11935
12058
|
var json2 = (status, body, headers = {}) => new Response(JSON.stringify(body), {
|
|
11936
12059
|
status,
|
|
11937
12060
|
headers: { "content-type": "application/json", ...headers }
|
|
@@ -11944,6 +12067,24 @@ function createUcpCheckoutKit(opts) {
|
|
|
11944
12067
|
store: opts.idempotencyStore ?? new MemoryIdempotencyStore(),
|
|
11945
12068
|
profile: "ucp"
|
|
11946
12069
|
};
|
|
12070
|
+
warnInMemoryStores("UCP", [
|
|
12071
|
+
...opts.store ? [] : ["checkout store"],
|
|
12072
|
+
...opts.idempotencyStore ? [] : ["idempotency store"]
|
|
12073
|
+
]);
|
|
12074
|
+
if (!store.claim) {
|
|
12075
|
+
warnOnce(
|
|
12076
|
+
"ucp-claim",
|
|
12077
|
+
"[astrasync] UCP checkout kit: your CheckoutStore has no claim() \u2014 concurrent completes of one checkout aren't locked. Implement claim(id, from, to) as an atomic compare-and-set."
|
|
12078
|
+
);
|
|
12079
|
+
}
|
|
12080
|
+
const orderIndex = /* @__PURE__ */ new Map();
|
|
12081
|
+
const ordersOn = Boolean(profile.ucp.capabilities?.[UCP_ORDER_CAPABILITY]);
|
|
12082
|
+
const handlerIds = new Set(
|
|
12083
|
+
Object.entries(profile.ucp.payment_handlers).flatMap(([name, entries]) => [
|
|
12084
|
+
name,
|
|
12085
|
+
...entries.map((e) => e.id)
|
|
12086
|
+
])
|
|
12087
|
+
);
|
|
11947
12088
|
const fetchProfile = opts.fetchProfile ?? (async (url, fresh) => {
|
|
11948
12089
|
const r = await fetchUcpProfile(url, { fresh });
|
|
11949
12090
|
return r.ok ? r.profile : r;
|
|
@@ -11955,12 +12096,12 @@ function createUcpCheckoutKit(opts) {
|
|
|
11955
12096
|
const [h, , sig] = attached.split(".");
|
|
11956
12097
|
return { detached: `${h}..${sig}`, attached };
|
|
11957
12098
|
}
|
|
11958
|
-
async function render(s, status = 200) {
|
|
12099
|
+
async function render(s, status = 200, mode = "persist") {
|
|
11959
12100
|
const view = {
|
|
11960
12101
|
ucp: {
|
|
11961
12102
|
version: profile.ucp.version,
|
|
11962
12103
|
capabilities: Object.fromEntries(
|
|
11963
|
-
Object.keys(profile.ucp.capabilities ?? {}).filter((k) => k !== "dev.ucp.common.payment.ap2_mandate" || s._ap2).map((k) => [k, [{ version: profile.ucp.version }]])
|
|
12104
|
+
Object.keys(profile.ucp.capabilities ?? {}).filter((k) => k !== "dev.ucp.common.payment.ap2_mandate" || s._ap2).filter((k) => k !== UCP_ORDER_CAPABILITY).map((k) => [k, [{ version: profile.ucp.version }]])
|
|
11964
12105
|
),
|
|
11965
12106
|
payment_handlers: profile.ucp.payment_handlers
|
|
11966
12107
|
},
|
|
@@ -11969,21 +12110,132 @@ function createUcpCheckoutKit(opts) {
|
|
|
11969
12110
|
currency: s.currency,
|
|
11970
12111
|
line_items: s.line_items,
|
|
11971
12112
|
totals: s.totals,
|
|
12113
|
+
...opts.links?.length && { links: opts.links },
|
|
11972
12114
|
...s.buyer && { buyer: s.buyer },
|
|
11973
12115
|
...s.messages?.length && { messages: s.messages },
|
|
11974
12116
|
...s.continue_url && s.status === "requires_escalation" && { continue_url: s.continue_url },
|
|
11975
12117
|
...s.order && { order: s.order }
|
|
11976
12118
|
};
|
|
11977
|
-
if (s._ap2) {
|
|
11978
|
-
const
|
|
11979
|
-
if (
|
|
11980
|
-
view.ap2 = { merchant_authorization:
|
|
11981
|
-
|
|
11982
|
-
await
|
|
12119
|
+
if (s._ap2 && opts.signingKey) {
|
|
12120
|
+
const viewHash = (0, import_crypto8.createHash)("sha256").update(canonicalJson2(view)).digest("hex");
|
|
12121
|
+
if (mode === "reuse" && s._merchantAuth && s._merchantAuthFor === viewHash) {
|
|
12122
|
+
view.ap2 = { merchant_authorization: s._merchantAuth };
|
|
12123
|
+
} else {
|
|
12124
|
+
const auth = await merchantAuthorization(view);
|
|
12125
|
+
if (auth) {
|
|
12126
|
+
view.ap2 = { merchant_authorization: auth.detached };
|
|
12127
|
+
if (mode !== "ephemeral") {
|
|
12128
|
+
s._checkoutJwt = auth.attached;
|
|
12129
|
+
s._merchantAuth = auth.detached;
|
|
12130
|
+
s._merchantAuthFor = viewHash;
|
|
12131
|
+
await store.put(s);
|
|
12132
|
+
}
|
|
12133
|
+
}
|
|
11983
12134
|
}
|
|
11984
12135
|
}
|
|
11985
12136
|
return json2(status, view);
|
|
11986
12137
|
}
|
|
12138
|
+
function busy(s) {
|
|
12139
|
+
return render(
|
|
12140
|
+
{
|
|
12141
|
+
...s,
|
|
12142
|
+
messages: [
|
|
12143
|
+
...s.messages ?? [],
|
|
12144
|
+
ucpError(
|
|
12145
|
+
"checkout_in_progress",
|
|
12146
|
+
"This checkout is already being completed. Retry shortly.",
|
|
12147
|
+
"recoverable"
|
|
12148
|
+
)
|
|
12149
|
+
]
|
|
12150
|
+
},
|
|
12151
|
+
200,
|
|
12152
|
+
"ephemeral"
|
|
12153
|
+
);
|
|
12154
|
+
}
|
|
12155
|
+
async function save(s) {
|
|
12156
|
+
if (s.order) orderIndex.set(s.order.id, s.id);
|
|
12157
|
+
await store.put(s);
|
|
12158
|
+
}
|
|
12159
|
+
function webhookTarget(s) {
|
|
12160
|
+
const w = opts.webhook;
|
|
12161
|
+
if (!w) return null;
|
|
12162
|
+
const url = w.url ?? s._webhookUrl;
|
|
12163
|
+
const privateKey = w.privateKey ?? opts.signingKey?.privateKey ?? void 0;
|
|
12164
|
+
const keyId = w.keyId ?? opts.signingKey?.kid;
|
|
12165
|
+
if (!url || !privateKey || !keyId) return null;
|
|
12166
|
+
return { w, url, privateKey, keyId };
|
|
12167
|
+
}
|
|
12168
|
+
async function deliverOrder(s) {
|
|
12169
|
+
const target = webhookTarget(s);
|
|
12170
|
+
const order = buildUcpOrder(s, { version: profile.ucp.version });
|
|
12171
|
+
if (!target || !order) return null;
|
|
12172
|
+
const r = await sendUcpWebhook({
|
|
12173
|
+
url: target.url,
|
|
12174
|
+
body: order,
|
|
12175
|
+
privateKey: target.privateKey,
|
|
12176
|
+
keyId: target.keyId,
|
|
12177
|
+
businessProfileUrl: target.w.businessProfileUrl ?? new URL("/.well-known/ucp", opts.profile.endpoint).toString(),
|
|
12178
|
+
...target.w.attempts && { attempts: target.w.attempts },
|
|
12179
|
+
...target.w.fetch && { fetch: target.w.fetch }
|
|
12180
|
+
});
|
|
12181
|
+
target.w.onResult?.(r, order);
|
|
12182
|
+
return r;
|
|
12183
|
+
}
|
|
12184
|
+
function emitOrder(s) {
|
|
12185
|
+
void deliverOrder(s).catch(() => void 0);
|
|
12186
|
+
}
|
|
12187
|
+
async function reportOutcome(p, settled) {
|
|
12188
|
+
if (!opts.reportSettlement || !p.orderId) return;
|
|
12189
|
+
await opts.reportSettlement({
|
|
12190
|
+
orderId: p.orderId,
|
|
12191
|
+
status: settled.status,
|
|
12192
|
+
...p.report,
|
|
12193
|
+
...settled.status === "settled" && settled.processorRef && { processorRef: settled.processorRef },
|
|
12194
|
+
...settled.status === "settled" && settled.txHash && { txHash: settled.txHash, chainId: settled.chainId },
|
|
12195
|
+
...settled.status === "failed" && settled.failureCode && { failureCode: settled.failureCode }
|
|
12196
|
+
}).catch(() => void 0);
|
|
12197
|
+
}
|
|
12198
|
+
async function finish(s, result, p, settled) {
|
|
12199
|
+
await reportOutcome(p, settled);
|
|
12200
|
+
delete s._pending;
|
|
12201
|
+
if (settled.status === "failed") {
|
|
12202
|
+
s.status = "ready_for_complete";
|
|
12203
|
+
s.messages = [
|
|
12204
|
+
ucpError("payment_failed", "The payment did not go through.", "requires_buyer_input")
|
|
12205
|
+
];
|
|
12206
|
+
await save(s);
|
|
12207
|
+
return;
|
|
12208
|
+
}
|
|
12209
|
+
const order = await opts.fulfil({ session: s, result });
|
|
12210
|
+
s.order = {
|
|
12211
|
+
...order,
|
|
12212
|
+
...!order.permalink_url && opts.permalinkBase && {
|
|
12213
|
+
permalink_url: `${opts.permalinkBase.replace(/\/+$/, "")}/${encodeURIComponent(order.id)}`
|
|
12214
|
+
}
|
|
12215
|
+
};
|
|
12216
|
+
s.status = "completed";
|
|
12217
|
+
s.messages = [];
|
|
12218
|
+
await save(s);
|
|
12219
|
+
emitOrder(s);
|
|
12220
|
+
}
|
|
12221
|
+
async function claim2(s, from) {
|
|
12222
|
+
if (store.claim) {
|
|
12223
|
+
if (!await store.claim(s.id, from, "complete_in_progress")) return false;
|
|
12224
|
+
s.status = "complete_in_progress";
|
|
12225
|
+
return true;
|
|
12226
|
+
}
|
|
12227
|
+
s.status = "complete_in_progress";
|
|
12228
|
+
await store.put(s);
|
|
12229
|
+
return true;
|
|
12230
|
+
}
|
|
12231
|
+
async function bindAgent(req, result) {
|
|
12232
|
+
const mode = opts.ucpAgentBinding ?? "registered";
|
|
12233
|
+
if (mode === "off") return null;
|
|
12234
|
+
const identities = opts.resolveIdentities ? await opts.resolveIdentities(req, result) : result.agent?.protocolIdentities;
|
|
12235
|
+
if (mode === "registered" && !identities?.ucpProfile) return null;
|
|
12236
|
+
const b = checkUcpAgentBinding(req.headers.get("ucp-agent"), identities);
|
|
12237
|
+
return b.ok ? null : b;
|
|
12238
|
+
}
|
|
11987
12239
|
async function priceLines(lines) {
|
|
11988
12240
|
const out = [];
|
|
11989
12241
|
const messages = [];
|
|
@@ -12076,13 +12328,13 @@ function createUcpCheckoutKit(opts) {
|
|
|
12076
12328
|
ap2: Boolean(neg.capabilities["dev.ucp.common.payment.ap2_mandate"])
|
|
12077
12329
|
};
|
|
12078
12330
|
}
|
|
12079
|
-
async function withIdempotency2(req, body, path, run) {
|
|
12331
|
+
async function withIdempotency2(req, body, path, caller, run) {
|
|
12080
12332
|
const d = await beginIdempotent(idem, {
|
|
12081
12333
|
method: req.method,
|
|
12082
12334
|
path,
|
|
12083
12335
|
body,
|
|
12084
12336
|
key: req.headers.get("idempotency-key") ?? void 0,
|
|
12085
|
-
auth:
|
|
12337
|
+
auth: caller
|
|
12086
12338
|
});
|
|
12087
12339
|
if (d.kind === "reject")
|
|
12088
12340
|
return json2(d.status, { type: "invalid_request", code: d.code, message: d.message });
|
|
@@ -12103,6 +12355,7 @@ function createUcpCheckoutKit(opts) {
|
|
|
12103
12355
|
}
|
|
12104
12356
|
async function complete(req, s, body) {
|
|
12105
12357
|
if (s.status === "completed" || s.status === "canceled") return render(s);
|
|
12358
|
+
if (s.status === "complete_in_progress") return busy(s);
|
|
12106
12359
|
const ap2 = body.ap2;
|
|
12107
12360
|
const checkoutJwt = s._ap2 ? s._checkoutJwt : void 0;
|
|
12108
12361
|
if (s._ap2) {
|
|
@@ -12114,6 +12367,7 @@ function createUcpCheckoutKit(opts) {
|
|
|
12114
12367
|
"unrecoverable"
|
|
12115
12368
|
)
|
|
12116
12369
|
];
|
|
12370
|
+
await store.put(s);
|
|
12117
12371
|
return render(s);
|
|
12118
12372
|
}
|
|
12119
12373
|
const kidResolver = async (kid) => opts.mandateKey ? opts.mandateKey(kid, s) : (s._platformKeys ?? []).find((k) => k.kid === kid) ?? null;
|
|
@@ -12124,71 +12378,106 @@ function createUcpCheckoutKit(opts) {
|
|
|
12124
12378
|
});
|
|
12125
12379
|
if (!v.ok) {
|
|
12126
12380
|
s.messages = [ucpError(v.code, v.error, "unrecoverable")];
|
|
12381
|
+
await store.put(s);
|
|
12127
12382
|
return render(s);
|
|
12128
12383
|
}
|
|
12129
12384
|
}
|
|
12130
|
-
const
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
astraId: req.headers.get("x-astra-id") ?? void 0,
|
|
12134
|
-
attemptId: req.headers.get("x-astra-attempt-id") ?? void 0,
|
|
12135
|
-
...checkoutJwt && { checkoutJwt },
|
|
12136
|
-
valueMajor: total(s) / 100
|
|
12137
|
-
});
|
|
12138
|
-
const held = result.settlementOutcome?.status === "requires_approval" || result.stepUpApproval && result.stepUpApproval.status === "pending";
|
|
12139
|
-
if (held) {
|
|
12140
|
-
s.status = "requires_escalation";
|
|
12141
|
-
s.continue_url = result.stepUpApproval?.approvalUrl ?? opts.fallbackContinueUrl;
|
|
12142
|
-
s.messages = [
|
|
12143
|
-
ucpError(
|
|
12144
|
-
"buyer_approval_required",
|
|
12145
|
-
"The buyer needs to approve this purchase.",
|
|
12146
|
-
"requires_buyer_review"
|
|
12147
|
-
)
|
|
12148
|
-
];
|
|
12149
|
-
await store.put(s);
|
|
12150
|
-
return render(s);
|
|
12151
|
-
}
|
|
12152
|
-
if (!result.identityVerified || !result.policyAllowed) {
|
|
12385
|
+
const instruments = body.payment?.instruments;
|
|
12386
|
+
const instrument = Array.isArray(instruments) && instruments.length === 1 ? instruments[0] : null;
|
|
12387
|
+
if (!instrument || typeof instrument.handler_id !== "string" || !handlerIds.has(instrument.handler_id)) {
|
|
12153
12388
|
s.messages = [
|
|
12154
12389
|
ucpError(
|
|
12155
|
-
"
|
|
12156
|
-
"
|
|
12157
|
-
"
|
|
12390
|
+
"payment_failed",
|
|
12391
|
+
"Send exactly one payment instrument whose handler_id is one of this business\u2019s payment_handlers.",
|
|
12392
|
+
"recoverable",
|
|
12393
|
+
"$.payment.instruments"
|
|
12158
12394
|
)
|
|
12159
12395
|
];
|
|
12160
12396
|
await store.put(s);
|
|
12161
12397
|
return render(s);
|
|
12162
12398
|
}
|
|
12163
|
-
s.status
|
|
12164
|
-
|
|
12165
|
-
|
|
12166
|
-
|
|
12167
|
-
if (opts.reportSettlement && orderId && settled.status !== "pending") {
|
|
12168
|
-
await opts.reportSettlement({
|
|
12169
|
-
orderId,
|
|
12170
|
-
status: settled.status === "settled" ? "settled" : "failed",
|
|
12171
|
-
...orderReportAmount(result, { amountMinor: total(s), currency: s.currency }),
|
|
12172
|
-
...settled.status === "settled" && settled.processorRef && { processorRef: settled.processorRef },
|
|
12173
|
-
...settled.status === "settled" && settled.txHash && { txHash: settled.txHash, chainId: settled.chainId },
|
|
12174
|
-
...settled.status === "failed" && settled.failureCode && { failureCode: settled.failureCode }
|
|
12175
|
-
}).catch(() => void 0);
|
|
12399
|
+
const from = s.status;
|
|
12400
|
+
if (!await claim2(s, from)) {
|
|
12401
|
+
const current = await store.get(s.id);
|
|
12402
|
+
return busy(current ?? s);
|
|
12176
12403
|
}
|
|
12177
|
-
|
|
12178
|
-
|
|
12179
|
-
|
|
12180
|
-
|
|
12181
|
-
|
|
12182
|
-
|
|
12404
|
+
try {
|
|
12405
|
+
const result = await opts.verifyPurchase({
|
|
12406
|
+
session: s,
|
|
12407
|
+
checkoutSessionId: s._astraCheckoutSessionId ?? s.id,
|
|
12408
|
+
astraId: req.headers.get("x-astra-id") ?? void 0,
|
|
12409
|
+
attemptId: req.headers.get("x-astra-attempt-id") ?? void 0,
|
|
12410
|
+
...checkoutJwt && { checkoutJwt },
|
|
12411
|
+
valueMajor: total(s) / 100
|
|
12412
|
+
});
|
|
12413
|
+
const binding2 = await bindAgent(req, result);
|
|
12414
|
+
if (binding2) {
|
|
12415
|
+
s.status = from;
|
|
12416
|
+
s.messages = [ucpError(binding2.code, binding2.message, "unrecoverable")];
|
|
12417
|
+
await store.put(s);
|
|
12418
|
+
return render(s);
|
|
12419
|
+
}
|
|
12420
|
+
if (isHeld(result)) {
|
|
12421
|
+
s.status = "requires_escalation";
|
|
12422
|
+
s.continue_url = result.stepUpApproval?.approvalUrl ?? opts.fallbackContinueUrl;
|
|
12423
|
+
s.messages = [
|
|
12424
|
+
ucpError(
|
|
12425
|
+
"buyer_approval_required",
|
|
12426
|
+
"The buyer needs to approve this purchase.",
|
|
12427
|
+
"requires_buyer_review"
|
|
12428
|
+
)
|
|
12429
|
+
];
|
|
12430
|
+
await store.put(s);
|
|
12431
|
+
return render(s);
|
|
12432
|
+
}
|
|
12433
|
+
if (!result.identityVerified || !result.policyAllowed) {
|
|
12434
|
+
s.status = from;
|
|
12435
|
+
s.messages = [
|
|
12436
|
+
ucpError(
|
|
12437
|
+
"agent_not_authorized",
|
|
12438
|
+
"The agent is not authorized for this purchase.",
|
|
12439
|
+
"unrecoverable"
|
|
12440
|
+
)
|
|
12441
|
+
];
|
|
12442
|
+
await store.put(s);
|
|
12443
|
+
return render(s);
|
|
12444
|
+
}
|
|
12445
|
+
const settled = await opts.settle({ session: s, result, instrument });
|
|
12446
|
+
const pending = {
|
|
12447
|
+
...result.settlementOutcome?.orderId && {
|
|
12448
|
+
orderId: result.settlementOutcome.orderId
|
|
12449
|
+
},
|
|
12450
|
+
report: orderReportAmount(result, { amountMinor: total(s), currency: s.currency }),
|
|
12451
|
+
result: pendingResult(result)
|
|
12452
|
+
};
|
|
12453
|
+
if (settled.status === "pending") {
|
|
12454
|
+
s._pending = pending;
|
|
12455
|
+
s.messages = [];
|
|
12456
|
+
await store.put(s);
|
|
12457
|
+
return render(s);
|
|
12458
|
+
}
|
|
12459
|
+
await finish(s, result, pending, settled);
|
|
12183
12460
|
return render(s);
|
|
12461
|
+
} catch (e) {
|
|
12462
|
+
if (s.status === "complete_in_progress" && !s._pending) {
|
|
12463
|
+
s.status = from;
|
|
12464
|
+
await store.put(s).catch(() => void 0);
|
|
12465
|
+
}
|
|
12466
|
+
throw e;
|
|
12184
12467
|
}
|
|
12185
|
-
s.order = await opts.fulfil({ session: s, result });
|
|
12186
|
-
s.status = "completed";
|
|
12187
|
-
s.messages = [];
|
|
12188
|
-
await store.put(s);
|
|
12189
|
-
return render(s);
|
|
12190
12468
|
}
|
|
12191
|
-
async function
|
|
12469
|
+
async function resolvePending(sessionId, outcome) {
|
|
12470
|
+
const s = await store.get(sessionId);
|
|
12471
|
+
if (!s) return null;
|
|
12472
|
+
if (s.status !== "complete_in_progress" || !s._pending) return s;
|
|
12473
|
+
await finish(s, s._pending.result, s._pending, outcome);
|
|
12474
|
+
return s;
|
|
12475
|
+
}
|
|
12476
|
+
async function sendOrderWebhook(sessionId) {
|
|
12477
|
+
const s = await store.get(sessionId);
|
|
12478
|
+
return s ? deliverOrder(s) : null;
|
|
12479
|
+
}
|
|
12480
|
+
async function handle(req, reqCtx) {
|
|
12192
12481
|
const base = new URL(opts.profile.endpoint).pathname.replace(/\/+$/, "");
|
|
12193
12482
|
const url = new URL(req.url);
|
|
12194
12483
|
const path = url.pathname.startsWith(base) ? url.pathname.slice(base.length) : url.pathname;
|
|
@@ -12202,20 +12491,24 @@ function createUcpCheckoutKit(opts) {
|
|
|
12202
12491
|
const p = await platform(req, body);
|
|
12203
12492
|
if ("error" in p && p.error) return p.error;
|
|
12204
12493
|
const ctx = p;
|
|
12494
|
+
const caller = await resolveCallerScope(req, reqCtx, opts.resolveCallerId) ?? fallbackScope("ucp-profile", ctx.profileUrl);
|
|
12205
12495
|
if (req.method === "POST" && path === "/checkout-sessions") {
|
|
12206
|
-
return withIdempotency2(req, body, path, async () => {
|
|
12496
|
+
return withIdempotency2(req, body, path, caller, async () => {
|
|
12207
12497
|
const priced = await priceLines(parsed.line_items ?? []);
|
|
12498
|
+
const webhookUrl = ctx.plat.ucp.capabilities?.[UCP_ORDER_CAPABILITY]?.[0]?.config?.webhook_url;
|
|
12208
12499
|
const s2 = {
|
|
12209
|
-
id: `chk_${(0,
|
|
12500
|
+
id: `chk_${(0, import_crypto8.randomUUID)().replace(/-/g, "")}`,
|
|
12210
12501
|
status: priced.lines.length && !priced.messages.length ? "ready_for_complete" : "incomplete",
|
|
12211
12502
|
currency: opts.currency,
|
|
12212
12503
|
line_items: priced.lines,
|
|
12213
12504
|
totals: priced.totals,
|
|
12214
12505
|
messages: priced.messages,
|
|
12215
12506
|
...parsed.buyer ? { buyer: parsed.buyer } : {},
|
|
12507
|
+
_caller: caller,
|
|
12216
12508
|
_platformProfile: ctx.profileUrl,
|
|
12217
12509
|
_ap2: ctx.ap2,
|
|
12218
12510
|
_platformKeys: ctx.plat.keys ?? [],
|
|
12511
|
+
...typeof webhookUrl === "string" && /^https:\/\//.test(webhookUrl) && { _webhookUrl: webhookUrl },
|
|
12219
12512
|
...req.headers.get("x-astra-checkout-session") && {
|
|
12220
12513
|
_astraCheckoutSessionId: req.headers.get("x-astra-checkout-session").slice(0, 64)
|
|
12221
12514
|
}
|
|
@@ -12234,16 +12527,28 @@ function createUcpCheckoutKit(opts) {
|
|
|
12234
12527
|
return render(s2, 201);
|
|
12235
12528
|
});
|
|
12236
12529
|
}
|
|
12530
|
+
const notFound = (what = "checkout session") => json2(404, { code: "not_found", content: `Unknown ${what}.` });
|
|
12531
|
+
const om = /^\/orders\/([^/]+)$/.exec(path);
|
|
12532
|
+
if (om && ordersOn) {
|
|
12533
|
+
if (req.method !== "GET")
|
|
12534
|
+
return json2(405, { code: "method_not_allowed", content: "Method not allowed." });
|
|
12535
|
+
const orderId = decodeURIComponent(om[1]);
|
|
12536
|
+
const viaIndex = orderIndex.get(orderId);
|
|
12537
|
+
const s2 = store.findByOrderId ? await store.findByOrderId(orderId) : viaIndex ? await store.get(viaIndex) : null;
|
|
12538
|
+
if (!s2 || s2._caller !== caller || s2._platformProfile !== ctx.profileUrl)
|
|
12539
|
+
return notFound("order");
|
|
12540
|
+
const order = buildUcpOrder(s2, { version: profile.ucp.version });
|
|
12541
|
+
return order ? json2(200, order) : notFound("order");
|
|
12542
|
+
}
|
|
12237
12543
|
const m = /^\/checkout-sessions\/([^/]+)(\/complete|\/cancel)?$/.exec(path);
|
|
12238
12544
|
if (!m) return json2(404, { code: "not_found", content: "Unknown operation." });
|
|
12239
12545
|
const s = await store.get(m[1]);
|
|
12240
|
-
if (!s
|
|
12241
|
-
if (
|
|
12242
|
-
return json2(404, { code: "not_found", content: "Unknown checkout session." });
|
|
12243
|
-
if (req.method === "GET" && !m[2]) return render(s);
|
|
12546
|
+
if (!s || s._caller !== caller || s._platformProfile !== ctx.profileUrl) return notFound();
|
|
12547
|
+
if (req.method === "GET" && !m[2]) return render(s, 200, "reuse");
|
|
12244
12548
|
if (req.method === "PUT" && !m[2]) {
|
|
12245
|
-
return withIdempotency2(req, body, path, async () => {
|
|
12549
|
+
return withIdempotency2(req, body, path, caller, async () => {
|
|
12246
12550
|
if (s.status === "completed" || s.status === "canceled") return render(s);
|
|
12551
|
+
if (s.status === "complete_in_progress") return busy(s);
|
|
12247
12552
|
if (parsed.line_items) {
|
|
12248
12553
|
const priced = await priceLines(parsed.line_items);
|
|
12249
12554
|
s.line_items = priced.lines;
|
|
@@ -12257,11 +12562,17 @@ function createUcpCheckoutKit(opts) {
|
|
|
12257
12562
|
});
|
|
12258
12563
|
}
|
|
12259
12564
|
if (req.method === "POST" && m[2] === "/complete") {
|
|
12260
|
-
return withIdempotency2(req, body, path, () => complete(req, s, parsed));
|
|
12565
|
+
return withIdempotency2(req, body, path, caller, () => complete(req, s, parsed));
|
|
12261
12566
|
}
|
|
12262
12567
|
if (req.method === "POST" && m[2] === "/cancel") {
|
|
12263
|
-
return withIdempotency2(req, body, path, async () => {
|
|
12264
|
-
if (s.status
|
|
12568
|
+
return withIdempotency2(req, body, path, caller, async () => {
|
|
12569
|
+
if (s.status === "completed" || s.status === "canceled")
|
|
12570
|
+
return json2(405, {
|
|
12571
|
+
code: "method_not_allowed",
|
|
12572
|
+
content: `A ${s.status} checkout can't be canceled.`
|
|
12573
|
+
});
|
|
12574
|
+
if (s.status === "complete_in_progress") return busy(s);
|
|
12575
|
+
s.status = "canceled";
|
|
12265
12576
|
await store.put(s);
|
|
12266
12577
|
return render(s);
|
|
12267
12578
|
});
|
|
@@ -12271,7 +12582,9 @@ function createUcpCheckoutKit(opts) {
|
|
|
12271
12582
|
return {
|
|
12272
12583
|
handle,
|
|
12273
12584
|
profile,
|
|
12274
|
-
profileHandler: () => json2(200, profile, { "cache-control": "public, max-age=300" })
|
|
12585
|
+
profileHandler: () => json2(200, profile, { "cache-control": "public, max-age=300" }),
|
|
12586
|
+
resolvePending,
|
|
12587
|
+
sendOrderWebhook
|
|
12275
12588
|
};
|
|
12276
12589
|
}
|
|
12277
12590
|
|
|
@@ -12324,7 +12637,7 @@ function x402PaymentMatchesOffer(payment, offered) {
|
|
|
12324
12637
|
}
|
|
12325
12638
|
|
|
12326
12639
|
// src/payments/mpp.ts
|
|
12327
|
-
var
|
|
12640
|
+
var import_crypto9 = require("crypto");
|
|
12328
12641
|
var b64url = (s) => Buffer.from(s, "utf8").toString("base64url");
|
|
12329
12642
|
function canonical(value) {
|
|
12330
12643
|
if (Array.isArray(value)) return `[${value.map(canonical).join(",")}]`;
|
|
@@ -12333,27 +12646,29 @@ function canonical(value) {
|
|
|
12333
12646
|
}
|
|
12334
12647
|
return JSON.stringify(value);
|
|
12335
12648
|
}
|
|
12336
|
-
var
|
|
12337
|
-
"realm",
|
|
12338
|
-
"method",
|
|
12339
|
-
"intent",
|
|
12340
|
-
"request",
|
|
12341
|
-
"expires",
|
|
12342
|
-
"digest",
|
|
12343
|
-
"opaque",
|
|
12344
|
-
"header"
|
|
12345
|
-
];
|
|
12649
|
+
var requestSlot = (request) => typeof request === "string" ? request : b64url(canonical(request ?? {}));
|
|
12346
12650
|
function binding(c, secret) {
|
|
12347
|
-
const
|
|
12348
|
-
|
|
12349
|
-
|
|
12350
|
-
|
|
12651
|
+
const slots = [
|
|
12652
|
+
c.realm,
|
|
12653
|
+
c.method,
|
|
12654
|
+
c.intent,
|
|
12655
|
+
requestSlot(c.request),
|
|
12656
|
+
c.expires ?? "",
|
|
12657
|
+
c.digest ?? ""
|
|
12658
|
+
];
|
|
12659
|
+
if (c.header && c.header.toLowerCase() !== "authorization") slots.push(c.header);
|
|
12660
|
+
slots.push(c.opaque ?? "");
|
|
12661
|
+
return (0, import_crypto9.createHmac)("sha256", secret).update(slots.join("|")).digest("base64url");
|
|
12351
12662
|
}
|
|
12352
12663
|
var quote = (v) => `"${v.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
12353
12664
|
function buildMppChallenge(input, hmacSecret) {
|
|
12354
12665
|
if (!/^[a-z]+$/.test(input.method)) throw new Error("mpp: method must be lowercase ASCII");
|
|
12355
|
-
const { request, ...rest } = input;
|
|
12356
|
-
const c = {
|
|
12666
|
+
const { request, meta, ...rest } = input;
|
|
12667
|
+
const c = {
|
|
12668
|
+
...rest,
|
|
12669
|
+
request: b64url(canonical(request)),
|
|
12670
|
+
...rest.opaque === void 0 && meta !== void 0 && { opaque: b64url(canonical(meta)) }
|
|
12671
|
+
};
|
|
12357
12672
|
const challenge = { id: binding(c, hmacSecret), ...c };
|
|
12358
12673
|
const parts = Object.keys(challenge).filter((k) => challenge[k] !== void 0).map((k) => `${k}=${quote(String(challenge[k]))}`);
|
|
12359
12674
|
return { challenge, header: `Payment ${parts.join(", ")}` };
|
|
@@ -12370,13 +12685,71 @@ function parseMppCredential(header) {
|
|
|
12370
12685
|
return null;
|
|
12371
12686
|
}
|
|
12372
12687
|
}
|
|
12373
|
-
|
|
12688
|
+
var MemoryMppChallengeStore = class {
|
|
12689
|
+
constructor(defaultTtlMs = 60 * 60 * 1e3, now = Date.now) {
|
|
12690
|
+
this.defaultTtlMs = defaultTtlMs;
|
|
12691
|
+
this.now = now;
|
|
12692
|
+
this.seen = /* @__PURE__ */ new Map();
|
|
12693
|
+
}
|
|
12694
|
+
async consume(id, expiresAt) {
|
|
12695
|
+
const t = this.now();
|
|
12696
|
+
for (const [k, exp] of this.seen) if (exp <= t) this.seen.delete(k);
|
|
12697
|
+
if (this.seen.has(id)) return false;
|
|
12698
|
+
this.seen.set(id, Number.isFinite(expiresAt) ? expiresAt : t + this.defaultTtlMs);
|
|
12699
|
+
return true;
|
|
12700
|
+
}
|
|
12701
|
+
};
|
|
12702
|
+
function mppBodyDigest(body) {
|
|
12703
|
+
return `sha-256=${(0, import_crypto9.createHash)("sha256").update(body).digest("base64")}`;
|
|
12704
|
+
}
|
|
12705
|
+
function checkChallenge(challenge, hmacSecret, now) {
|
|
12374
12706
|
const { id, ...rest } = challenge;
|
|
12375
12707
|
const expected = Buffer.from(binding(rest, hmacSecret));
|
|
12376
12708
|
const got = Buffer.from(String(id ?? ""));
|
|
12377
|
-
if (expected.length !== got.length || !(0,
|
|
12378
|
-
|
|
12379
|
-
|
|
12709
|
+
if (expected.length !== got.length || !(0, import_crypto9.timingSafeEqual)(expected, got))
|
|
12710
|
+
return { ok: false, reason: "invalid_id" };
|
|
12711
|
+
if (challenge.expires && Date.parse(challenge.expires) < now.getTime())
|
|
12712
|
+
return { ok: false, reason: "expired" };
|
|
12713
|
+
return { ok: true };
|
|
12714
|
+
}
|
|
12715
|
+
function verifyMppChallenge(challenge, hmacSecret, nowOrOptions = /* @__PURE__ */ new Date()) {
|
|
12716
|
+
if (nowOrOptions instanceof Date) return checkChallenge(challenge, hmacSecret, nowOrOptions).ok;
|
|
12717
|
+
const opts = nowOrOptions;
|
|
12718
|
+
return (async () => {
|
|
12719
|
+
const base = checkChallenge(challenge, hmacSecret, opts.now ?? /* @__PURE__ */ new Date());
|
|
12720
|
+
if (!base.ok) return base;
|
|
12721
|
+
if (challenge.digest) {
|
|
12722
|
+
if (opts.body === void 0) return { ok: false, reason: "body_required" };
|
|
12723
|
+
const want = Buffer.from(challenge.digest);
|
|
12724
|
+
const got = Buffer.from(mppBodyDigest(opts.body));
|
|
12725
|
+
if (want.length !== got.length || !(0, import_crypto9.timingSafeEqual)(want, got))
|
|
12726
|
+
return { ok: false, reason: "digest_mismatch" };
|
|
12727
|
+
}
|
|
12728
|
+
if (opts.store) {
|
|
12729
|
+
const expiresAt = challenge.expires ? Date.parse(challenge.expires) : NaN;
|
|
12730
|
+
if (!await opts.store.consume(challenge.id, expiresAt))
|
|
12731
|
+
return { ok: false, reason: "already_used" };
|
|
12732
|
+
}
|
|
12733
|
+
return { ok: true };
|
|
12734
|
+
})();
|
|
12735
|
+
}
|
|
12736
|
+
function buildMpp402Response(challenges, problem = {}) {
|
|
12737
|
+
const list = Array.isArray(challenges) ? challenges : [challenges];
|
|
12738
|
+
const headers = new Headers({
|
|
12739
|
+
"content-type": "application/problem+json",
|
|
12740
|
+
"cache-control": "no-store"
|
|
12741
|
+
});
|
|
12742
|
+
for (const c of list) headers.append("www-authenticate", typeof c === "string" ? c : c.header);
|
|
12743
|
+
return new Response(
|
|
12744
|
+
JSON.stringify({
|
|
12745
|
+
type: problem.type ?? "about:blank",
|
|
12746
|
+
title: problem.title ?? "Payment Required",
|
|
12747
|
+
status: 402,
|
|
12748
|
+
...problem.detail && { detail: problem.detail },
|
|
12749
|
+
...problem.instance && { instance: problem.instance }
|
|
12750
|
+
}),
|
|
12751
|
+
{ status: 402, headers }
|
|
12752
|
+
);
|
|
12380
12753
|
}
|
|
12381
12754
|
function decodeMppRequest(challenge) {
|
|
12382
12755
|
try {
|
|
@@ -12453,7 +12826,7 @@ async function verifyKyaPayTokens(header, opts) {
|
|
|
12453
12826
|
}
|
|
12454
12827
|
|
|
12455
12828
|
// src/aep/core.ts
|
|
12456
|
-
var
|
|
12829
|
+
var import_crypto10 = require("crypto");
|
|
12457
12830
|
var AEP_SPEC_VERSION = "aep-1.0.3-rc.2";
|
|
12458
12831
|
function aepCanonicalJson(value) {
|
|
12459
12832
|
if (value === null) return "null";
|
|
@@ -12474,7 +12847,7 @@ function aepCanonicalJson(value) {
|
|
|
12474
12847
|
throw new Error(`AEP canonical JSON: unsupported value of type ${typeof value}`);
|
|
12475
12848
|
}
|
|
12476
12849
|
function digest(input) {
|
|
12477
|
-
return (0,
|
|
12850
|
+
return (0, import_crypto10.createHash)("sha256").update(aepCanonicalJson(input), "utf8").digest();
|
|
12478
12851
|
}
|
|
12479
12852
|
function aepHash(input) {
|
|
12480
12853
|
return `sha256:${digest(input).toString("hex")}`;
|
|
@@ -12487,23 +12860,23 @@ var ED25519_SPKI_PREFIX = Buffer.from("302a300506032b6570032100", "hex");
|
|
|
12487
12860
|
function aepPrivateKeyFromSeed(seedBase64) {
|
|
12488
12861
|
const seed = Buffer.from(seedBase64, "base64");
|
|
12489
12862
|
if (seed.length !== 32) throw new Error("Ed25519 seed must be 32 bytes");
|
|
12490
|
-
return (0,
|
|
12863
|
+
return (0, import_crypto10.createPrivateKey)({
|
|
12491
12864
|
key: Buffer.concat([ED25519_PKCS8_PREFIX, seed]),
|
|
12492
12865
|
format: "der",
|
|
12493
12866
|
type: "pkcs8"
|
|
12494
12867
|
});
|
|
12495
12868
|
}
|
|
12496
12869
|
function aepPublicKeyFromBase64(raw) {
|
|
12497
|
-
const
|
|
12498
|
-
if (
|
|
12499
|
-
return (0,
|
|
12500
|
-
key: Buffer.concat([ED25519_SPKI_PREFIX,
|
|
12870
|
+
const bytes2 = Buffer.from(raw, "base64");
|
|
12871
|
+
if (bytes2.length !== 32) throw new Error("Ed25519 public key must be 32 bytes");
|
|
12872
|
+
return (0, import_crypto10.createPublicKey)({
|
|
12873
|
+
key: Buffer.concat([ED25519_SPKI_PREFIX, bytes2]),
|
|
12501
12874
|
format: "der",
|
|
12502
12875
|
type: "spki"
|
|
12503
12876
|
});
|
|
12504
12877
|
}
|
|
12505
12878
|
function aepRawPublicKey(key) {
|
|
12506
|
-
const pub = key.type === "private" ? (0,
|
|
12879
|
+
const pub = key.type === "private" ? (0, import_crypto10.createPublicKey)(key) : key;
|
|
12507
12880
|
return pub.export({ format: "der", type: "spki" }).subarray(12).toString("base64");
|
|
12508
12881
|
}
|
|
12509
12882
|
function hashBytes(currentHash) {
|
|
@@ -12512,11 +12885,11 @@ function hashBytes(currentHash) {
|
|
|
12512
12885
|
return Buffer.from(m[1], "hex");
|
|
12513
12886
|
}
|
|
12514
12887
|
function aepSign(currentHash, privateKey) {
|
|
12515
|
-
return (0,
|
|
12888
|
+
return (0, import_crypto10.sign)(null, hashBytes(currentHash), privateKey).toString("base64");
|
|
12516
12889
|
}
|
|
12517
12890
|
function aepVerifySignature(currentHash, signature, publicKey) {
|
|
12518
12891
|
try {
|
|
12519
|
-
return (0,
|
|
12892
|
+
return (0, import_crypto10.verify)(null, hashBytes(currentHash), publicKey, Buffer.from(signature, "base64"));
|
|
12520
12893
|
} catch {
|
|
12521
12894
|
return false;
|
|
12522
12895
|
}
|
|
@@ -12614,8 +12987,33 @@ function aepPublicKeyDocument(keys, revocations = []) {
|
|
|
12614
12987
|
}
|
|
12615
12988
|
|
|
12616
12989
|
// src/acp/checkout-kit.ts
|
|
12617
|
-
var
|
|
12990
|
+
var import_crypto11 = require("crypto");
|
|
12618
12991
|
var ACP_API_VERSION = "2026-04-17";
|
|
12992
|
+
var ACP_SUPPORTED_API_VERSIONS = [ACP_API_VERSION];
|
|
12993
|
+
function acpPaymentHandlers(names) {
|
|
12994
|
+
return names.map((name, i) => ({
|
|
12995
|
+
id: name.split(".").pop(),
|
|
12996
|
+
name,
|
|
12997
|
+
version: ACP_API_VERSION,
|
|
12998
|
+
spec: `https://astrasync.ai/ucp/handlers/${name}`,
|
|
12999
|
+
requires_delegate_payment: false,
|
|
13000
|
+
requires_pci_compliance: false,
|
|
13001
|
+
psp: "astrasync",
|
|
13002
|
+
config_schema: `https://astrasync.ai/ucp/handlers/${name}.json`,
|
|
13003
|
+
instrument_schemas: [],
|
|
13004
|
+
config: {},
|
|
13005
|
+
display_order: i
|
|
13006
|
+
}));
|
|
13007
|
+
}
|
|
13008
|
+
function buildAcpWellKnown(opts) {
|
|
13009
|
+
return {
|
|
13010
|
+
protocol: "acp",
|
|
13011
|
+
api_versions: [...opts.apiVersions ?? ACP_SUPPORTED_API_VERSIONS],
|
|
13012
|
+
endpoint: opts.endpoint,
|
|
13013
|
+
capabilities: { payment: { handlers: acpPaymentHandlers(opts.paymentHandlers) } },
|
|
13014
|
+
...opts.links?.length && { links: opts.links }
|
|
13015
|
+
};
|
|
13016
|
+
}
|
|
12619
13017
|
var json3 = (status, body) => new Response(JSON.stringify(body), { status, headers: { "content-type": "application/json" } });
|
|
12620
13018
|
var apiError = (status, code, message, param) => json3(status, { type: "invalid_request", code, message, ...param && { param } });
|
|
12621
13019
|
var total2 = (s) => s.totals.find((t) => t.type === "total")?.amount ?? 0;
|
|
@@ -12623,26 +13021,30 @@ function createAcpCheckoutKit(opts) {
|
|
|
12623
13021
|
const mem = /* @__PURE__ */ new Map();
|
|
12624
13022
|
const store = opts.store ?? {
|
|
12625
13023
|
get: async (id) => mem.get(id) ?? null,
|
|
12626
|
-
put: async (s) => void mem.set(s.id, s)
|
|
13024
|
+
put: async (s) => void mem.set(s.id, s),
|
|
13025
|
+
claim: async (id, from, to) => {
|
|
13026
|
+
const s = mem.get(id);
|
|
13027
|
+
if (!s || s.status !== from) return false;
|
|
13028
|
+
s.status = to;
|
|
13029
|
+
return true;
|
|
13030
|
+
}
|
|
12627
13031
|
};
|
|
12628
13032
|
const idem = {
|
|
12629
13033
|
store: opts.idempotencyStore ?? new MemoryIdempotencyStore(),
|
|
12630
13034
|
profile: "acp",
|
|
12631
13035
|
required: true
|
|
12632
13036
|
};
|
|
12633
|
-
|
|
12634
|
-
|
|
12635
|
-
|
|
12636
|
-
|
|
12637
|
-
|
|
12638
|
-
|
|
12639
|
-
|
|
12640
|
-
|
|
12641
|
-
|
|
12642
|
-
|
|
12643
|
-
|
|
12644
|
-
display_order: i
|
|
12645
|
-
}));
|
|
13037
|
+
warnInMemoryStores("ACP", [
|
|
13038
|
+
...opts.store ? [] : ["checkout store"],
|
|
13039
|
+
...opts.idempotencyStore ? [] : ["idempotency store"]
|
|
13040
|
+
]);
|
|
13041
|
+
if (!store.claim) {
|
|
13042
|
+
warnOnce(
|
|
13043
|
+
"acp-claim",
|
|
13044
|
+
"[astrasync] ACP checkout kit: your store has no claim() \u2014 concurrent completes of one session aren't locked. Implement claim(id, from, to) as an atomic compare-and-set."
|
|
13045
|
+
);
|
|
13046
|
+
}
|
|
13047
|
+
const handlers = acpPaymentHandlers(opts.paymentHandlers);
|
|
12646
13048
|
function view(s) {
|
|
12647
13049
|
return {
|
|
12648
13050
|
id: s.id,
|
|
@@ -12697,13 +13099,13 @@ function createAcpCheckoutKit(opts) {
|
|
|
12697
13099
|
]
|
|
12698
13100
|
};
|
|
12699
13101
|
}
|
|
12700
|
-
async function idempotent(req, body, path, run) {
|
|
13102
|
+
async function idempotent(req, body, path, caller, run) {
|
|
12701
13103
|
const d = await beginIdempotent(idem, {
|
|
12702
13104
|
method: req.method,
|
|
12703
13105
|
path,
|
|
12704
13106
|
body,
|
|
12705
13107
|
key: req.headers.get("idempotency-key") ?? void 0,
|
|
12706
|
-
auth:
|
|
13108
|
+
auth: caller
|
|
12707
13109
|
});
|
|
12708
13110
|
if (d.kind === "reject") return apiError(d.status, d.code, d.message);
|
|
12709
13111
|
if (d.kind === "replay")
|
|
@@ -12720,63 +13122,21 @@ function createAcpCheckoutKit(opts) {
|
|
|
12720
13122
|
});
|
|
12721
13123
|
return res;
|
|
12722
13124
|
}
|
|
12723
|
-
|
|
12724
|
-
|
|
12725
|
-
if (!
|
|
12726
|
-
|
|
12727
|
-
|
|
12728
|
-
|
|
12729
|
-
|
|
12730
|
-
|
|
12731
|
-
|
|
12732
|
-
|
|
12733
|
-
});
|
|
12734
|
-
|
|
12735
|
-
|
|
12736
|
-
|
|
12737
|
-
|
|
12738
|
-
s.messages = [
|
|
12739
|
-
{
|
|
12740
|
-
type: "error",
|
|
12741
|
-
code: "approval_required",
|
|
12742
|
-
content: "The buyer needs to approve this purchase.",
|
|
12743
|
-
severity: "medium",
|
|
12744
|
-
resolution: "requires_buyer_review"
|
|
12745
|
-
}
|
|
12746
|
-
];
|
|
12747
|
-
await store.put(s);
|
|
12748
|
-
return json3(200, view(s));
|
|
12749
|
-
}
|
|
12750
|
-
if (!result.identityVerified || !result.policyAllowed) {
|
|
12751
|
-
s.messages = [
|
|
12752
|
-
{
|
|
12753
|
-
type: "error",
|
|
12754
|
-
code: "intervention_required",
|
|
12755
|
-
content: "The agent is not authorized for this purchase.",
|
|
12756
|
-
severity: "high",
|
|
12757
|
-
resolution: "requires_buyer_review"
|
|
12758
|
-
}
|
|
12759
|
-
];
|
|
12760
|
-
await store.put(s);
|
|
12761
|
-
return json3(200, view(s));
|
|
12762
|
-
}
|
|
12763
|
-
s.status = "complete_in_progress";
|
|
12764
|
-
const settled = await opts.settle({
|
|
12765
|
-
session: s,
|
|
12766
|
-
result,
|
|
12767
|
-
paymentData: body.payment_data
|
|
12768
|
-
});
|
|
12769
|
-
const orderId = result.settlementOutcome?.orderId;
|
|
12770
|
-
if (opts.reportSettlement && orderId && settled.status !== "pending") {
|
|
12771
|
-
await opts.reportSettlement({
|
|
12772
|
-
orderId,
|
|
12773
|
-
status: settled.status === "settled" ? "settled" : "failed",
|
|
12774
|
-
...orderReportAmount(result, { amountMinor: total2(s), currency: s.currency }),
|
|
12775
|
-
...settled.status === "settled" && settled.processorRef && { processorRef: settled.processorRef },
|
|
12776
|
-
...settled.status === "settled" && settled.txHash && { txHash: settled.txHash, chainId: settled.chainId },
|
|
12777
|
-
...settled.status === "failed" && settled.failureCode && { failureCode: settled.failureCode }
|
|
12778
|
-
}).catch(() => void 0);
|
|
12779
|
-
}
|
|
13125
|
+
const inProgress = () => apiError(409, "checkout_in_progress", "This checkout session is already being completed.");
|
|
13126
|
+
async function reportOutcome(p, settled) {
|
|
13127
|
+
if (!opts.reportSettlement || !p.orderId) return;
|
|
13128
|
+
await opts.reportSettlement({
|
|
13129
|
+
orderId: p.orderId,
|
|
13130
|
+
status: settled.status,
|
|
13131
|
+
...p.report,
|
|
13132
|
+
...settled.status === "settled" && settled.processorRef && { processorRef: settled.processorRef },
|
|
13133
|
+
...settled.status === "settled" && settled.txHash && { txHash: settled.txHash, chainId: settled.chainId },
|
|
13134
|
+
...settled.status === "failed" && settled.failureCode && { failureCode: settled.failureCode }
|
|
13135
|
+
}).catch(() => void 0);
|
|
13136
|
+
}
|
|
13137
|
+
async function finish(s, result, p, settled) {
|
|
13138
|
+
await reportOutcome(p, settled);
|
|
13139
|
+
delete s._pending;
|
|
12780
13140
|
if (settled.status === "failed") {
|
|
12781
13141
|
s.status = "ready_for_payment";
|
|
12782
13142
|
s.messages = [
|
|
@@ -12789,26 +13149,126 @@ function createAcpCheckoutKit(opts) {
|
|
|
12789
13149
|
}
|
|
12790
13150
|
];
|
|
12791
13151
|
await store.put(s);
|
|
12792
|
-
return
|
|
13152
|
+
return;
|
|
12793
13153
|
}
|
|
12794
13154
|
const order = await opts.fulfil({ session: s, result });
|
|
13155
|
+
const permalink = order.permalink_url ?? (opts.permalinkBase && `${opts.permalinkBase.replace(/\/+$/, "")}/${encodeURIComponent(order.id)}`);
|
|
12795
13156
|
s.order = {
|
|
12796
13157
|
id: order.id,
|
|
13158
|
+
checkout_session_id: s.id,
|
|
12797
13159
|
status: "confirmed",
|
|
12798
13160
|
currency: s.currency.toLowerCase(),
|
|
12799
13161
|
total: total2(s),
|
|
12800
|
-
line_items:
|
|
13162
|
+
line_items: s.line_items.map((l) => ({
|
|
13163
|
+
id: l.id,
|
|
13164
|
+
item: l.item,
|
|
13165
|
+
name: l.name,
|
|
13166
|
+
quantity: l.quantity,
|
|
13167
|
+
unit_amount: l.unit_amount,
|
|
13168
|
+
totals: l.totals
|
|
13169
|
+
})),
|
|
12801
13170
|
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
12802
|
-
...
|
|
13171
|
+
...permalink && { permalink_url: permalink }
|
|
12803
13172
|
};
|
|
12804
13173
|
s.status = "completed";
|
|
12805
13174
|
s.messages = [];
|
|
12806
13175
|
await store.put(s);
|
|
12807
|
-
return json3(200, view(s));
|
|
12808
13176
|
}
|
|
12809
|
-
async function
|
|
12810
|
-
if (
|
|
12811
|
-
|
|
13177
|
+
async function complete(req, s, body) {
|
|
13178
|
+
if (s.status === "completed" || s.status === "canceled") return json3(200, view(s));
|
|
13179
|
+
if (s.status === "complete_in_progress") return inProgress();
|
|
13180
|
+
if (!body.payment_data)
|
|
13181
|
+
return apiError(400, "missing", "payment_data is required.", "$.payment_data");
|
|
13182
|
+
const from = s.status;
|
|
13183
|
+
if (store.claim) {
|
|
13184
|
+
if (!await store.claim(s.id, from, "complete_in_progress")) return inProgress();
|
|
13185
|
+
s.status = "complete_in_progress";
|
|
13186
|
+
} else {
|
|
13187
|
+
s.status = "complete_in_progress";
|
|
13188
|
+
await store.put(s);
|
|
13189
|
+
}
|
|
13190
|
+
try {
|
|
13191
|
+
const result = await opts.verifyPurchase({
|
|
13192
|
+
session: s,
|
|
13193
|
+
checkoutSessionId: s._astraCheckoutSessionId ?? s.id,
|
|
13194
|
+
astraId: req.headers.get("x-astra-id") ?? void 0,
|
|
13195
|
+
attemptId: req.headers.get("x-astra-attempt-id") ?? void 0,
|
|
13196
|
+
valueMajor: total2(s) / 100
|
|
13197
|
+
});
|
|
13198
|
+
if (isHeld(result)) {
|
|
13199
|
+
s.status = "pending_approval";
|
|
13200
|
+
s.continue_url = result.stepUpApproval?.approvalUrl ?? opts.fallbackContinueUrl;
|
|
13201
|
+
s.messages = [
|
|
13202
|
+
{
|
|
13203
|
+
type: "error",
|
|
13204
|
+
code: "approval_required",
|
|
13205
|
+
content: "The buyer needs to approve this purchase.",
|
|
13206
|
+
severity: "medium",
|
|
13207
|
+
resolution: "requires_buyer_review"
|
|
13208
|
+
}
|
|
13209
|
+
];
|
|
13210
|
+
await store.put(s);
|
|
13211
|
+
return json3(200, view(s));
|
|
13212
|
+
}
|
|
13213
|
+
if (!result.identityVerified || !result.policyAllowed) {
|
|
13214
|
+
s.status = from;
|
|
13215
|
+
s.messages = [
|
|
13216
|
+
{
|
|
13217
|
+
type: "error",
|
|
13218
|
+
code: "intervention_required",
|
|
13219
|
+
content: "The agent is not authorized for this purchase.",
|
|
13220
|
+
severity: "high",
|
|
13221
|
+
resolution: "requires_buyer_review"
|
|
13222
|
+
}
|
|
13223
|
+
];
|
|
13224
|
+
await store.put(s);
|
|
13225
|
+
return json3(200, view(s));
|
|
13226
|
+
}
|
|
13227
|
+
const settled = await opts.settle({
|
|
13228
|
+
session: s,
|
|
13229
|
+
result,
|
|
13230
|
+
paymentData: body.payment_data
|
|
13231
|
+
});
|
|
13232
|
+
const orderId = result.settlementOutcome?.orderId;
|
|
13233
|
+
const pending = {
|
|
13234
|
+
...orderId && { orderId },
|
|
13235
|
+
report: orderReportAmount(result, { amountMinor: total2(s), currency: s.currency }),
|
|
13236
|
+
result: pendingResult(result)
|
|
13237
|
+
};
|
|
13238
|
+
if (settled.status === "pending") {
|
|
13239
|
+
s._pending = pending;
|
|
13240
|
+
s.messages = [];
|
|
13241
|
+
await store.put(s);
|
|
13242
|
+
return json3(200, view(s));
|
|
13243
|
+
}
|
|
13244
|
+
await finish(s, result, pending, settled);
|
|
13245
|
+
return json3(200, view(s));
|
|
13246
|
+
} catch (e) {
|
|
13247
|
+
if (s.status === "complete_in_progress" && !s._pending) {
|
|
13248
|
+
s.status = from;
|
|
13249
|
+
await store.put(s).catch(() => void 0);
|
|
13250
|
+
}
|
|
13251
|
+
throw e;
|
|
13252
|
+
}
|
|
13253
|
+
}
|
|
13254
|
+
async function resolvePending(sessionId, outcome) {
|
|
13255
|
+
const s = await store.get(sessionId);
|
|
13256
|
+
if (!s) return null;
|
|
13257
|
+
if (s.status !== "complete_in_progress" || !s._pending) return s;
|
|
13258
|
+
await finish(s, s._pending.result, s._pending, outcome);
|
|
13259
|
+
return s;
|
|
13260
|
+
}
|
|
13261
|
+
async function route(req, reqCtx) {
|
|
13262
|
+
const version = req.headers.get("api-version");
|
|
13263
|
+
if (!version) return apiError(400, "missing", "The API-Version header is required.");
|
|
13264
|
+
if (!ACP_SUPPORTED_API_VERSIONS.includes(version)) {
|
|
13265
|
+
return json3(400, {
|
|
13266
|
+
type: "invalid_request",
|
|
13267
|
+
code: "unsupported_api_version",
|
|
13268
|
+
message: `API-Version ${version} is not supported.`,
|
|
13269
|
+
supported_versions: [...ACP_SUPPORTED_API_VERSIONS]
|
|
13270
|
+
});
|
|
13271
|
+
}
|
|
12812
13272
|
const url = new URL(req.url);
|
|
12813
13273
|
const base = (opts.basePath ?? "").replace(/\/+$/, "");
|
|
12814
13274
|
const path = url.pathname.startsWith(base) ? url.pathname.slice(base.length) : url.pathname;
|
|
@@ -12819,15 +13279,17 @@ function createAcpCheckoutKit(opts) {
|
|
|
12819
13279
|
} catch {
|
|
12820
13280
|
return apiError(400, "invalid", "Body is not JSON.");
|
|
12821
13281
|
}
|
|
12822
|
-
const caller = req.
|
|
13282
|
+
const caller = await resolveCallerScope(req, reqCtx, opts.resolveCallerId);
|
|
13283
|
+
if (!caller)
|
|
13284
|
+
return apiError(401, "unauthorized", "Send an Authorization header (or X-Astra-Id).");
|
|
12823
13285
|
if (req.method === "POST" && path === "/checkout_sessions") {
|
|
12824
|
-
return idempotent(req, body, path, async () => {
|
|
13286
|
+
return idempotent(req, body, path, caller, async () => {
|
|
12825
13287
|
const items = parsed.line_items ?? parsed.items;
|
|
12826
13288
|
if (!items?.length)
|
|
12827
13289
|
return apiError(400, "missing", "line_items is required.", "$.line_items");
|
|
12828
13290
|
const p = await price(items);
|
|
12829
13291
|
const s2 = {
|
|
12830
|
-
id: `cs_${(0,
|
|
13292
|
+
id: `cs_${(0, import_crypto11.randomUUID)().replace(/-/g, "")}`,
|
|
12831
13293
|
status: p.lines.length && !p.messages.length ? "ready_for_payment" : "not_ready_for_payment",
|
|
12832
13294
|
currency: opts.currency,
|
|
12833
13295
|
line_items: p.lines,
|
|
@@ -12849,8 +13311,9 @@ function createAcpCheckoutKit(opts) {
|
|
|
12849
13311
|
if (req.method === "GET" && !m[2]) return json3(200, view(s));
|
|
12850
13312
|
if (req.method !== "POST") return apiError(405, "unsupported", "Method not allowed.");
|
|
12851
13313
|
if (!m[2]) {
|
|
12852
|
-
return idempotent(req, body, path, async () => {
|
|
13314
|
+
return idempotent(req, body, path, caller, async () => {
|
|
12853
13315
|
if (s.status === "completed" || s.status === "canceled") return json3(200, view(s));
|
|
13316
|
+
if (s.status === "complete_in_progress") return inProgress();
|
|
12854
13317
|
const items = parsed.line_items ?? parsed.items;
|
|
12855
13318
|
if (items) {
|
|
12856
13319
|
const p = await price(items);
|
|
@@ -12865,18 +13328,83 @@ function createAcpCheckoutKit(opts) {
|
|
|
12865
13328
|
return json3(200, view(s));
|
|
12866
13329
|
});
|
|
12867
13330
|
}
|
|
12868
|
-
if (m[2] === "/complete")
|
|
12869
|
-
|
|
12870
|
-
|
|
13331
|
+
if (m[2] === "/complete")
|
|
13332
|
+
return idempotent(req, body, path, caller, () => complete(req, s, parsed));
|
|
13333
|
+
return idempotent(req, body, path, caller, async () => {
|
|
13334
|
+
if (s.status === "completed" || s.status === "canceled")
|
|
13335
|
+
return apiError(405, "method_not_allowed", `A ${s.status} session can't be canceled.`);
|
|
13336
|
+
if (s.status === "complete_in_progress") return inProgress();
|
|
13337
|
+
s.status = "canceled";
|
|
12871
13338
|
await store.put(s);
|
|
12872
13339
|
return json3(200, view(s));
|
|
12873
13340
|
});
|
|
12874
13341
|
}
|
|
12875
|
-
|
|
13342
|
+
async function handle(req, reqCtx) {
|
|
13343
|
+
const res = await route(req, reqCtx);
|
|
13344
|
+
const key = req.headers.get("idempotency-key");
|
|
13345
|
+
const requestId = req.headers.get("request-id");
|
|
13346
|
+
if (!key && !requestId) return res;
|
|
13347
|
+
const headers = new Headers(res.headers);
|
|
13348
|
+
if (key) headers.set("idempotency-key", key);
|
|
13349
|
+
if (requestId) headers.set("request-id", requestId);
|
|
13350
|
+
return new Response(res.body, { status: res.status, headers });
|
|
13351
|
+
}
|
|
13352
|
+
return { handle, resolvePending };
|
|
13353
|
+
}
|
|
13354
|
+
|
|
13355
|
+
// src/adapters/kit-express.ts
|
|
13356
|
+
var bytes = (b) => b.buffer.slice(b.byteOffset, b.byteOffset + b.byteLength);
|
|
13357
|
+
function rawBodyOf(req) {
|
|
13358
|
+
if (req.method === "GET" || req.method === "HEAD") return void 0;
|
|
13359
|
+
const raw = req.rawBody;
|
|
13360
|
+
if (Buffer.isBuffer(raw)) return bytes(raw);
|
|
13361
|
+
if (typeof raw === "string") return raw;
|
|
13362
|
+
if (Buffer.isBuffer(req.body)) return bytes(req.body);
|
|
13363
|
+
if (typeof req.body === "string") return req.body;
|
|
13364
|
+
if (req.body !== void 0 && req.body !== null && typeof req.body === "object") {
|
|
13365
|
+
if (Object.keys(req.body).length === 0) return void 0;
|
|
13366
|
+
warnOnce(
|
|
13367
|
+
"kit-express-parsed-body",
|
|
13368
|
+
"[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."
|
|
13369
|
+
);
|
|
13370
|
+
return JSON.stringify(req.body);
|
|
13371
|
+
}
|
|
13372
|
+
return void 0;
|
|
13373
|
+
}
|
|
13374
|
+
function expressHandler(kit, options = {}) {
|
|
13375
|
+
return async (req, res, next) => {
|
|
13376
|
+
try {
|
|
13377
|
+
const host = req.get?.("host") ?? req.headers.host ?? "localhost";
|
|
13378
|
+
const url = `${req.protocol ?? "http"}://${host}${req.originalUrl ?? req.url}`;
|
|
13379
|
+
const headers = new Headers();
|
|
13380
|
+
for (const [k, v] of Object.entries(req.headers)) {
|
|
13381
|
+
if (v === void 0) continue;
|
|
13382
|
+
if (Array.isArray(v)) v.forEach((x) => headers.append(k, x));
|
|
13383
|
+
else headers.set(k, v);
|
|
13384
|
+
}
|
|
13385
|
+
const body = rawBodyOf(req);
|
|
13386
|
+
const request = new Request(url, {
|
|
13387
|
+
method: req.method,
|
|
13388
|
+
headers,
|
|
13389
|
+
...body !== void 0 && { body }
|
|
13390
|
+
});
|
|
13391
|
+
const verified = req.agentVerification?.identityVerified ? req.agentVerification.agent?.astraId : void 0;
|
|
13392
|
+
const callerId = options.callerId ? options.callerId(req) : verified;
|
|
13393
|
+
const response = await kit.handle(request, callerId ? { callerId } : void 0);
|
|
13394
|
+
res.status(response.status);
|
|
13395
|
+
response.headers.forEach((value, name) => {
|
|
13396
|
+
res.setHeader(name, value);
|
|
13397
|
+
});
|
|
13398
|
+
res.end(Buffer.from(await response.arrayBuffer()));
|
|
13399
|
+
} catch (err) {
|
|
13400
|
+
next(err);
|
|
13401
|
+
}
|
|
13402
|
+
};
|
|
12876
13403
|
}
|
|
12877
13404
|
// Annotate the CommonJS export names for ESM import in node:
|
|
12878
13405
|
0 && (module.exports = {
|
|
12879
13406
|
ACP_API_VERSION,
|
|
13407
|
+
ACP_SUPPORTED_API_VERSIONS,
|
|
12880
13408
|
AEP_SPEC_VERSION,
|
|
12881
13409
|
AP2_VCT,
|
|
12882
13410
|
AepChain,
|
|
@@ -12897,6 +13425,7 @@ function createAcpCheckoutKit(opts) {
|
|
|
12897
13425
|
MCP_VERIFIED_HOP_MAX_AGE_MS,
|
|
12898
13426
|
MemoryCheckoutStore,
|
|
12899
13427
|
MemoryIdempotencyStore,
|
|
13428
|
+
MemoryMppChallengeStore,
|
|
12900
13429
|
PLATFORM_AGENT_SIGNATURES,
|
|
12901
13430
|
RUNTIME_SIGNATURES,
|
|
12902
13431
|
RedisIdempotencyStore,
|
|
@@ -12906,10 +13435,12 @@ function createAcpCheckoutKit(opts) {
|
|
|
12906
13435
|
SDK_USER_AGENT,
|
|
12907
13436
|
SettlementReportError,
|
|
12908
13437
|
TRUST_LEVEL_RANGES,
|
|
13438
|
+
UCP_ORDER_CAPABILITY,
|
|
12909
13439
|
UCP_VERSION,
|
|
12910
13440
|
VERIFICATION_STATUS_HEADER,
|
|
12911
13441
|
VERSION,
|
|
12912
13442
|
_resetEdgeConfigCache,
|
|
13443
|
+
acpPaymentHandlers,
|
|
12913
13444
|
aepCanonicalJson,
|
|
12914
13445
|
aepHash,
|
|
12915
13446
|
aepPrivateKeyFromSeed,
|
|
@@ -12924,9 +13455,12 @@ function createAcpCheckoutKit(opts) {
|
|
|
12924
13455
|
authorizeSettlement,
|
|
12925
13456
|
awaitStepUpApproval,
|
|
12926
13457
|
beginIdempotent,
|
|
13458
|
+
buildAcpWellKnown,
|
|
12927
13459
|
buildGuidance,
|
|
13460
|
+
buildMpp402Response,
|
|
12928
13461
|
buildMppChallenge,
|
|
12929
13462
|
buildSdkObservedMetadata,
|
|
13463
|
+
buildUcpOrder,
|
|
12930
13464
|
buildUcpProfile,
|
|
12931
13465
|
buildVerificationUnavailableBody,
|
|
12932
13466
|
buildX402Challenge,
|
|
@@ -12950,6 +13484,7 @@ function createAcpCheckoutKit(opts) {
|
|
|
12950
13484
|
encodeMppReceipt,
|
|
12951
13485
|
encodeX402SettlementResponse,
|
|
12952
13486
|
express,
|
|
13487
|
+
expressHandler,
|
|
12953
13488
|
extractApiKeyFormat,
|
|
12954
13489
|
extractCredentials,
|
|
12955
13490
|
extractMcpCredentials,
|
|
@@ -12974,6 +13509,7 @@ function createAcpCheckoutKit(opts) {
|
|
|
12974
13509
|
matchEdgePathRule,
|
|
12975
13510
|
matchPlatformSignature,
|
|
12976
13511
|
matchRoutePattern,
|
|
13512
|
+
mppBodyDigest,
|
|
12977
13513
|
negotiateUcp,
|
|
12978
13514
|
nextjs,
|
|
12979
13515
|
normalizeDeclaredSource,
|