@stardeck-customer-apps/testing 0.11.0 → 0.13.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/SKILL.md +40 -2
- package/dist/index.d.mts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +45 -0
- package/dist/index.mjs +45 -0
- package/dist/next/headers-shim.js +1 -0
- package/dist/next/headers-shim.mjs +1 -0
- package/dist/setup.js +41 -0
- package/dist/setup.mjs +41 -0
- package/package.json +1 -1
package/SKILL.md
CHANGED
|
@@ -193,6 +193,21 @@ await app.payments.deliverBeamEvent(beamPost, {
|
|
|
193
193
|
// charge-failure or expiry event for bolt payments.
|
|
194
194
|
// EXPIRED is derived from expiresAt on read, never stored.
|
|
195
195
|
|
|
196
|
+
// Fail exactly one real SDK call, then let the next poll recover normally.
|
|
197
|
+
app.payments.failNext("beam.getPaymentLinkStatus", {
|
|
198
|
+
status: 503,
|
|
199
|
+
message: "Beam is temporarily unavailable",
|
|
200
|
+
});
|
|
201
|
+
await expect(payments.getPaymentLinkStatus("plink_test_1")).rejects.toMatchObject({
|
|
202
|
+
statusCode: 503,
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
// Network failures reject fetch instead of returning a PaymentError response.
|
|
206
|
+
app.payments.failNext("stripe.getCheckoutSessionStatus", {
|
|
207
|
+
kind: "network",
|
|
208
|
+
message: "connection reset",
|
|
209
|
+
});
|
|
210
|
+
|
|
196
211
|
// File upload
|
|
197
212
|
const storage = new StorageClient();
|
|
198
213
|
await storage.upload(new File(["hi"], "note.txt", { type: "text/plain" }));
|
|
@@ -285,7 +300,14 @@ expect(app.edge.latestDisplay()?.action).toBe("show");
|
|
|
285
300
|
- `app.issueSession(partial?)` — mint access/refresh tokens for cookie-based
|
|
286
301
|
auth flows (`__stardeck:sess`).
|
|
287
302
|
- `app.inbox` — emails sent through the email-sdk: `.latest(addr?)`,
|
|
288
|
-
`.to(addr)`, `.all()`, `.count`, `.clear()`.
|
|
303
|
+
`.to(addr)`, `.all()`, `.count`, `.clear()`. Each captured email carries
|
|
304
|
+
`headers` (`{}` when none were set), so a reply that should thread onto an
|
|
305
|
+
inbound conversation can be asserted:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
expect(app.inbox.latest()?.headers["In-Reply-To"]).toBe("<original@mail.example>");
|
|
309
|
+
```
|
|
310
|
+
|
|
289
311
|
- `app.identities` — the platform-identity directory created through
|
|
290
312
|
integrations-sdk `client.identities`: `.get(id)`, `.links(id)`, `.all()`,
|
|
291
313
|
`.count`, `.clear()`. The test-only `.seedVerifiedLink(id, { kind,
|
|
@@ -295,6 +317,8 @@ externalId })` helper models a trusted platform/channel link, and
|
|
|
295
317
|
identities through the integrations SDK.
|
|
296
318
|
- `app.payments` — checkouts created through payments-sdk:
|
|
297
319
|
`.checkouts`, `.latest()`, `.setProducts()`, `.markPaid(id)`,
|
|
320
|
+
`.setSessionStatus(id, status)`, `.setPaymentLinkStatus(id, status)`,
|
|
321
|
+
`.failNext(operation, failure)`,
|
|
298
322
|
`.deliverStripeEvent(handler, event)`, `.deliverBeamEvent(handler, event)`,
|
|
299
323
|
Bolt+ controls: `.approveBoltIntent(id)`, `.declineBoltIntent(id)`,
|
|
300
324
|
`.expireBoltIntent(id)`, `.listBoltIntents()`, `.getBoltIntent(id)`,
|
|
@@ -378,7 +402,21 @@ cursor, limit })`; `list()` intentionally keeps its previous array shape.
|
|
|
378
402
|
connections/intents/charges, product list) — captured in `app.payments`;
|
|
379
403
|
fulfill checkout via `markPaid` (poll) or `deliverStripeEvent` /
|
|
380
404
|
`deliverBeamEvent` (webhook push). Drive a terminal without hardware via
|
|
381
|
-
`approveBoltIntent` / `declineBoltIntent` / `expireBoltIntent`.
|
|
405
|
+
`approveBoltIntent` / `declineBoltIntent` / `expireBoltIntent`. Beam payment-link
|
|
406
|
+
polling returns the app's original `order.referenceId`; playground project
|
|
407
|
+
scoping is an internal control-plane detail and must not be handled in app code.
|
|
408
|
+
- Payment outcomes are controllable without bypassing the SDK: Stripe sessions
|
|
409
|
+
support `open`, `complete`, and `expired` with `paid`, `unpaid`, or
|
|
410
|
+
`no_payment_required`; Beam links support `ACTIVE`, `DISABLED`, `EXPIRED`,
|
|
411
|
+
`PAID`, `VOIDED`, and `REFUNDED`; Bolt+ supports approve, decline, expiry, and
|
|
412
|
+
cancellation through the real SDK call. Use `app.payments.failNext()` for
|
|
413
|
+
one-shot HTTP or network failures during Stripe checkout creation/status polling
|
|
414
|
+
and Beam payment-link creation/status polling. The operation names are
|
|
415
|
+
`stripe.createCheckout`, `stripe.getCheckoutSessionStatus`,
|
|
416
|
+
`beam.createPaymentLink`, and `beam.getPaymentLinkStatus`. HTTP failures support
|
|
417
|
+
statuses 400, 402, 409, 429, 500, and 503 plus optional `code`, `details`, and
|
|
418
|
+
`retryAfterSeconds`; `{ kind: "network", message }` rejects fetch instead.
|
|
419
|
+
`app.reset()` clears pending failures.
|
|
382
420
|
- `StorageClient` (upload/list/get/patch/delete, presigned upload) — captured
|
|
383
421
|
in `app.storage` against the simulated `STORAGE_URL` host.
|
|
384
422
|
- `client.slack` / `client.line` / `client.facebook` send endpoints — captured
|
package/dist/index.d.mts
CHANGED
|
@@ -53,6 +53,11 @@ interface CapturedEmail {
|
|
|
53
53
|
html?: string;
|
|
54
54
|
text?: string;
|
|
55
55
|
replyTo?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Raw headers the sender attached, e.g. the `In-Reply-To` / `References` pair
|
|
58
|
+
* that threads a reply onto an inbound conversation. Empty when none were set.
|
|
59
|
+
*/
|
|
60
|
+
headers: Record<string, string>;
|
|
56
61
|
attachments: Array<{
|
|
57
62
|
filename: string;
|
|
58
63
|
contentType?: string;
|
|
@@ -133,6 +138,18 @@ interface CapturedCheckout {
|
|
|
133
138
|
metadata?: Record<string, string>;
|
|
134
139
|
createdAt: Date;
|
|
135
140
|
}
|
|
141
|
+
type PaymentSimulatorOperation = "stripe.createCheckout" | "stripe.getCheckoutSessionStatus" | "beam.createPaymentLink" | "beam.getPaymentLinkStatus";
|
|
142
|
+
type PaymentSimulatorFailure = {
|
|
143
|
+
kind?: "http";
|
|
144
|
+
status: 400 | 402 | 409 | 429 | 500 | 503;
|
|
145
|
+
message: string;
|
|
146
|
+
code?: string;
|
|
147
|
+
details?: unknown;
|
|
148
|
+
retryAfterSeconds?: number;
|
|
149
|
+
} | {
|
|
150
|
+
kind: "network";
|
|
151
|
+
message: string;
|
|
152
|
+
};
|
|
136
153
|
/** Simulated Bolt+ connection as returned by the control-plane store API. */
|
|
137
154
|
interface SimBoltConnection {
|
|
138
155
|
id: string;
|
|
@@ -184,6 +201,8 @@ interface TestPayments {
|
|
|
184
201
|
get checkouts(): CapturedCheckout[];
|
|
185
202
|
latest(): CapturedCheckout | undefined;
|
|
186
203
|
setProducts(products: _stardeck_customer_apps_payments_sdk.Product[]): void;
|
|
204
|
+
/** Fail the next matching SDK request once, then resume normal simulator behavior. */
|
|
205
|
+
failNext(operation: PaymentSimulatorOperation, failure: PaymentSimulatorFailure): void;
|
|
187
206
|
markPaid(id: string): void;
|
|
188
207
|
setSessionStatus(id: string, status: Partial<_stardeck_customer_apps_payments_sdk.CheckoutSessionStatus>): void;
|
|
189
208
|
setPaymentLinkStatus(id: string, status: _stardeck_customer_apps_payments_sdk.BeamPaymentLinkStatus): void;
|
|
@@ -545,4 +564,4 @@ declare const TEST_ENV_DEFAULTS: {
|
|
|
545
564
|
/** Default location of the DDL snapshot written by `generate-types`. */
|
|
546
565
|
declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
|
|
547
566
|
|
|
548
|
-
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedTestPrint, type CapturedUpload, DATA_STORE_TEST_HOST, DATA_STORE_TEST_URL, DEFAULT_SCHEMA_PATH, type DeviceInfo, type PeripheralInfo, STORAGE_TEST_HOST, STORAGE_TEST_URL, type SessionTokens, type SimBoltCharge, type SimBoltConnection, type SimBoltIntentRecord, type SimBoltIntentStatus, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
|
567
|
+
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedTestPrint, type CapturedUpload, DATA_STORE_TEST_HOST, DATA_STORE_TEST_URL, DEFAULT_SCHEMA_PATH, type DeviceInfo, type PaymentSimulatorFailure, type PaymentSimulatorOperation, type PeripheralInfo, STORAGE_TEST_HOST, STORAGE_TEST_URL, type SessionTokens, type SimBoltCharge, type SimBoltConnection, type SimBoltIntentRecord, type SimBoltIntentStatus, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
package/dist/index.d.ts
CHANGED
|
@@ -53,6 +53,11 @@ interface CapturedEmail {
|
|
|
53
53
|
html?: string;
|
|
54
54
|
text?: string;
|
|
55
55
|
replyTo?: string;
|
|
56
|
+
/**
|
|
57
|
+
* Raw headers the sender attached, e.g. the `In-Reply-To` / `References` pair
|
|
58
|
+
* that threads a reply onto an inbound conversation. Empty when none were set.
|
|
59
|
+
*/
|
|
60
|
+
headers: Record<string, string>;
|
|
56
61
|
attachments: Array<{
|
|
57
62
|
filename: string;
|
|
58
63
|
contentType?: string;
|
|
@@ -133,6 +138,18 @@ interface CapturedCheckout {
|
|
|
133
138
|
metadata?: Record<string, string>;
|
|
134
139
|
createdAt: Date;
|
|
135
140
|
}
|
|
141
|
+
type PaymentSimulatorOperation = "stripe.createCheckout" | "stripe.getCheckoutSessionStatus" | "beam.createPaymentLink" | "beam.getPaymentLinkStatus";
|
|
142
|
+
type PaymentSimulatorFailure = {
|
|
143
|
+
kind?: "http";
|
|
144
|
+
status: 400 | 402 | 409 | 429 | 500 | 503;
|
|
145
|
+
message: string;
|
|
146
|
+
code?: string;
|
|
147
|
+
details?: unknown;
|
|
148
|
+
retryAfterSeconds?: number;
|
|
149
|
+
} | {
|
|
150
|
+
kind: "network";
|
|
151
|
+
message: string;
|
|
152
|
+
};
|
|
136
153
|
/** Simulated Bolt+ connection as returned by the control-plane store API. */
|
|
137
154
|
interface SimBoltConnection {
|
|
138
155
|
id: string;
|
|
@@ -184,6 +201,8 @@ interface TestPayments {
|
|
|
184
201
|
get checkouts(): CapturedCheckout[];
|
|
185
202
|
latest(): CapturedCheckout | undefined;
|
|
186
203
|
setProducts(products: _stardeck_customer_apps_payments_sdk.Product[]): void;
|
|
204
|
+
/** Fail the next matching SDK request once, then resume normal simulator behavior. */
|
|
205
|
+
failNext(operation: PaymentSimulatorOperation, failure: PaymentSimulatorFailure): void;
|
|
187
206
|
markPaid(id: string): void;
|
|
188
207
|
setSessionStatus(id: string, status: Partial<_stardeck_customer_apps_payments_sdk.CheckoutSessionStatus>): void;
|
|
189
208
|
setPaymentLinkStatus(id: string, status: _stardeck_customer_apps_payments_sdk.BeamPaymentLinkStatus): void;
|
|
@@ -545,4 +564,4 @@ declare const TEST_ENV_DEFAULTS: {
|
|
|
545
564
|
/** Default location of the DDL snapshot written by `generate-types`. */
|
|
546
565
|
declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
|
|
547
566
|
|
|
548
|
-
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedTestPrint, type CapturedUpload, DATA_STORE_TEST_HOST, DATA_STORE_TEST_URL, DEFAULT_SCHEMA_PATH, type DeviceInfo, type PeripheralInfo, STORAGE_TEST_HOST, STORAGE_TEST_URL, type SessionTokens, type SimBoltCharge, type SimBoltConnection, type SimBoltIntentRecord, type SimBoltIntentStatus, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
|
567
|
+
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedTestPrint, type CapturedUpload, DATA_STORE_TEST_HOST, DATA_STORE_TEST_URL, DEFAULT_SCHEMA_PATH, type DeviceInfo, type PaymentSimulatorFailure, type PaymentSimulatorOperation, type PeripheralInfo, STORAGE_TEST_HOST, STORAGE_TEST_URL, type SessionTokens, type SimBoltCharge, type SimBoltConnection, type SimBoltIntentRecord, type SimBoltIntentStatus, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
package/dist/index.js
CHANGED
|
@@ -108,6 +108,7 @@ var state = globalSingleton("state", () => ({
|
|
|
108
108
|
checkoutCounter: 0,
|
|
109
109
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
110
110
|
paymentLinks: /* @__PURE__ */ new Map(),
|
|
111
|
+
paymentFailures: [],
|
|
111
112
|
products: [],
|
|
112
113
|
boltConnections: /* @__PURE__ */ new Map(),
|
|
113
114
|
boltUsedPairingCodes: /* @__PURE__ */ new Set(),
|
|
@@ -660,6 +661,7 @@ async function handleEmailSend(request) {
|
|
|
660
661
|
html: body.html ? String(body.html) : void 0,
|
|
661
662
|
text: body.text ? String(body.text) : void 0,
|
|
662
663
|
replyTo: body.replyTo ? String(body.replyTo) : void 0,
|
|
664
|
+
headers: { ...body.headers ?? {} },
|
|
663
665
|
attachments: (body.attachments ?? []).map((a) => ({
|
|
664
666
|
filename: String(a.filename ?? ""),
|
|
665
667
|
contentType: a.contentType ? String(a.contentType) : void 0
|
|
@@ -1273,6 +1275,43 @@ function payErr(error, status = 400, code, details) {
|
|
|
1273
1275
|
if (details !== void 0) body.details = details;
|
|
1274
1276
|
return json(body, status);
|
|
1275
1277
|
}
|
|
1278
|
+
function paymentOperationForRequest(request, pathname) {
|
|
1279
|
+
if (request.method === "POST" && /^\/api\/store\/beam\/[^/]+\/payment-links$/.test(pathname)) {
|
|
1280
|
+
return "beam.createPaymentLink";
|
|
1281
|
+
}
|
|
1282
|
+
if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/payment-links\/[^/]+$/.test(pathname)) {
|
|
1283
|
+
return "beam.getPaymentLinkStatus";
|
|
1284
|
+
}
|
|
1285
|
+
if (request.method === "POST" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout$/.test(pathname)) {
|
|
1286
|
+
return "stripe.createCheckout";
|
|
1287
|
+
}
|
|
1288
|
+
if (request.method === "GET" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout-sessions\/[^/]+$/.test(pathname)) {
|
|
1289
|
+
return "stripe.getCheckoutSessionStatus";
|
|
1290
|
+
}
|
|
1291
|
+
return null;
|
|
1292
|
+
}
|
|
1293
|
+
function consumePaymentFailure(request, pathname) {
|
|
1294
|
+
const operation = paymentOperationForRequest(request, pathname);
|
|
1295
|
+
if (!operation) return null;
|
|
1296
|
+
const index = state.paymentFailures.findIndex((entry) => entry.operation === operation);
|
|
1297
|
+
if (index === -1) return null;
|
|
1298
|
+
const [{ failure: failure2 }] = state.paymentFailures.splice(index, 1);
|
|
1299
|
+
if (failure2.kind === "network") {
|
|
1300
|
+
throw new TypeError(failure2.message);
|
|
1301
|
+
}
|
|
1302
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
1303
|
+
if (failure2.retryAfterSeconds !== void 0) {
|
|
1304
|
+
headers.set("Retry-After", String(failure2.retryAfterSeconds));
|
|
1305
|
+
}
|
|
1306
|
+
return new Response(
|
|
1307
|
+
JSON.stringify({
|
|
1308
|
+
error: failure2.message,
|
|
1309
|
+
code: failure2.code ?? "REQUEST_ERROR",
|
|
1310
|
+
...failure2.details !== void 0 ? { details: failure2.details } : {}
|
|
1311
|
+
}),
|
|
1312
|
+
{ status: failure2.status, headers }
|
|
1313
|
+
);
|
|
1314
|
+
}
|
|
1276
1315
|
function isBoltPaymentMethod(value) {
|
|
1277
1316
|
return typeof value === "string" && BEAM_BOLT_PAYMENT_METHODS.includes(value);
|
|
1278
1317
|
}
|
|
@@ -1416,6 +1455,8 @@ async function deliverEvent(envelope, handler, options) {
|
|
|
1416
1455
|
}
|
|
1417
1456
|
async function handlePaymentsRequest(request, url) {
|
|
1418
1457
|
const pathname = url.pathname;
|
|
1458
|
+
const injectedFailure = consumePaymentFailure(request, pathname);
|
|
1459
|
+
if (injectedFailure) return injectedFailure;
|
|
1419
1460
|
if (/\/billing-portal$/.test(pathname)) {
|
|
1420
1461
|
return payErr("Not found", 404, "NOT_FOUND");
|
|
1421
1462
|
}
|
|
@@ -1710,6 +1751,9 @@ function createPayments() {
|
|
|
1710
1751
|
setProducts(products) {
|
|
1711
1752
|
state.products = products;
|
|
1712
1753
|
},
|
|
1754
|
+
failNext(operation, failure2) {
|
|
1755
|
+
state.paymentFailures.push({ operation, failure: failure2 });
|
|
1756
|
+
},
|
|
1713
1757
|
markPaid(id) {
|
|
1714
1758
|
const session = state.sessionStatuses.get(id);
|
|
1715
1759
|
if (session) {
|
|
@@ -1819,6 +1863,7 @@ function createPayments() {
|
|
|
1819
1863
|
state.checkoutCounter = 0;
|
|
1820
1864
|
state.sessionStatuses.clear();
|
|
1821
1865
|
state.paymentLinks.clear();
|
|
1866
|
+
state.paymentFailures = [];
|
|
1822
1867
|
state.products = [];
|
|
1823
1868
|
state.boltConnections.clear();
|
|
1824
1869
|
state.boltUsedPairingCodes.clear();
|
package/dist/index.mjs
CHANGED
|
@@ -59,6 +59,7 @@ var state = globalSingleton("state", () => ({
|
|
|
59
59
|
checkoutCounter: 0,
|
|
60
60
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
61
61
|
paymentLinks: /* @__PURE__ */ new Map(),
|
|
62
|
+
paymentFailures: [],
|
|
62
63
|
products: [],
|
|
63
64
|
boltConnections: /* @__PURE__ */ new Map(),
|
|
64
65
|
boltUsedPairingCodes: /* @__PURE__ */ new Set(),
|
|
@@ -611,6 +612,7 @@ async function handleEmailSend(request) {
|
|
|
611
612
|
html: body.html ? String(body.html) : void 0,
|
|
612
613
|
text: body.text ? String(body.text) : void 0,
|
|
613
614
|
replyTo: body.replyTo ? String(body.replyTo) : void 0,
|
|
615
|
+
headers: { ...body.headers ?? {} },
|
|
614
616
|
attachments: (body.attachments ?? []).map((a) => ({
|
|
615
617
|
filename: String(a.filename ?? ""),
|
|
616
618
|
contentType: a.contentType ? String(a.contentType) : void 0
|
|
@@ -1224,6 +1226,43 @@ function payErr(error, status = 400, code, details) {
|
|
|
1224
1226
|
if (details !== void 0) body.details = details;
|
|
1225
1227
|
return json(body, status);
|
|
1226
1228
|
}
|
|
1229
|
+
function paymentOperationForRequest(request, pathname) {
|
|
1230
|
+
if (request.method === "POST" && /^\/api\/store\/beam\/[^/]+\/payment-links$/.test(pathname)) {
|
|
1231
|
+
return "beam.createPaymentLink";
|
|
1232
|
+
}
|
|
1233
|
+
if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/payment-links\/[^/]+$/.test(pathname)) {
|
|
1234
|
+
return "beam.getPaymentLinkStatus";
|
|
1235
|
+
}
|
|
1236
|
+
if (request.method === "POST" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout$/.test(pathname)) {
|
|
1237
|
+
return "stripe.createCheckout";
|
|
1238
|
+
}
|
|
1239
|
+
if (request.method === "GET" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout-sessions\/[^/]+$/.test(pathname)) {
|
|
1240
|
+
return "stripe.getCheckoutSessionStatus";
|
|
1241
|
+
}
|
|
1242
|
+
return null;
|
|
1243
|
+
}
|
|
1244
|
+
function consumePaymentFailure(request, pathname) {
|
|
1245
|
+
const operation = paymentOperationForRequest(request, pathname);
|
|
1246
|
+
if (!operation) return null;
|
|
1247
|
+
const index = state.paymentFailures.findIndex((entry) => entry.operation === operation);
|
|
1248
|
+
if (index === -1) return null;
|
|
1249
|
+
const [{ failure: failure2 }] = state.paymentFailures.splice(index, 1);
|
|
1250
|
+
if (failure2.kind === "network") {
|
|
1251
|
+
throw new TypeError(failure2.message);
|
|
1252
|
+
}
|
|
1253
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
1254
|
+
if (failure2.retryAfterSeconds !== void 0) {
|
|
1255
|
+
headers.set("Retry-After", String(failure2.retryAfterSeconds));
|
|
1256
|
+
}
|
|
1257
|
+
return new Response(
|
|
1258
|
+
JSON.stringify({
|
|
1259
|
+
error: failure2.message,
|
|
1260
|
+
code: failure2.code ?? "REQUEST_ERROR",
|
|
1261
|
+
...failure2.details !== void 0 ? { details: failure2.details } : {}
|
|
1262
|
+
}),
|
|
1263
|
+
{ status: failure2.status, headers }
|
|
1264
|
+
);
|
|
1265
|
+
}
|
|
1227
1266
|
function isBoltPaymentMethod(value) {
|
|
1228
1267
|
return typeof value === "string" && BEAM_BOLT_PAYMENT_METHODS.includes(value);
|
|
1229
1268
|
}
|
|
@@ -1367,6 +1406,8 @@ async function deliverEvent(envelope, handler, options) {
|
|
|
1367
1406
|
}
|
|
1368
1407
|
async function handlePaymentsRequest(request, url) {
|
|
1369
1408
|
const pathname = url.pathname;
|
|
1409
|
+
const injectedFailure = consumePaymentFailure(request, pathname);
|
|
1410
|
+
if (injectedFailure) return injectedFailure;
|
|
1370
1411
|
if (/\/billing-portal$/.test(pathname)) {
|
|
1371
1412
|
return payErr("Not found", 404, "NOT_FOUND");
|
|
1372
1413
|
}
|
|
@@ -1661,6 +1702,9 @@ function createPayments() {
|
|
|
1661
1702
|
setProducts(products) {
|
|
1662
1703
|
state.products = products;
|
|
1663
1704
|
},
|
|
1705
|
+
failNext(operation, failure2) {
|
|
1706
|
+
state.paymentFailures.push({ operation, failure: failure2 });
|
|
1707
|
+
},
|
|
1664
1708
|
markPaid(id) {
|
|
1665
1709
|
const session = state.sessionStatuses.get(id);
|
|
1666
1710
|
if (session) {
|
|
@@ -1770,6 +1814,7 @@ function createPayments() {
|
|
|
1770
1814
|
state.checkoutCounter = 0;
|
|
1771
1815
|
state.sessionStatuses.clear();
|
|
1772
1816
|
state.paymentLinks.clear();
|
|
1817
|
+
state.paymentFailures = [];
|
|
1773
1818
|
state.products = [];
|
|
1774
1819
|
state.boltConnections.clear();
|
|
1775
1820
|
state.boltUsedPairingCodes.clear();
|
|
@@ -51,6 +51,7 @@ var state = globalSingleton("state", () => ({
|
|
|
51
51
|
checkoutCounter: 0,
|
|
52
52
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
53
53
|
paymentLinks: /* @__PURE__ */ new Map(),
|
|
54
|
+
paymentFailures: [],
|
|
54
55
|
products: [],
|
|
55
56
|
boltConnections: /* @__PURE__ */ new Map(),
|
|
56
57
|
boltUsedPairingCodes: /* @__PURE__ */ new Set(),
|
|
@@ -24,6 +24,7 @@ var state = globalSingleton("state", () => ({
|
|
|
24
24
|
checkoutCounter: 0,
|
|
25
25
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
26
26
|
paymentLinks: /* @__PURE__ */ new Map(),
|
|
27
|
+
paymentFailures: [],
|
|
27
28
|
products: [],
|
|
28
29
|
boltConnections: /* @__PURE__ */ new Map(),
|
|
29
30
|
boltUsedPairingCodes: /* @__PURE__ */ new Set(),
|
package/dist/setup.js
CHANGED
|
@@ -45,6 +45,7 @@ var state = globalSingleton("state", () => ({
|
|
|
45
45
|
checkoutCounter: 0,
|
|
46
46
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
47
47
|
paymentLinks: /* @__PURE__ */ new Map(),
|
|
48
|
+
paymentFailures: [],
|
|
48
49
|
products: [],
|
|
49
50
|
boltConnections: /* @__PURE__ */ new Map(),
|
|
50
51
|
boltUsedPairingCodes: /* @__PURE__ */ new Set(),
|
|
@@ -607,6 +608,7 @@ async function handleEmailSend(request) {
|
|
|
607
608
|
html: body.html ? String(body.html) : void 0,
|
|
608
609
|
text: body.text ? String(body.text) : void 0,
|
|
609
610
|
replyTo: body.replyTo ? String(body.replyTo) : void 0,
|
|
611
|
+
headers: { ...body.headers ?? {} },
|
|
610
612
|
attachments: (body.attachments ?? []).map((a) => ({
|
|
611
613
|
filename: String(a.filename ?? ""),
|
|
612
614
|
contentType: a.contentType ? String(a.contentType) : void 0
|
|
@@ -1011,6 +1013,43 @@ function payErr(error, status = 400, code, details) {
|
|
|
1011
1013
|
if (details !== void 0) body.details = details;
|
|
1012
1014
|
return json(body, status);
|
|
1013
1015
|
}
|
|
1016
|
+
function paymentOperationForRequest(request, pathname) {
|
|
1017
|
+
if (request.method === "POST" && /^\/api\/store\/beam\/[^/]+\/payment-links$/.test(pathname)) {
|
|
1018
|
+
return "beam.createPaymentLink";
|
|
1019
|
+
}
|
|
1020
|
+
if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/payment-links\/[^/]+$/.test(pathname)) {
|
|
1021
|
+
return "beam.getPaymentLinkStatus";
|
|
1022
|
+
}
|
|
1023
|
+
if (request.method === "POST" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout$/.test(pathname)) {
|
|
1024
|
+
return "stripe.createCheckout";
|
|
1025
|
+
}
|
|
1026
|
+
if (request.method === "GET" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout-sessions\/[^/]+$/.test(pathname)) {
|
|
1027
|
+
return "stripe.getCheckoutSessionStatus";
|
|
1028
|
+
}
|
|
1029
|
+
return null;
|
|
1030
|
+
}
|
|
1031
|
+
function consumePaymentFailure(request, pathname) {
|
|
1032
|
+
const operation = paymentOperationForRequest(request, pathname);
|
|
1033
|
+
if (!operation) return null;
|
|
1034
|
+
const index = state.paymentFailures.findIndex((entry) => entry.operation === operation);
|
|
1035
|
+
if (index === -1) return null;
|
|
1036
|
+
const [{ failure: failure2 }] = state.paymentFailures.splice(index, 1);
|
|
1037
|
+
if (failure2.kind === "network") {
|
|
1038
|
+
throw new TypeError(failure2.message);
|
|
1039
|
+
}
|
|
1040
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
1041
|
+
if (failure2.retryAfterSeconds !== void 0) {
|
|
1042
|
+
headers.set("Retry-After", String(failure2.retryAfterSeconds));
|
|
1043
|
+
}
|
|
1044
|
+
return new Response(
|
|
1045
|
+
JSON.stringify({
|
|
1046
|
+
error: failure2.message,
|
|
1047
|
+
code: failure2.code ?? "REQUEST_ERROR",
|
|
1048
|
+
...failure2.details !== void 0 ? { details: failure2.details } : {}
|
|
1049
|
+
}),
|
|
1050
|
+
{ status: failure2.status, headers }
|
|
1051
|
+
);
|
|
1052
|
+
}
|
|
1014
1053
|
function isBoltPaymentMethod(value) {
|
|
1015
1054
|
return typeof value === "string" && BEAM_BOLT_PAYMENT_METHODS.includes(value);
|
|
1016
1055
|
}
|
|
@@ -1119,6 +1158,8 @@ function storedStatusesForFilter(statuses) {
|
|
|
1119
1158
|
}
|
|
1120
1159
|
async function handlePaymentsRequest(request, url) {
|
|
1121
1160
|
const pathname = url.pathname;
|
|
1161
|
+
const injectedFailure = consumePaymentFailure(request, pathname);
|
|
1162
|
+
if (injectedFailure) return injectedFailure;
|
|
1122
1163
|
if (/\/billing-portal$/.test(pathname)) {
|
|
1123
1164
|
return payErr("Not found", 404, "NOT_FOUND");
|
|
1124
1165
|
}
|
package/dist/setup.mjs
CHANGED
|
@@ -21,6 +21,7 @@ var state = globalSingleton("state", () => ({
|
|
|
21
21
|
checkoutCounter: 0,
|
|
22
22
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
23
23
|
paymentLinks: /* @__PURE__ */ new Map(),
|
|
24
|
+
paymentFailures: [],
|
|
24
25
|
products: [],
|
|
25
26
|
boltConnections: /* @__PURE__ */ new Map(),
|
|
26
27
|
boltUsedPairingCodes: /* @__PURE__ */ new Set(),
|
|
@@ -583,6 +584,7 @@ async function handleEmailSend(request) {
|
|
|
583
584
|
html: body.html ? String(body.html) : void 0,
|
|
584
585
|
text: body.text ? String(body.text) : void 0,
|
|
585
586
|
replyTo: body.replyTo ? String(body.replyTo) : void 0,
|
|
587
|
+
headers: { ...body.headers ?? {} },
|
|
586
588
|
attachments: (body.attachments ?? []).map((a) => ({
|
|
587
589
|
filename: String(a.filename ?? ""),
|
|
588
590
|
contentType: a.contentType ? String(a.contentType) : void 0
|
|
@@ -987,6 +989,43 @@ function payErr(error, status = 400, code, details) {
|
|
|
987
989
|
if (details !== void 0) body.details = details;
|
|
988
990
|
return json(body, status);
|
|
989
991
|
}
|
|
992
|
+
function paymentOperationForRequest(request, pathname) {
|
|
993
|
+
if (request.method === "POST" && /^\/api\/store\/beam\/[^/]+\/payment-links$/.test(pathname)) {
|
|
994
|
+
return "beam.createPaymentLink";
|
|
995
|
+
}
|
|
996
|
+
if (request.method === "GET" && /^\/api\/store\/beam\/[^/]+\/payment-links\/[^/]+$/.test(pathname)) {
|
|
997
|
+
return "beam.getPaymentLinkStatus";
|
|
998
|
+
}
|
|
999
|
+
if (request.method === "POST" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout$/.test(pathname)) {
|
|
1000
|
+
return "stripe.createCheckout";
|
|
1001
|
+
}
|
|
1002
|
+
if (request.method === "GET" && /^\/api\/store\/(?!beam\/)[^/]+\/checkout-sessions\/[^/]+$/.test(pathname)) {
|
|
1003
|
+
return "stripe.getCheckoutSessionStatus";
|
|
1004
|
+
}
|
|
1005
|
+
return null;
|
|
1006
|
+
}
|
|
1007
|
+
function consumePaymentFailure(request, pathname) {
|
|
1008
|
+
const operation = paymentOperationForRequest(request, pathname);
|
|
1009
|
+
if (!operation) return null;
|
|
1010
|
+
const index = state.paymentFailures.findIndex((entry) => entry.operation === operation);
|
|
1011
|
+
if (index === -1) return null;
|
|
1012
|
+
const [{ failure: failure2 }] = state.paymentFailures.splice(index, 1);
|
|
1013
|
+
if (failure2.kind === "network") {
|
|
1014
|
+
throw new TypeError(failure2.message);
|
|
1015
|
+
}
|
|
1016
|
+
const headers = new Headers({ "Content-Type": "application/json" });
|
|
1017
|
+
if (failure2.retryAfterSeconds !== void 0) {
|
|
1018
|
+
headers.set("Retry-After", String(failure2.retryAfterSeconds));
|
|
1019
|
+
}
|
|
1020
|
+
return new Response(
|
|
1021
|
+
JSON.stringify({
|
|
1022
|
+
error: failure2.message,
|
|
1023
|
+
code: failure2.code ?? "REQUEST_ERROR",
|
|
1024
|
+
...failure2.details !== void 0 ? { details: failure2.details } : {}
|
|
1025
|
+
}),
|
|
1026
|
+
{ status: failure2.status, headers }
|
|
1027
|
+
);
|
|
1028
|
+
}
|
|
990
1029
|
function isBoltPaymentMethod(value) {
|
|
991
1030
|
return typeof value === "string" && BEAM_BOLT_PAYMENT_METHODS.includes(value);
|
|
992
1031
|
}
|
|
@@ -1095,6 +1134,8 @@ function storedStatusesForFilter(statuses) {
|
|
|
1095
1134
|
}
|
|
1096
1135
|
async function handlePaymentsRequest(request, url) {
|
|
1097
1136
|
const pathname = url.pathname;
|
|
1137
|
+
const injectedFailure = consumePaymentFailure(request, pathname);
|
|
1138
|
+
if (injectedFailure) return injectedFailure;
|
|
1098
1139
|
if (/\/billing-portal$/.test(pathname)) {
|
|
1099
1140
|
return payErr("Not found", 404, "NOT_FOUND");
|
|
1100
1141
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stardeck-customer-apps/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "Vitest test harness for Stardeck customer apps — in-process Postgres (PGlite) plus a control-plane simulator so the real Stardeck SDKs run unmodified in tests",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|