1import assert from "node:assert/strict";2import { operation, validate } from "./contract.mjs";3 4// Run on the app backend; the provider still authenticates the store evidence.5export function toVerifyPurchaseInput(purchase, context = {}) {6 const { store, purchaseToken } = purchase ?? {};7 let input;8 const required = (value) => {9 if (typeof value !== "string" || !value.trim())10 throw new Error("Purchase evidence is required");11 return value;12 };13 switch (store) {14 case "apple":15 input = { store, apple: { jws: required(purchaseToken) } };16 break;17 case "google":18 input = { store, google: { purchaseToken: required(purchaseToken) } };19 break;20 case "amazon":21 input = {22 store,23 amazon: {24 userId: required(context.storeUserId),25 receiptId: required(purchaseToken),26 ...(context.amazonSandbox === true ? { sandbox: true } : {}),27 },28 };29 break;30 case "horizon":31 input = {32 store,33 horizon: {34 userId: required(context.storeUserId),35 sku: required(purchase.productId),36 },37 };38 break;39 default:40 throw new Error("Unsupported purchase store");41 }42 if (!validate(operation("verifyPurchase").input, input))43 throw new Error("Purchase evidence does not match the protocol input");44 return input;45}46 47export function runBridgeDemo() {48 const checks = [];49 for (const store of ["apple", "google"]) {50 const token = `fictional-${store}-evidence`;51 const input = toVerifyPurchaseInput({52 store,53 purchaseToken: token,54 productId: "premium.monthly",55 userId: "untrusted-client-claim",56 });57 assert.deepEqual(input, {58 store,59 ...(store === "apple"60 ? { apple: { jws: token } }61 : { google: { purchaseToken: token } }),62 });63 checks.push(`${store}: maps evidence without forwarding client identity`);64 assert(validate(operation("verifyPurchase").input, input));65 checks.push(`${store}: matches the installed verification input schema`);66 }67 for (const store of ["amazon", "horizon"]) {68 const input = toVerifyPurchaseInput(69 {70 store,71 purchaseToken: "receipt-1",72 productId: "premium.monthly",73 userId: "untrusted-app-user",74 },75 { storeUserId: "authenticated-store-user", amazonSandbox: true },76 );77 assert.deepEqual(78 input,79 store === "amazon"80 ? {81 store,82 amazon: {83 userId: "authenticated-store-user",84 receiptId: "receipt-1",85 sandbox: true,86 },87 }88 : {89 store,90 horizon: {91 userId: "authenticated-store-user",92 sku: "premium.monthly",93 },94 },95 );96 checks.push(97 `${store}: uses server-selected store identity, distinct from the app user`,98 );99 assert(validate(operation("verifyPurchase").input, input));100 checks.push(`${store}: matches the installed verification input schema`);101 }102 for (const [label, purchase] of [103 ["missing purchase", null],104 ["unknown store", { store: "unknown", purchaseToken: "fictional" }],105 [106 "Amazon requires its authenticated store user",107 { store: "amazon", purchaseToken: "fictional" },108 ],109 [110 "Horizon requires its authenticated store user",111 { store: "horizon", purchaseToken: "fictional" },112 ],113 ["missing evidence", { store: "apple" }],114 ["blank evidence", { store: "google", purchaseToken: " " }],115 ["non-string evidence", { store: "apple", purchaseToken: 123 }],116 [117 "oversized evidence",118 { store: "apple", purchaseToken: "x".repeat(16385) },119 ],120 ]) {121 assert.throws(() => toVerifyPurchaseInput(purchase), Error);122 checks.push(`Rejects ${label}`);123 }124 return checks;125}126 127if (import.meta.main)128 console.log(129 `Client boundary: ${runBridgeDemo().length} checks passed against the installed contract. Fixture fields only; no SDK checkout or store contacted.`,130 );131