@stardeck-customer-apps/testing 0.3.1 → 0.4.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 CHANGED
@@ -67,6 +67,42 @@ describeWorkflow("checkout", () => {
67
67
  });
68
68
  ```
69
69
 
70
+ Payments, storage, and messaging:
71
+
72
+ ```ts
73
+ import { paymentsHandler } from "@stardeck-customer-apps/payments-sdk";
74
+ import { PaymentsServerClient } from "@stardeck-customer-apps/payments-sdk/server";
75
+ import { StorageClient } from "@stardeck-customer-apps/storage-sdk/server";
76
+ import { createIntegrationsClient } from "@stardeck-customer-apps/integrations-sdk";
77
+
78
+ // Stripe checkout + webhook fulfillment
79
+ const payments = new PaymentsServerClient({ /* reads CONTROL_PLANE_URL + DEPLOYMENT_SECRET from env */ });
80
+ const session = await payments.createCheckout({ /* lineItems, successUrl, cancelUrl */ });
81
+ const { POST } = paymentsHandler({
82
+ onStripeWebhook: async (event) => {
83
+ if (event.type === "checkout.session.completed") {
84
+ await app.query(`UPDATE orders SET status = 'paid' WHERE session_id = $1`, [
85
+ (event.data as { object: { id: string } }).object.id,
86
+ ]);
87
+ }
88
+ },
89
+ });
90
+ await app.payments.deliverStripeEvent(POST, {
91
+ type: "checkout.session.completed",
92
+ data: { object: { id: session.id } },
93
+ });
94
+
95
+ // File upload
96
+ const storage = new StorageClient();
97
+ await storage.upload(new File(["hi"], "note.txt", { type: "text/plain" }));
98
+ expect(app.storage.latest()?.filename).toBe("note.txt");
99
+
100
+ // LINE notification
101
+ const integrations = createIntegrationsClient();
102
+ await integrations.line.push("U123", { type: "text", text: "Your order shipped" });
103
+ expect(app.messages.channel("line").to("U123")[0].body.text).toMatch(/shipped/i);
104
+ ```
105
+
70
106
  ## API
71
107
 
72
108
  - `createTestApp(options)` — boots PGlite + the control-plane simulator and
@@ -88,6 +124,13 @@ describeWorkflow("checkout", () => {
88
124
  - `app.identities` — the platform-identity directory created through
89
125
  integrations-sdk `client.identities`: `.get(id)`, `.links(id)`, `.all()`,
90
126
  `.count`, `.clear()`.
127
+ - `app.payments` — checkouts created through payments-sdk:
128
+ `.checkouts`, `.latest()`, `.setProducts()`, `.markPaid(id)`,
129
+ `.deliverStripeEvent(handler, event)`, `.deliverBeamEvent(handler, event)`,
130
+ `.count`, `.clear()`.
131
+ - `app.storage` — uploads through storage-sdk: `.uploads`, `.latest()`, `.count`, `.clear()`.
132
+ - `app.messages` — outbound Slack/LINE/Facebook sends:
133
+ `.all()`, `.latest()`, `.to(recipient)`, `.channel("line")`, `.count`, `.clear()`.
91
134
  - `app.query(sql, params?)` / `app.db` — direct database access for
92
135
  assertions and seeding.
93
136
  - `callRoute(handler, opts)` — invoke an App Router route handler with a real
@@ -111,6 +154,13 @@ describeWorkflow("checkout", () => {
111
154
  persons, attach channel links) — served offline by the simulated directory;
112
155
  `update` replaces the `profile` object (not a merge), like the control plane.
113
156
  Inspect via `app.identities`. Merge/archive are dashboard-only — not simulated.
157
+ - `PaymentsServerClient` (Stripe checkout + Beam payment links, product list) —
158
+ captured in `app.payments`; fulfill via `markPaid` (poll) or
159
+ `deliverStripeEvent` / `deliverBeamEvent` (webhook push).
160
+ - `StorageClient` (upload/list/get/patch/delete, presigned upload) — captured
161
+ in `app.storage` against the simulated `STORAGE_URL` host.
162
+ - `client.slack` / `client.line` / `client.facebook` send endpoints — captured
163
+ in `app.messages`.
114
164
  - `next/headers` (`headers()`/`cookies()`) inside handlers under `callRoute`.
115
165
 
116
166
  ## Rules
package/dist/index.d.mts CHANGED
@@ -1,6 +1,27 @@
1
+ import * as _stardeck_customer_apps_payments_sdk from '@stardeck-customer-apps/payments-sdk';
2
+ import * as next_server from 'next/server';
1
3
  import { PGlite } from '@electric-sql/pglite';
2
- import { ModuleSchemaOp, ModuleDataPort, IdentityClient } from '@stardeck-customer-apps/core';
3
4
 
5
+ type RouteHandler<Req extends Request = Request, P = Record<string, string | string[]>> = (request: Req, context: {
6
+ params: Promise<P>;
7
+ }) => Promise<Response> | Response;
8
+ interface CallRouteOptions {
9
+ /** Request path, e.g. "/api/orders". Defaults to "/api/test-route". */
10
+ path?: string;
11
+ method?: string;
12
+ /** JSON body. Implies POST unless `method` is set. */
13
+ body?: unknown;
14
+ searchParams?: Record<string, string>;
15
+ /** Next.js dynamic segment params, e.g. { id: "123" }. */
16
+ params?: Record<string, string | string[]>;
17
+ headers?: Record<string, string>;
18
+ cookies?: Record<string, string>;
19
+ /** Override the active test user for this call only. */
20
+ user?: TestUser | null;
21
+ }
22
+ declare function callRoute<Req extends Request = Request, P = Record<string, string | string[]>>(handler: RouteHandler<Req, P>, options?: CallRouteOptions): Promise<Response>;
23
+
24
+ type PaymentsWebhookHandler = RouteHandler<next_server.NextRequest, Record<string, string | string[] | undefined>>;
4
25
  /**
5
26
  * The user shape returned by project-auth's `getSession()`. Mirrors the
6
27
  * `UserSchema` in @stardeck-customer-apps/project-auth — keep in sync.
@@ -85,6 +106,84 @@ interface TestDirectory {
85
106
  clear(): void;
86
107
  get count(): number;
87
108
  }
109
+ interface CapturedCheckout {
110
+ id: string;
111
+ url: string;
112
+ provider: "stripe" | "beam";
113
+ options: Record<string, unknown>;
114
+ mode?: "payment" | "subscription";
115
+ metadata?: Record<string, string>;
116
+ createdAt: Date;
117
+ }
118
+ interface TestPayments {
119
+ get checkouts(): CapturedCheckout[];
120
+ latest(): CapturedCheckout | undefined;
121
+ setProducts(products: _stardeck_customer_apps_payments_sdk.Product[]): void;
122
+ markPaid(id: string): void;
123
+ setSessionStatus(id: string, status: Partial<_stardeck_customer_apps_payments_sdk.CheckoutSessionStatus>): void;
124
+ setPaymentLinkStatus(id: string, status: _stardeck_customer_apps_payments_sdk.BeamPaymentLinkStatus): void;
125
+ deliverStripeEvent(handler: PaymentsWebhookHandler, event: {
126
+ type: string;
127
+ data: unknown;
128
+ accountId?: string;
129
+ }, options?: {
130
+ path?: string;
131
+ deploymentSecret?: string;
132
+ }): Promise<Response>;
133
+ deliverBeamEvent(handler: PaymentsWebhookHandler, event: {
134
+ type: string;
135
+ payload: Record<string, unknown>;
136
+ }, options?: {
137
+ path?: string;
138
+ deploymentSecret?: string;
139
+ }): Promise<Response>;
140
+ clear(): void;
141
+ get count(): number;
142
+ }
143
+ interface CapturedUpload {
144
+ id: string;
145
+ key: string;
146
+ filename: string;
147
+ contentType: string;
148
+ sizeBytes: number;
149
+ url: string;
150
+ uploadedAt: string;
151
+ isPublic: boolean;
152
+ metadata?: Record<string, string>;
153
+ method: string;
154
+ path: string;
155
+ }
156
+ interface TestStorage {
157
+ get uploads(): CapturedUpload[];
158
+ latest(): CapturedUpload | undefined;
159
+ clear(): void;
160
+ get count(): number;
161
+ }
162
+ interface CapturedMessage {
163
+ channel: "slack" | "line" | "facebook";
164
+ recipient: string;
165
+ body: {
166
+ text?: string;
167
+ blocks?: unknown[];
168
+ threadTs?: string;
169
+ messagingType?: string;
170
+ tag?: string;
171
+ };
172
+ connectionId?: string;
173
+ sentAt: Date;
174
+ }
175
+ interface TestMessages {
176
+ all(): CapturedMessage[];
177
+ latest(): CapturedMessage | undefined;
178
+ to(recipient: string): CapturedMessage[];
179
+ channel(kind: "slack" | "line" | "facebook"): {
180
+ all(): CapturedMessage[];
181
+ latest(): CapturedMessage | undefined;
182
+ to(recipient: string): CapturedMessage[];
183
+ };
184
+ clear(): void;
185
+ get count(): number;
186
+ }
88
187
  interface TestAppOptions {
89
188
  /**
90
189
  * Path to the schema.sql snapshot generated by
@@ -114,6 +213,12 @@ interface TestApp {
114
213
  inbox: TestInbox;
115
214
  /** Inspect the simulated platform-identity directory (`client.identities`). */
116
215
  identities: TestDirectory;
216
+ /** Captured checkouts and webhook delivery helpers for payments-sdk. */
217
+ payments: TestPayments;
218
+ /** Captured file uploads from storage-sdk. */
219
+ storage: TestStorage;
220
+ /** Captured outbound messages from integrations-sdk messaging channels. */
221
+ messages: TestMessages;
117
222
  /** Convenience for raw SQL: `app.query("SELECT ...", [param])`. */
118
223
  query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
119
224
  /**
@@ -141,71 +246,6 @@ interface TestApp {
141
246
  */
142
247
  declare function createTestApp(options?: TestAppOptions): Promise<TestApp>;
143
248
 
144
- /** The minimal slice of a module definition the harness needs to stand it up. */
145
- interface MountableModule {
146
- schema: ModuleSchemaOp[];
147
- }
148
- interface ModuleSeedDeps {
149
- /** Raw-SQL data port over the harness PGlite — what the module engine reads/writes through. */
150
- data: ModuleDataPort;
151
- /** Identity client backed by the simulated platform identity directory. */
152
- identities: IdentityClient;
153
- }
154
- interface CreateModuleAppOptions {
155
- /** Modules whose install schema is rendered to DDL and applied to the test DB. */
156
- modules: MountableModule[];
157
- /**
158
- * Seed run once after the schema is applied, and again on every `reset()`.
159
- * Receives the same data port + identity client the module engine uses, so a
160
- * module's own `seed*` function drops straight in.
161
- */
162
- seed?: (deps: ModuleSeedDeps) => Promise<void>;
163
- /** Allow real outbound network (default false). */
164
- allowNetwork?: boolean;
165
- }
166
- interface ModuleApp extends ModuleSeedDeps {
167
- /** The underlying harness app (db, identities inspector, callRoute, asUser, …). */
168
- app: TestApp;
169
- /** Reset to a clean slate: drop + re-apply the module schema, clear the sim, re-run the seed. */
170
- reset(): Promise<void>;
171
- /** Tear down (restore global fetch, close the db). */
172
- close(): Promise<void>;
173
- }
174
- /**
175
- * Stand a capability module up on the in-process platform simulator — the **L2**
176
- * harness. It renders the module's install schema to real DDL (the SAME renderer
177
- * the control plane uses, drift-tested in apps/web), applies it to PGlite, wires a
178
- * raw-SQL data port over it, and a real `integrations-sdk` identity client talking
179
- * to the simulated identity directory (so scoping + governance behave as in prod).
180
- *
181
- * That's a near-end-to-end test of a module's runtime — schema + data port +
182
- * identity integration + engine — minus the HTTP/RSC shell (those belong to a
183
- * real-deploy smoke). The same seams back the local dev playground.
184
- *
185
- * Adding a module costs one co-located test file calling this with its own
186
- * definition + seed; there is no per-module harness to maintain.
187
- */
188
- declare function createModuleApp(options: CreateModuleAppOptions): Promise<ModuleApp>;
189
-
190
- type RouteHandler<Req extends Request, P> = (request: Req, context: {
191
- params: Promise<P>;
192
- }) => Promise<Response> | Response;
193
- interface CallRouteOptions {
194
- /** Request path, e.g. "/api/orders". Defaults to "/api/test-route". */
195
- path?: string;
196
- method?: string;
197
- /** JSON body. Implies POST unless `method` is set. */
198
- body?: unknown;
199
- searchParams?: Record<string, string>;
200
- /** Next.js dynamic segment params, e.g. { id: "123" }. */
201
- params?: Record<string, string | string[]>;
202
- headers?: Record<string, string>;
203
- cookies?: Record<string, string>;
204
- /** Override the active test user for this call only. */
205
- user?: TestUser | null;
206
- }
207
- declare function callRoute<Req extends Request = Request, P = Record<string, string | string[]>>(handler: RouteHandler<Req, P>, options?: CallRouteOptions): Promise<Response>;
208
-
209
249
  /**
210
250
  * Tags a describe block as covering a named critical workflow ("checkout",
211
251
  * "booking", "inventory"). The platform parses the `workflow:` prefix out of
@@ -219,6 +259,8 @@ declare function parseWorkflowName(describeTitle: string): string | null;
219
259
 
220
260
  declare const CONTROL_PLANE_TEST_URL = "https://control-plane.stardeck.test";
221
261
  declare const DATA_STORE_TEST_HOST = "db.stardeck.test";
262
+ declare const STORAGE_TEST_URL = "https://storage.stardeck.test";
263
+ declare const STORAGE_TEST_HOST = "storage.stardeck.test";
222
264
  declare const TEST_ENV_DEFAULTS: {
223
265
  readonly CONTROL_PLANE_URL: "https://control-plane.stardeck.test";
224
266
  readonly DEPLOYMENT_SECRET: "stardeck-test-deployment-secret";
@@ -226,8 +268,9 @@ declare const TEST_ENV_DEFAULTS: {
226
268
  readonly PROJECT_ID: "00000000-0000-4000-8000-00000000000b";
227
269
  readonly DEPLOYMENT_ID: "00000000-0000-4000-8000-00000000000c";
228
270
  readonly DATA_STORE_URL: "postgresql://test:test@db.stardeck.test/main";
271
+ readonly STORAGE_URL: "https://storage.stardeck.test";
229
272
  };
230
273
  /** Default location of the DDL snapshot written by `generate-types`. */
231
274
  declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
232
275
 
233
- export { CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CreateModuleAppOptions, DATA_STORE_TEST_HOST, DEFAULT_SCHEMA_PATH, type ModuleApp, type ModuleSeedDeps, type MountableModule, type SessionTokens, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, type TestDirectory, type TestInbox, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createModuleApp, createTestApp, describeWorkflow, parseWorkflowName };
276
+ export { CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedUpload, DATA_STORE_TEST_HOST, DEFAULT_SCHEMA_PATH, STORAGE_TEST_HOST, STORAGE_TEST_URL, type SessionTokens, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, type TestDirectory, type TestInbox, type TestMessages, type TestPayments, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,27 @@
1
+ import * as _stardeck_customer_apps_payments_sdk from '@stardeck-customer-apps/payments-sdk';
2
+ import * as next_server from 'next/server';
1
3
  import { PGlite } from '@electric-sql/pglite';
2
- import { ModuleSchemaOp, ModuleDataPort, IdentityClient } from '@stardeck-customer-apps/core';
3
4
 
5
+ type RouteHandler<Req extends Request = Request, P = Record<string, string | string[]>> = (request: Req, context: {
6
+ params: Promise<P>;
7
+ }) => Promise<Response> | Response;
8
+ interface CallRouteOptions {
9
+ /** Request path, e.g. "/api/orders". Defaults to "/api/test-route". */
10
+ path?: string;
11
+ method?: string;
12
+ /** JSON body. Implies POST unless `method` is set. */
13
+ body?: unknown;
14
+ searchParams?: Record<string, string>;
15
+ /** Next.js dynamic segment params, e.g. { id: "123" }. */
16
+ params?: Record<string, string | string[]>;
17
+ headers?: Record<string, string>;
18
+ cookies?: Record<string, string>;
19
+ /** Override the active test user for this call only. */
20
+ user?: TestUser | null;
21
+ }
22
+ declare function callRoute<Req extends Request = Request, P = Record<string, string | string[]>>(handler: RouteHandler<Req, P>, options?: CallRouteOptions): Promise<Response>;
23
+
24
+ type PaymentsWebhookHandler = RouteHandler<next_server.NextRequest, Record<string, string | string[] | undefined>>;
4
25
  /**
5
26
  * The user shape returned by project-auth's `getSession()`. Mirrors the
6
27
  * `UserSchema` in @stardeck-customer-apps/project-auth — keep in sync.
@@ -85,6 +106,84 @@ interface TestDirectory {
85
106
  clear(): void;
86
107
  get count(): number;
87
108
  }
109
+ interface CapturedCheckout {
110
+ id: string;
111
+ url: string;
112
+ provider: "stripe" | "beam";
113
+ options: Record<string, unknown>;
114
+ mode?: "payment" | "subscription";
115
+ metadata?: Record<string, string>;
116
+ createdAt: Date;
117
+ }
118
+ interface TestPayments {
119
+ get checkouts(): CapturedCheckout[];
120
+ latest(): CapturedCheckout | undefined;
121
+ setProducts(products: _stardeck_customer_apps_payments_sdk.Product[]): void;
122
+ markPaid(id: string): void;
123
+ setSessionStatus(id: string, status: Partial<_stardeck_customer_apps_payments_sdk.CheckoutSessionStatus>): void;
124
+ setPaymentLinkStatus(id: string, status: _stardeck_customer_apps_payments_sdk.BeamPaymentLinkStatus): void;
125
+ deliverStripeEvent(handler: PaymentsWebhookHandler, event: {
126
+ type: string;
127
+ data: unknown;
128
+ accountId?: string;
129
+ }, options?: {
130
+ path?: string;
131
+ deploymentSecret?: string;
132
+ }): Promise<Response>;
133
+ deliverBeamEvent(handler: PaymentsWebhookHandler, event: {
134
+ type: string;
135
+ payload: Record<string, unknown>;
136
+ }, options?: {
137
+ path?: string;
138
+ deploymentSecret?: string;
139
+ }): Promise<Response>;
140
+ clear(): void;
141
+ get count(): number;
142
+ }
143
+ interface CapturedUpload {
144
+ id: string;
145
+ key: string;
146
+ filename: string;
147
+ contentType: string;
148
+ sizeBytes: number;
149
+ url: string;
150
+ uploadedAt: string;
151
+ isPublic: boolean;
152
+ metadata?: Record<string, string>;
153
+ method: string;
154
+ path: string;
155
+ }
156
+ interface TestStorage {
157
+ get uploads(): CapturedUpload[];
158
+ latest(): CapturedUpload | undefined;
159
+ clear(): void;
160
+ get count(): number;
161
+ }
162
+ interface CapturedMessage {
163
+ channel: "slack" | "line" | "facebook";
164
+ recipient: string;
165
+ body: {
166
+ text?: string;
167
+ blocks?: unknown[];
168
+ threadTs?: string;
169
+ messagingType?: string;
170
+ tag?: string;
171
+ };
172
+ connectionId?: string;
173
+ sentAt: Date;
174
+ }
175
+ interface TestMessages {
176
+ all(): CapturedMessage[];
177
+ latest(): CapturedMessage | undefined;
178
+ to(recipient: string): CapturedMessage[];
179
+ channel(kind: "slack" | "line" | "facebook"): {
180
+ all(): CapturedMessage[];
181
+ latest(): CapturedMessage | undefined;
182
+ to(recipient: string): CapturedMessage[];
183
+ };
184
+ clear(): void;
185
+ get count(): number;
186
+ }
88
187
  interface TestAppOptions {
89
188
  /**
90
189
  * Path to the schema.sql snapshot generated by
@@ -114,6 +213,12 @@ interface TestApp {
114
213
  inbox: TestInbox;
115
214
  /** Inspect the simulated platform-identity directory (`client.identities`). */
116
215
  identities: TestDirectory;
216
+ /** Captured checkouts and webhook delivery helpers for payments-sdk. */
217
+ payments: TestPayments;
218
+ /** Captured file uploads from storage-sdk. */
219
+ storage: TestStorage;
220
+ /** Captured outbound messages from integrations-sdk messaging channels. */
221
+ messages: TestMessages;
117
222
  /** Convenience for raw SQL: `app.query("SELECT ...", [param])`. */
118
223
  query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
119
224
  /**
@@ -141,71 +246,6 @@ interface TestApp {
141
246
  */
142
247
  declare function createTestApp(options?: TestAppOptions): Promise<TestApp>;
143
248
 
144
- /** The minimal slice of a module definition the harness needs to stand it up. */
145
- interface MountableModule {
146
- schema: ModuleSchemaOp[];
147
- }
148
- interface ModuleSeedDeps {
149
- /** Raw-SQL data port over the harness PGlite — what the module engine reads/writes through. */
150
- data: ModuleDataPort;
151
- /** Identity client backed by the simulated platform identity directory. */
152
- identities: IdentityClient;
153
- }
154
- interface CreateModuleAppOptions {
155
- /** Modules whose install schema is rendered to DDL and applied to the test DB. */
156
- modules: MountableModule[];
157
- /**
158
- * Seed run once after the schema is applied, and again on every `reset()`.
159
- * Receives the same data port + identity client the module engine uses, so a
160
- * module's own `seed*` function drops straight in.
161
- */
162
- seed?: (deps: ModuleSeedDeps) => Promise<void>;
163
- /** Allow real outbound network (default false). */
164
- allowNetwork?: boolean;
165
- }
166
- interface ModuleApp extends ModuleSeedDeps {
167
- /** The underlying harness app (db, identities inspector, callRoute, asUser, …). */
168
- app: TestApp;
169
- /** Reset to a clean slate: drop + re-apply the module schema, clear the sim, re-run the seed. */
170
- reset(): Promise<void>;
171
- /** Tear down (restore global fetch, close the db). */
172
- close(): Promise<void>;
173
- }
174
- /**
175
- * Stand a capability module up on the in-process platform simulator — the **L2**
176
- * harness. It renders the module's install schema to real DDL (the SAME renderer
177
- * the control plane uses, drift-tested in apps/web), applies it to PGlite, wires a
178
- * raw-SQL data port over it, and a real `integrations-sdk` identity client talking
179
- * to the simulated identity directory (so scoping + governance behave as in prod).
180
- *
181
- * That's a near-end-to-end test of a module's runtime — schema + data port +
182
- * identity integration + engine — minus the HTTP/RSC shell (those belong to a
183
- * real-deploy smoke). The same seams back the local dev playground.
184
- *
185
- * Adding a module costs one co-located test file calling this with its own
186
- * definition + seed; there is no per-module harness to maintain.
187
- */
188
- declare function createModuleApp(options: CreateModuleAppOptions): Promise<ModuleApp>;
189
-
190
- type RouteHandler<Req extends Request, P> = (request: Req, context: {
191
- params: Promise<P>;
192
- }) => Promise<Response> | Response;
193
- interface CallRouteOptions {
194
- /** Request path, e.g. "/api/orders". Defaults to "/api/test-route". */
195
- path?: string;
196
- method?: string;
197
- /** JSON body. Implies POST unless `method` is set. */
198
- body?: unknown;
199
- searchParams?: Record<string, string>;
200
- /** Next.js dynamic segment params, e.g. { id: "123" }. */
201
- params?: Record<string, string | string[]>;
202
- headers?: Record<string, string>;
203
- cookies?: Record<string, string>;
204
- /** Override the active test user for this call only. */
205
- user?: TestUser | null;
206
- }
207
- declare function callRoute<Req extends Request = Request, P = Record<string, string | string[]>>(handler: RouteHandler<Req, P>, options?: CallRouteOptions): Promise<Response>;
208
-
209
249
  /**
210
250
  * Tags a describe block as covering a named critical workflow ("checkout",
211
251
  * "booking", "inventory"). The platform parses the `workflow:` prefix out of
@@ -219,6 +259,8 @@ declare function parseWorkflowName(describeTitle: string): string | null;
219
259
 
220
260
  declare const CONTROL_PLANE_TEST_URL = "https://control-plane.stardeck.test";
221
261
  declare const DATA_STORE_TEST_HOST = "db.stardeck.test";
262
+ declare const STORAGE_TEST_URL = "https://storage.stardeck.test";
263
+ declare const STORAGE_TEST_HOST = "storage.stardeck.test";
222
264
  declare const TEST_ENV_DEFAULTS: {
223
265
  readonly CONTROL_PLANE_URL: "https://control-plane.stardeck.test";
224
266
  readonly DEPLOYMENT_SECRET: "stardeck-test-deployment-secret";
@@ -226,8 +268,9 @@ declare const TEST_ENV_DEFAULTS: {
226
268
  readonly PROJECT_ID: "00000000-0000-4000-8000-00000000000b";
227
269
  readonly DEPLOYMENT_ID: "00000000-0000-4000-8000-00000000000c";
228
270
  readonly DATA_STORE_URL: "postgresql://test:test@db.stardeck.test/main";
271
+ readonly STORAGE_URL: "https://storage.stardeck.test";
229
272
  };
230
273
  /** Default location of the DDL snapshot written by `generate-types`. */
231
274
  declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
232
275
 
233
- export { CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CreateModuleAppOptions, DATA_STORE_TEST_HOST, DEFAULT_SCHEMA_PATH, type ModuleApp, type ModuleSeedDeps, type MountableModule, type SessionTokens, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, type TestDirectory, type TestInbox, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createModuleApp, createTestApp, describeWorkflow, parseWorkflowName };
276
+ export { CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedUpload, DATA_STORE_TEST_HOST, DEFAULT_SCHEMA_PATH, STORAGE_TEST_HOST, STORAGE_TEST_URL, type SessionTokens, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, type TestDirectory, type TestInbox, type TestMessages, type TestPayments, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };