@stardeck-customer-apps/testing 0.25.0 → 0.26.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 +8 -1
- package/dist/index.d.mts +19 -1
- package/dist/index.d.ts +19 -1
- package/dist/index.js +41 -2
- package/dist/index.mjs +41 -2
- package/dist/next/headers-shim.js +1 -0
- package/dist/next/headers-shim.mjs +1 -0
- package/dist/setup.js +21 -2
- package/dist/setup.mjs +21 -2
- package/package.json +2 -1
package/SKILL.md
CHANGED
|
@@ -568,7 +568,8 @@ cursor, limit })`; `list()` intentionally keeps its previous array shape.
|
|
|
568
568
|
- `createEdgeClient()` (print, `enqueueReceipt()`/`getPrintJob()` durable receipts: idempotent per key,
|
|
569
569
|
conflicts and refused options mirrored, `app.edge.durablePrints`, and
|
|
570
570
|
`app.edge.settleNextDurableJob({ status: "needs_attention", reason, outcome })` to drive the
|
|
571
|
-
uncertain/not-printed UI
|
|
571
|
+
uncertain/not-printed UI, or `{ status: "sent_to_printer", simulated: true }` to mirror a
|
|
572
|
+
virtual-printer job (the status then carries `simulated: true`); pair/unpair, list devices/peripherals, show/clear
|
|
572
573
|
display, test print, `getCapabilities()`) — captured in `app.edge`; seed
|
|
573
574
|
devices/peripherals for pairing pickers via `app.edge.seedDevices()` /
|
|
574
575
|
`seedPeripherals()`.
|
|
@@ -585,6 +586,12 @@ cursor, limit })`; `list()` intentionally keeps its previous array shape.
|
|
|
585
586
|
high request with no image input answers `effort: "low"` as production does;
|
|
586
587
|
pass `effort: "low"` in `app.starlens.mock(...)` to simulate an image production
|
|
587
588
|
could not decode.
|
|
589
|
+
- `wakeSchedule(key, at)` from the scheduling SDK — there is no scheduler in tests: each
|
|
590
|
+
wake is recorded in `app.schedules`. After a write that creates work for an adaptive job,
|
|
591
|
+
assert the job was asked for in time:
|
|
592
|
+
`expect(app.schedules.earliestWake("booking-janitor")!.getTime()).toBeLessThanOrEqual(dueAt.getTime())`.
|
|
593
|
+
`app.schedules.wakesFor(key)` lists them; `reset()` clears them. Run the job's handler
|
|
594
|
+
yourself to test what it does and the `nextRun()` it returns.
|
|
588
595
|
|
|
589
596
|
### Receipt layout and printer capabilities
|
|
590
597
|
|
package/dist/index.d.mts
CHANGED
|
@@ -555,8 +555,10 @@ interface CapturedDurablePrint {
|
|
|
555
555
|
/** How a simulated durable job settles. Mirrors the platform's status contract. */
|
|
556
556
|
type SimulatedDurableOutcome = {
|
|
557
557
|
status: "sent_to_printer";
|
|
558
|
+
simulated?: boolean;
|
|
558
559
|
} | {
|
|
559
560
|
status: "queued";
|
|
561
|
+
simulated?: boolean;
|
|
560
562
|
} | {
|
|
561
563
|
status: "needs_attention";
|
|
562
564
|
reason: string;
|
|
@@ -650,6 +652,20 @@ interface TestStarlens {
|
|
|
650
652
|
clear(): void;
|
|
651
653
|
get count(): number;
|
|
652
654
|
}
|
|
655
|
+
/** A wake the app asked for: run `scheduleKey` by `at` (scheduling-sdk `wakeSchedule`). */
|
|
656
|
+
interface CapturedScheduleWake {
|
|
657
|
+
scheduleKey: string;
|
|
658
|
+
at: Date;
|
|
659
|
+
requestedAt: Date;
|
|
660
|
+
}
|
|
661
|
+
interface TestSchedules {
|
|
662
|
+
/** Every wake the app asked for, oldest first. */
|
|
663
|
+
get wakes(): CapturedScheduleWake[];
|
|
664
|
+
wakesFor(scheduleKey: string): CapturedScheduleWake[];
|
|
665
|
+
/** The earliest `at` any wake asked of `scheduleKey`, or undefined if none did. */
|
|
666
|
+
earliestWake(scheduleKey: string): Date | undefined;
|
|
667
|
+
clear(): void;
|
|
668
|
+
}
|
|
653
669
|
interface TestAppOptions {
|
|
654
670
|
/**
|
|
655
671
|
* The LIFF ID the platform forwards to the app for a LINE MINI App shop. It is
|
|
@@ -702,6 +718,8 @@ interface TestApp {
|
|
|
702
718
|
edge: TestEdge;
|
|
703
719
|
/** Scripted replies and captured calls for the Starlens SDK. */
|
|
704
720
|
starlens: TestStarlens;
|
|
721
|
+
/** Wakes the app asked of its adaptive schedules (`wakeSchedule`). */
|
|
722
|
+
schedules: TestSchedules;
|
|
705
723
|
/** Convenience for raw SQL: `app.query("SELECT ...", [param])`. */
|
|
706
724
|
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
707
725
|
/**
|
|
@@ -772,4 +790,4 @@ declare const TEST_ENV_DEFAULTS: {
|
|
|
772
790
|
/** Default location of the DDL snapshot written by `generate-types`. */
|
|
773
791
|
declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
|
|
774
792
|
|
|
775
|
-
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedDurablePrint, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedStarlensCall, 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, type SimulatedDurableOutcome, type StarlensReply, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestStarlens, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
|
793
|
+
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedDurablePrint, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedScheduleWake, type CapturedStarlensCall, 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, type SimulatedDurableOutcome, type StarlensReply, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestSchedules, type TestStarlens, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
package/dist/index.d.ts
CHANGED
|
@@ -555,8 +555,10 @@ interface CapturedDurablePrint {
|
|
|
555
555
|
/** How a simulated durable job settles. Mirrors the platform's status contract. */
|
|
556
556
|
type SimulatedDurableOutcome = {
|
|
557
557
|
status: "sent_to_printer";
|
|
558
|
+
simulated?: boolean;
|
|
558
559
|
} | {
|
|
559
560
|
status: "queued";
|
|
561
|
+
simulated?: boolean;
|
|
560
562
|
} | {
|
|
561
563
|
status: "needs_attention";
|
|
562
564
|
reason: string;
|
|
@@ -650,6 +652,20 @@ interface TestStarlens {
|
|
|
650
652
|
clear(): void;
|
|
651
653
|
get count(): number;
|
|
652
654
|
}
|
|
655
|
+
/** A wake the app asked for: run `scheduleKey` by `at` (scheduling-sdk `wakeSchedule`). */
|
|
656
|
+
interface CapturedScheduleWake {
|
|
657
|
+
scheduleKey: string;
|
|
658
|
+
at: Date;
|
|
659
|
+
requestedAt: Date;
|
|
660
|
+
}
|
|
661
|
+
interface TestSchedules {
|
|
662
|
+
/** Every wake the app asked for, oldest first. */
|
|
663
|
+
get wakes(): CapturedScheduleWake[];
|
|
664
|
+
wakesFor(scheduleKey: string): CapturedScheduleWake[];
|
|
665
|
+
/** The earliest `at` any wake asked of `scheduleKey`, or undefined if none did. */
|
|
666
|
+
earliestWake(scheduleKey: string): Date | undefined;
|
|
667
|
+
clear(): void;
|
|
668
|
+
}
|
|
653
669
|
interface TestAppOptions {
|
|
654
670
|
/**
|
|
655
671
|
* The LIFF ID the platform forwards to the app for a LINE MINI App shop. It is
|
|
@@ -702,6 +718,8 @@ interface TestApp {
|
|
|
702
718
|
edge: TestEdge;
|
|
703
719
|
/** Scripted replies and captured calls for the Starlens SDK. */
|
|
704
720
|
starlens: TestStarlens;
|
|
721
|
+
/** Wakes the app asked of its adaptive schedules (`wakeSchedule`). */
|
|
722
|
+
schedules: TestSchedules;
|
|
705
723
|
/** Convenience for raw SQL: `app.query("SELECT ...", [param])`. */
|
|
706
724
|
query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
|
|
707
725
|
/**
|
|
@@ -772,4 +790,4 @@ declare const TEST_ENV_DEFAULTS: {
|
|
|
772
790
|
/** Default location of the DDL snapshot written by `generate-types`. */
|
|
773
791
|
declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
|
|
774
792
|
|
|
775
|
-
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedDurablePrint, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedStarlensCall, 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, type SimulatedDurableOutcome, type StarlensReply, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestStarlens, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
|
793
|
+
export { type BindingInfo, CONTROL_PLANE_TEST_URL, type CallRouteOptions, type CapturedCheckout, type CapturedDisplay, type CapturedDurablePrint, type CapturedEmail, type CapturedIdentity, type CapturedIdentityLink, type CapturedMessage, type CapturedPrint, type CapturedScheduleWake, type CapturedStarlensCall, 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, type SimulatedDurableOutcome, type StarlensReply, TEST_ENV_DEFAULTS, type TestApp, type TestAppOptions, TestDataStoreInput, type TestDirectory, type TestEdge, type TestInbox, type TestMessages, type TestPayments, type TestSchedules, type TestStarlens, type TestStorage, type TestUser, WORKFLOW_NAME_PREFIX, callRoute, createTestApp, describeWorkflow, parseWorkflowName };
|
package/dist/index.js
CHANGED
|
@@ -338,6 +338,7 @@ var state = globalSingleton("state", () => ({
|
|
|
338
338
|
identitySuppressClaimDelivery: false,
|
|
339
339
|
identityAllowedReturnOrigins: /* @__PURE__ */ new Set([APP_TEST_ORIGIN]),
|
|
340
340
|
checkouts: [],
|
|
341
|
+
scheduleWakes: [],
|
|
341
342
|
checkoutCounter: 0,
|
|
342
343
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
343
344
|
idempotentCheckouts: /* @__PURE__ */ new Map(),
|
|
@@ -3440,7 +3441,9 @@ async function handleEnqueue(request) {
|
|
|
3440
3441
|
function durableView(jobId, as) {
|
|
3441
3442
|
const job = state.edgeDurableJobs.get(jobId);
|
|
3442
3443
|
const createdAt = now2();
|
|
3444
|
+
const simulated = job.outcome.status !== "needs_attention" && job.outcome.simulated ? { simulated: true } : {};
|
|
3443
3445
|
const base = {
|
|
3446
|
+
...simulated,
|
|
3444
3447
|
jobId,
|
|
3445
3448
|
attempts: as === "queued" ? 0 : 1,
|
|
3446
3449
|
createdAt,
|
|
@@ -3624,6 +3627,32 @@ function createEdge() {
|
|
|
3624
3627
|
};
|
|
3625
3628
|
}
|
|
3626
3629
|
|
|
3630
|
+
// src/simulator/schedules.ts
|
|
3631
|
+
async function handleScheduleWake(request, scheduleKey) {
|
|
3632
|
+
if (request.method !== "POST") return failure(`Method ${request.method} not allowed`, 405);
|
|
3633
|
+
const body = await readJsonBody(request);
|
|
3634
|
+
const at = typeof body.at === "string" ? new Date(body.at) : null;
|
|
3635
|
+
if (!at || Number.isNaN(at.getTime())) return failure("`at` must be an ISO date-time", 400);
|
|
3636
|
+
state.scheduleWakes.push({ scheduleKey, at, requestedAt: /* @__PURE__ */ new Date() });
|
|
3637
|
+
return success({ woken: true });
|
|
3638
|
+
}
|
|
3639
|
+
function createSchedules() {
|
|
3640
|
+
return {
|
|
3641
|
+
get wakes() {
|
|
3642
|
+
return state.scheduleWakes;
|
|
3643
|
+
},
|
|
3644
|
+
wakesFor(scheduleKey) {
|
|
3645
|
+
return state.scheduleWakes.filter((wake) => wake.scheduleKey === scheduleKey);
|
|
3646
|
+
},
|
|
3647
|
+
earliestWake(scheduleKey) {
|
|
3648
|
+
return this.wakesFor(scheduleKey).map((wake) => wake.at).sort((a, b) => a.getTime() - b.getTime())[0];
|
|
3649
|
+
},
|
|
3650
|
+
clear() {
|
|
3651
|
+
state.scheduleWakes = [];
|
|
3652
|
+
}
|
|
3653
|
+
};
|
|
3654
|
+
}
|
|
3655
|
+
|
|
3627
3656
|
// src/simulator/starlens.ts
|
|
3628
3657
|
var LATEST_VERSION = "v2";
|
|
3629
3658
|
function starlensFailure(error, status, code) {
|
|
@@ -3788,8 +3817,10 @@ function requiresDeploymentHmac(request, url) {
|
|
|
3788
3817
|
);
|
|
3789
3818
|
const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
|
|
3790
3819
|
const isStarlens = url.pathname === "/api/starlens/extract";
|
|
3791
|
-
|
|
3820
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
3821
|
+
return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
|
|
3792
3822
|
}
|
|
3823
|
+
var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
|
|
3793
3824
|
function deploymentIdFromPath(url) {
|
|
3794
3825
|
const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
|
|
3795
3826
|
if (!match) return null;
|
|
@@ -3854,6 +3885,10 @@ async function handleSimulatedRequest(request, url) {
|
|
|
3854
3885
|
if (edgeMatch) {
|
|
3855
3886
|
return handleEdgeRequest(request, edgeMatch[1] ?? "");
|
|
3856
3887
|
}
|
|
3888
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
3889
|
+
if (scheduleWakeMatch) {
|
|
3890
|
+
return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
|
|
3891
|
+
}
|
|
3857
3892
|
if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
|
|
3858
3893
|
return handleStarlensExtract(request, signedDeploymentId);
|
|
3859
3894
|
}
|
|
@@ -3878,7 +3913,7 @@ async function handleSimulatedRequest(request, url) {
|
|
|
3878
3913
|
}
|
|
3879
3914
|
}
|
|
3880
3915
|
return failure(
|
|
3881
|
-
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, auth verify/refresh, Neon /sql.`,
|
|
3916
|
+
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, schedule wakes, auth verify/refresh, Neon /sql.`,
|
|
3882
3917
|
404
|
|
3883
3918
|
);
|
|
3884
3919
|
}
|
|
@@ -4057,6 +4092,7 @@ async function createTestApp(options = {}) {
|
|
|
4057
4092
|
const messages = createMessages();
|
|
4058
4093
|
const edge = createEdge();
|
|
4059
4094
|
const starlens = createStarlens();
|
|
4095
|
+
const schedules = createSchedules();
|
|
4060
4096
|
const app = {
|
|
4061
4097
|
db,
|
|
4062
4098
|
inbox,
|
|
@@ -4066,6 +4102,7 @@ async function createTestApp(options = {}) {
|
|
|
4066
4102
|
messages,
|
|
4067
4103
|
edge,
|
|
4068
4104
|
starlens,
|
|
4105
|
+
schedules,
|
|
4069
4106
|
async query(sql, params = []) {
|
|
4070
4107
|
const result = await db.query(sql, params);
|
|
4071
4108
|
return result.rows;
|
|
@@ -4114,6 +4151,7 @@ async function createTestApp(options = {}) {
|
|
|
4114
4151
|
messages.clear();
|
|
4115
4152
|
edge.clear();
|
|
4116
4153
|
starlens.clear();
|
|
4154
|
+
schedules.clear();
|
|
4117
4155
|
},
|
|
4118
4156
|
async close() {
|
|
4119
4157
|
state.db = null;
|
|
@@ -4129,6 +4167,7 @@ async function createTestApp(options = {}) {
|
|
|
4129
4167
|
messages.clear();
|
|
4130
4168
|
edge.clear();
|
|
4131
4169
|
starlens.clear();
|
|
4170
|
+
schedules.clear();
|
|
4132
4171
|
uninstallFetchRouter();
|
|
4133
4172
|
await db.close();
|
|
4134
4173
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -299,6 +299,7 @@ var state = globalSingleton("state", () => ({
|
|
|
299
299
|
identitySuppressClaimDelivery: false,
|
|
300
300
|
identityAllowedReturnOrigins: /* @__PURE__ */ new Set([APP_TEST_ORIGIN]),
|
|
301
301
|
checkouts: [],
|
|
302
|
+
scheduleWakes: [],
|
|
302
303
|
checkoutCounter: 0,
|
|
303
304
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
304
305
|
idempotentCheckouts: /* @__PURE__ */ new Map(),
|
|
@@ -3401,7 +3402,9 @@ async function handleEnqueue(request) {
|
|
|
3401
3402
|
function durableView(jobId, as) {
|
|
3402
3403
|
const job = state.edgeDurableJobs.get(jobId);
|
|
3403
3404
|
const createdAt = now2();
|
|
3405
|
+
const simulated = job.outcome.status !== "needs_attention" && job.outcome.simulated ? { simulated: true } : {};
|
|
3404
3406
|
const base = {
|
|
3407
|
+
...simulated,
|
|
3405
3408
|
jobId,
|
|
3406
3409
|
attempts: as === "queued" ? 0 : 1,
|
|
3407
3410
|
createdAt,
|
|
@@ -3585,6 +3588,32 @@ function createEdge() {
|
|
|
3585
3588
|
};
|
|
3586
3589
|
}
|
|
3587
3590
|
|
|
3591
|
+
// src/simulator/schedules.ts
|
|
3592
|
+
async function handleScheduleWake(request, scheduleKey) {
|
|
3593
|
+
if (request.method !== "POST") return failure(`Method ${request.method} not allowed`, 405);
|
|
3594
|
+
const body = await readJsonBody(request);
|
|
3595
|
+
const at = typeof body.at === "string" ? new Date(body.at) : null;
|
|
3596
|
+
if (!at || Number.isNaN(at.getTime())) return failure("`at` must be an ISO date-time", 400);
|
|
3597
|
+
state.scheduleWakes.push({ scheduleKey, at, requestedAt: /* @__PURE__ */ new Date() });
|
|
3598
|
+
return success({ woken: true });
|
|
3599
|
+
}
|
|
3600
|
+
function createSchedules() {
|
|
3601
|
+
return {
|
|
3602
|
+
get wakes() {
|
|
3603
|
+
return state.scheduleWakes;
|
|
3604
|
+
},
|
|
3605
|
+
wakesFor(scheduleKey) {
|
|
3606
|
+
return state.scheduleWakes.filter((wake) => wake.scheduleKey === scheduleKey);
|
|
3607
|
+
},
|
|
3608
|
+
earliestWake(scheduleKey) {
|
|
3609
|
+
return this.wakesFor(scheduleKey).map((wake) => wake.at).sort((a, b) => a.getTime() - b.getTime())[0];
|
|
3610
|
+
},
|
|
3611
|
+
clear() {
|
|
3612
|
+
state.scheduleWakes = [];
|
|
3613
|
+
}
|
|
3614
|
+
};
|
|
3615
|
+
}
|
|
3616
|
+
|
|
3588
3617
|
// src/simulator/starlens.ts
|
|
3589
3618
|
var LATEST_VERSION = "v2";
|
|
3590
3619
|
function starlensFailure(error, status, code) {
|
|
@@ -3749,8 +3778,10 @@ function requiresDeploymentHmac(request, url) {
|
|
|
3749
3778
|
);
|
|
3750
3779
|
const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
|
|
3751
3780
|
const isStarlens = url.pathname === "/api/starlens/extract";
|
|
3752
|
-
|
|
3781
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
3782
|
+
return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
|
|
3753
3783
|
}
|
|
3784
|
+
var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
|
|
3754
3785
|
function deploymentIdFromPath(url) {
|
|
3755
3786
|
const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
|
|
3756
3787
|
if (!match) return null;
|
|
@@ -3815,6 +3846,10 @@ async function handleSimulatedRequest(request, url) {
|
|
|
3815
3846
|
if (edgeMatch) {
|
|
3816
3847
|
return handleEdgeRequest(request, edgeMatch[1] ?? "");
|
|
3817
3848
|
}
|
|
3849
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
3850
|
+
if (scheduleWakeMatch) {
|
|
3851
|
+
return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
|
|
3852
|
+
}
|
|
3818
3853
|
if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
|
|
3819
3854
|
return handleStarlensExtract(request, signedDeploymentId);
|
|
3820
3855
|
}
|
|
@@ -3839,7 +3874,7 @@ async function handleSimulatedRequest(request, url) {
|
|
|
3839
3874
|
}
|
|
3840
3875
|
}
|
|
3841
3876
|
return failure(
|
|
3842
|
-
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, auth verify/refresh, Neon /sql.`,
|
|
3877
|
+
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, schedule wakes, auth verify/refresh, Neon /sql.`,
|
|
3843
3878
|
404
|
|
3844
3879
|
);
|
|
3845
3880
|
}
|
|
@@ -4018,6 +4053,7 @@ async function createTestApp(options = {}) {
|
|
|
4018
4053
|
const messages = createMessages();
|
|
4019
4054
|
const edge = createEdge();
|
|
4020
4055
|
const starlens = createStarlens();
|
|
4056
|
+
const schedules = createSchedules();
|
|
4021
4057
|
const app = {
|
|
4022
4058
|
db,
|
|
4023
4059
|
inbox,
|
|
@@ -4027,6 +4063,7 @@ async function createTestApp(options = {}) {
|
|
|
4027
4063
|
messages,
|
|
4028
4064
|
edge,
|
|
4029
4065
|
starlens,
|
|
4066
|
+
schedules,
|
|
4030
4067
|
async query(sql, params = []) {
|
|
4031
4068
|
const result = await db.query(sql, params);
|
|
4032
4069
|
return result.rows;
|
|
@@ -4075,6 +4112,7 @@ async function createTestApp(options = {}) {
|
|
|
4075
4112
|
messages.clear();
|
|
4076
4113
|
edge.clear();
|
|
4077
4114
|
starlens.clear();
|
|
4115
|
+
schedules.clear();
|
|
4078
4116
|
},
|
|
4079
4117
|
async close() {
|
|
4080
4118
|
state.db = null;
|
|
@@ -4090,6 +4128,7 @@ async function createTestApp(options = {}) {
|
|
|
4090
4128
|
messages.clear();
|
|
4091
4129
|
edge.clear();
|
|
4092
4130
|
starlens.clear();
|
|
4131
|
+
schedules.clear();
|
|
4093
4132
|
uninstallFetchRouter();
|
|
4094
4133
|
await db.close();
|
|
4095
4134
|
}
|
|
@@ -60,6 +60,7 @@ var state = globalSingleton("state", () => ({
|
|
|
60
60
|
identitySuppressClaimDelivery: false,
|
|
61
61
|
identityAllowedReturnOrigins: /* @__PURE__ */ new Set([APP_TEST_ORIGIN]),
|
|
62
62
|
checkouts: [],
|
|
63
|
+
scheduleWakes: [],
|
|
63
64
|
checkoutCounter: 0,
|
|
64
65
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
65
66
|
idempotentCheckouts: /* @__PURE__ */ new Map(),
|
|
@@ -33,6 +33,7 @@ var state = globalSingleton("state", () => ({
|
|
|
33
33
|
identitySuppressClaimDelivery: false,
|
|
34
34
|
identityAllowedReturnOrigins: /* @__PURE__ */ new Set([APP_TEST_ORIGIN]),
|
|
35
35
|
checkouts: [],
|
|
36
|
+
scheduleWakes: [],
|
|
36
37
|
checkoutCounter: 0,
|
|
37
38
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
38
39
|
idempotentCheckouts: /* @__PURE__ */ new Map(),
|
package/dist/setup.js
CHANGED
|
@@ -65,6 +65,7 @@ var state = globalSingleton("state", () => ({
|
|
|
65
65
|
identitySuppressClaimDelivery: false,
|
|
66
66
|
identityAllowedReturnOrigins: /* @__PURE__ */ new Set([APP_TEST_ORIGIN]),
|
|
67
67
|
checkouts: [],
|
|
68
|
+
scheduleWakes: [],
|
|
68
69
|
checkoutCounter: 0,
|
|
69
70
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
70
71
|
idempotentCheckouts: /* @__PURE__ */ new Map(),
|
|
@@ -2585,7 +2586,9 @@ async function handleEnqueue(request) {
|
|
|
2585
2586
|
function durableView(jobId, as) {
|
|
2586
2587
|
const job = state.edgeDurableJobs.get(jobId);
|
|
2587
2588
|
const createdAt = now2();
|
|
2589
|
+
const simulated = job.outcome.status !== "needs_attention" && job.outcome.simulated ? { simulated: true } : {};
|
|
2588
2590
|
const base = {
|
|
2591
|
+
...simulated,
|
|
2589
2592
|
jobId,
|
|
2590
2593
|
attempts: as === "queued" ? 0 : 1,
|
|
2591
2594
|
createdAt,
|
|
@@ -2705,6 +2708,16 @@ async function handleEdgeRequest(request, subPath) {
|
|
|
2705
2708
|
return edgeFailure(`No edge simulator for ${method} .../edge${subPath}`, 404);
|
|
2706
2709
|
}
|
|
2707
2710
|
|
|
2711
|
+
// src/simulator/schedules.ts
|
|
2712
|
+
async function handleScheduleWake(request, scheduleKey) {
|
|
2713
|
+
if (request.method !== "POST") return failure(`Method ${request.method} not allowed`, 405);
|
|
2714
|
+
const body = await readJsonBody(request);
|
|
2715
|
+
const at = typeof body.at === "string" ? new Date(body.at) : null;
|
|
2716
|
+
if (!at || Number.isNaN(at.getTime())) return failure("`at` must be an ISO date-time", 400);
|
|
2717
|
+
state.scheduleWakes.push({ scheduleKey, at, requestedAt: /* @__PURE__ */ new Date() });
|
|
2718
|
+
return success({ woken: true });
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2708
2721
|
// src/simulator/starlens.ts
|
|
2709
2722
|
var LATEST_VERSION = "v2";
|
|
2710
2723
|
function starlensFailure(error, status, code) {
|
|
@@ -2842,8 +2855,10 @@ function requiresDeploymentHmac(request, url) {
|
|
|
2842
2855
|
);
|
|
2843
2856
|
const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
|
|
2844
2857
|
const isStarlens = url.pathname === "/api/starlens/extract";
|
|
2845
|
-
|
|
2858
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
2859
|
+
return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
|
|
2846
2860
|
}
|
|
2861
|
+
var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
|
|
2847
2862
|
function deploymentIdFromPath(url) {
|
|
2848
2863
|
const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
|
|
2849
2864
|
if (!match) return null;
|
|
@@ -2908,6 +2923,10 @@ async function handleSimulatedRequest(request, url) {
|
|
|
2908
2923
|
if (edgeMatch) {
|
|
2909
2924
|
return handleEdgeRequest(request, edgeMatch[1] ?? "");
|
|
2910
2925
|
}
|
|
2926
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
2927
|
+
if (scheduleWakeMatch) {
|
|
2928
|
+
return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
|
|
2929
|
+
}
|
|
2911
2930
|
if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
|
|
2912
2931
|
return handleStarlensExtract(request, signedDeploymentId);
|
|
2913
2932
|
}
|
|
@@ -2932,7 +2951,7 @@ async function handleSimulatedRequest(request, url) {
|
|
|
2932
2951
|
}
|
|
2933
2952
|
}
|
|
2934
2953
|
return failure(
|
|
2935
|
-
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, auth verify/refresh, Neon /sql.`,
|
|
2954
|
+
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, schedule wakes, auth verify/refresh, Neon /sql.`,
|
|
2936
2955
|
404
|
|
2937
2956
|
);
|
|
2938
2957
|
}
|
package/dist/setup.mjs
CHANGED
|
@@ -41,6 +41,7 @@ var state = globalSingleton("state", () => ({
|
|
|
41
41
|
identitySuppressClaimDelivery: false,
|
|
42
42
|
identityAllowedReturnOrigins: /* @__PURE__ */ new Set([APP_TEST_ORIGIN]),
|
|
43
43
|
checkouts: [],
|
|
44
|
+
scheduleWakes: [],
|
|
44
45
|
checkoutCounter: 0,
|
|
45
46
|
sessionStatuses: /* @__PURE__ */ new Map(),
|
|
46
47
|
idempotentCheckouts: /* @__PURE__ */ new Map(),
|
|
@@ -2561,7 +2562,9 @@ async function handleEnqueue(request) {
|
|
|
2561
2562
|
function durableView(jobId, as) {
|
|
2562
2563
|
const job = state.edgeDurableJobs.get(jobId);
|
|
2563
2564
|
const createdAt = now2();
|
|
2565
|
+
const simulated = job.outcome.status !== "needs_attention" && job.outcome.simulated ? { simulated: true } : {};
|
|
2564
2566
|
const base = {
|
|
2567
|
+
...simulated,
|
|
2565
2568
|
jobId,
|
|
2566
2569
|
attempts: as === "queued" ? 0 : 1,
|
|
2567
2570
|
createdAt,
|
|
@@ -2681,6 +2684,16 @@ async function handleEdgeRequest(request, subPath) {
|
|
|
2681
2684
|
return edgeFailure(`No edge simulator for ${method} .../edge${subPath}`, 404);
|
|
2682
2685
|
}
|
|
2683
2686
|
|
|
2687
|
+
// src/simulator/schedules.ts
|
|
2688
|
+
async function handleScheduleWake(request, scheduleKey) {
|
|
2689
|
+
if (request.method !== "POST") return failure(`Method ${request.method} not allowed`, 405);
|
|
2690
|
+
const body = await readJsonBody(request);
|
|
2691
|
+
const at = typeof body.at === "string" ? new Date(body.at) : null;
|
|
2692
|
+
if (!at || Number.isNaN(at.getTime())) return failure("`at` must be an ISO date-time", 400);
|
|
2693
|
+
state.scheduleWakes.push({ scheduleKey, at, requestedAt: /* @__PURE__ */ new Date() });
|
|
2694
|
+
return success({ woken: true });
|
|
2695
|
+
}
|
|
2696
|
+
|
|
2684
2697
|
// src/simulator/starlens.ts
|
|
2685
2698
|
var LATEST_VERSION = "v2";
|
|
2686
2699
|
function starlensFailure(error, status, code) {
|
|
@@ -2818,8 +2831,10 @@ function requiresDeploymentHmac(request, url) {
|
|
|
2818
2831
|
);
|
|
2819
2832
|
const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
|
|
2820
2833
|
const isStarlens = url.pathname === "/api/starlens/extract";
|
|
2821
|
-
|
|
2834
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
2835
|
+
return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
|
|
2822
2836
|
}
|
|
2837
|
+
var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
|
|
2823
2838
|
function deploymentIdFromPath(url) {
|
|
2824
2839
|
const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
|
|
2825
2840
|
if (!match) return null;
|
|
@@ -2884,6 +2899,10 @@ async function handleSimulatedRequest(request, url) {
|
|
|
2884
2899
|
if (edgeMatch) {
|
|
2885
2900
|
return handleEdgeRequest(request, edgeMatch[1] ?? "");
|
|
2886
2901
|
}
|
|
2902
|
+
const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
|
|
2903
|
+
if (scheduleWakeMatch) {
|
|
2904
|
+
return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
|
|
2905
|
+
}
|
|
2887
2906
|
if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
|
|
2888
2907
|
return handleStarlensExtract(request, signedDeploymentId);
|
|
2889
2908
|
}
|
|
@@ -2908,7 +2927,7 @@ async function handleSimulatedRequest(request, url) {
|
|
|
2908
2927
|
}
|
|
2909
2928
|
}
|
|
2910
2929
|
return failure(
|
|
2911
|
-
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, auth verify/refresh, Neon /sql.`,
|
|
2930
|
+
`[stardeck-testing] No simulator for ${request.method} ${url.pathname}. Supported: data-store query/mutate/schema, email send, identities CRUD, payments store/checkout, storage upload/files, messaging send, edge print/display/bindings, starlens extract, schedule wakes, auth verify/refresh, Neon /sql.`,
|
|
2912
2931
|
404
|
|
2913
2932
|
);
|
|
2914
2933
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stardeck-customer-apps/testing",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.26.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",
|
|
@@ -100,6 +100,7 @@
|
|
|
100
100
|
"@stardeck-customer-apps/email-sdk": "*",
|
|
101
101
|
"@stardeck-customer-apps/integrations-sdk": "*",
|
|
102
102
|
"@stardeck-customer-apps/payments-sdk": "*",
|
|
103
|
+
"@stardeck-customer-apps/scheduling-sdk": "*",
|
|
103
104
|
"@stardeck-customer-apps/storage-sdk": "*",
|
|
104
105
|
"@stardeck-customer-apps/tsconfig": "*",
|
|
105
106
|
"@types/node": "^24.10.1",
|