@tokenoftrust/storefront-runner 3.10.2 → 3.10.4
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/apps/storefront/migrations-apps/0019_commerce_source_authority.sql +23 -0
- package/apps/storefront/src/lib/checkout/commerce/finalCartAuthorization.ts +15 -3
- package/apps/storefront/src/lib/fulfillment/commerceRecovery.ts +7 -5
- package/apps/storefront/src/lib/fulfillment/fulfillmentService.ts +39 -12
- package/apps/storefront/src/lib/fulfillment/readiness.ts +8 -1
- package/apps/storefront/src/lib/integrations/webhooks/deliveryEngine.ts +23 -25
- package/apps/storefront/src/lib/inventory/allocations.ts +22 -13
- package/apps/storefront/src/lib/orders/data/orderForwardReceiver.ts +37 -7
- package/apps/storefront/src/lib/orders/data/ordersStore.ts +9 -2
- package/apps/storefront/src/lib/orders/data/sourceAuthorityContract.ts +379 -0
- package/apps/storefront/src/lib/orders/data/sourceAuthorityStore.ts +830 -0
- package/apps/storefront/src/pages/api/commerce/final-cart-authorization.ts +13 -6
- package/package.json +1 -1
- package/packages/public-runtime/src/checkout-orders.ts +1 -1
|
@@ -233,12 +233,17 @@ async function authorize(context: APIContext): Promise<Response> {
|
|
|
233
233
|
const requirements = await readCheckoutRequirements(tenant.tenant_id, contentEnv);
|
|
234
234
|
if (!requirements) return deny("checkout-requirements-unreadable", 503);
|
|
235
235
|
const policy = testStoreEvidencePolicy(requirements);
|
|
236
|
+
// Stock is tracked only for a tenant that declares the `mirror` provider. An undeclared tenant
|
|
237
|
+
// has no balance to read, so its stock evidence is honestly `not-required`, not a refusal.
|
|
238
|
+
const stockTracked = tenant.inventory?.provider === "mirror";
|
|
236
239
|
const authorities = [];
|
|
237
|
-
|
|
238
|
-
|
|
240
|
+
if (stockTracked) {
|
|
241
|
+
for (const sku of new Set(snapshot.lines.map(line => line.sku))) {
|
|
242
|
+
authorities.push(await readMirrorStock(queryable, { tenantId: snapshot.tenantId, stage: snapshot.stage, sku, locationId: "unspecified", now, maxAgeMs: 15 * 60_000 }));
|
|
243
|
+
}
|
|
239
244
|
}
|
|
240
245
|
const stockExpiry = Math.min(...authorities.flatMap(authority => authority ? [Date.parse(authority.asOf) + 15 * 60_000] : []));
|
|
241
|
-
const evidence: CommerceEvidence = { verification: "absent", tax: "absent", risk: "absent", stock: "fresh" };
|
|
246
|
+
const evidence: CommerceEvidence = { verification: "absent", tax: "absent", risk: "absent", stock: stockTracked ? "fresh" : "not-required" };
|
|
242
247
|
const expiresAt = existing?.expiresAt ?? new Date(Math.min(Date.now() + 5 * 60_000, stockExpiry)).toISOString();
|
|
243
248
|
const provenance = {} as CommerceEvidenceProvenance;
|
|
244
249
|
for (const field of ["verification", "tax", "risk"] as const) {
|
|
@@ -247,7 +252,9 @@ async function authorize(context: APIContext): Promise<Response> {
|
|
|
247
252
|
provenance[field] = { requirement: "not-required", state: "not-required", source: SHARED_STORE_POLICY_SOURCE, policyRevision: SHARED_STORE_POLICY_REVISION, expiresAt };
|
|
248
253
|
}
|
|
249
254
|
}
|
|
250
|
-
provenance.stock =
|
|
255
|
+
provenance.stock = stockTracked
|
|
256
|
+
? { requirement: "required", state: "satisfied", source: "tenant-inventory-movements", policyRevision: "mirror-v1", expiresAt }
|
|
257
|
+
: { requirement: "not-required", state: "not-required", source: "tenant-inventory-undeclared", policyRevision: "untracked-v1", expiresAt };
|
|
251
258
|
const presented: FinalCartBinding = { tenantId: snapshot.tenantId, stage: snapshot.stage, currency: snapshot.currency, lines: snapshot.lines,
|
|
252
259
|
destinationDigest: snapshot.destinationDigest, verificationExpiresAt: expiresAt, taxExpiresAt: expiresAt };
|
|
253
260
|
const seamView = await seam(authorityContext, snapshot, selected, policy);
|
|
@@ -257,7 +264,7 @@ async function authorize(context: APIContext): Promise<Response> {
|
|
|
257
264
|
}
|
|
258
265
|
const decision = await evaluateFinalCart({ now, routedTenantId: commerceTenantId(tenant), quoted: presented, presented, evidence,
|
|
259
266
|
seam: seamView, catalogAvailable: true, browserConfirmed: false, token,
|
|
260
|
-
trustedIssuers: issuers, expectedAudience: audience, activeKids, authorities });
|
|
267
|
+
trustedIssuers: issuers, expectedAudience: audience, activeKids, stockTracked, authorities });
|
|
261
268
|
if (!decision.ok) {
|
|
262
269
|
if (decision.finding === "verification-refused:flavored_prohibited" && seamView.flavors) {
|
|
263
270
|
return json({ ok: false, finding: decision.finding, flavors: seamView.flavors }, 409);
|
|
@@ -269,7 +276,7 @@ async function authorize(context: APIContext): Promise<Response> {
|
|
|
269
276
|
const cartDigest = existing?.cartDigest ?? await digest(`commerce-provider-cart-v1\n${snapshot.providerCartId}\n${snapshot.providerCartDigest}`);
|
|
270
277
|
const reserved = await reserveAllocation(d1CommerceRunner(database), { tenantId: decision.tenantId, stage: decision.stage, orderId: authorizationId,
|
|
271
278
|
cartDigest, expiresAt: decision.expiresAt, now, currency: snapshot.currency, amountMinor: snapshot.totals.totalMinor,
|
|
272
|
-
issuer: decision.issuer, jti: decision.jti, holds: decision.holds,
|
|
279
|
+
issuer: decision.issuer, jti: decision.jti, holds: decision.holds, stockUntracked: !stockTracked,
|
|
273
280
|
providerCart: { provider: snapshot.provider, id: snapshot.providerCartId, digest: snapshot.providerCartDigest, expectedAuthorizationId: snapshot.expectedAuthorizationId },
|
|
274
281
|
admissionStatement: admissionSnapshotStatement({ ...snapshot, authorizationId, cartDigest, evidence, provenance, expiresAt: decision.expiresAt, now }),
|
|
275
282
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tokenoftrust/storefront-runner",
|
|
3
|
-
"version": "3.10.
|
|
3
|
+
"version": "3.10.4",
|
|
4
4
|
"license": "SEE LICENSE IN LICENSE",
|
|
5
5
|
"description": "World-shareable storefront runner: multi-tenant renderer on Astro/Cloudflare. No control plane.",
|
|
6
6
|
"packageManager": "pnpm@11.9.0",
|
|
@@ -401,7 +401,7 @@ export type CallerTokenRefusal =
|
|
|
401
401
|
| "stage";
|
|
402
402
|
|
|
403
403
|
export function evidencePermitsRelease(evidence: CommerceEvidence): boolean {
|
|
404
|
-
return
|
|
404
|
+
return (["verification", "tax", "risk", "stock"] as const)
|
|
405
405
|
.every(field => evidence[field] === "fresh" || evidence[field] === "not-required");
|
|
406
406
|
}
|
|
407
407
|
|