@stardeck-customer-apps/testing 0.25.1 → 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 CHANGED
@@ -586,6 +586,12 @@ cursor, limit })`; `list()` intentionally keeps its previous array shape.
586
586
  high request with no image input answers `effort: "low"` as production does;
587
587
  pass `effort: "low"` in `app.starlens.mock(...)` to simulate an image production
588
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.
589
595
 
590
596
  ### Receipt layout and printer capabilities
591
597
 
package/dist/index.d.mts CHANGED
@@ -652,6 +652,20 @@ interface TestStarlens {
652
652
  clear(): void;
653
653
  get count(): number;
654
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
+ }
655
669
  interface TestAppOptions {
656
670
  /**
657
671
  * The LIFF ID the platform forwards to the app for a LINE MINI App shop. It is
@@ -704,6 +718,8 @@ interface TestApp {
704
718
  edge: TestEdge;
705
719
  /** Scripted replies and captured calls for the Starlens SDK. */
706
720
  starlens: TestStarlens;
721
+ /** Wakes the app asked of its adaptive schedules (`wakeSchedule`). */
722
+ schedules: TestSchedules;
707
723
  /** Convenience for raw SQL: `app.query("SELECT ...", [param])`. */
708
724
  query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
709
725
  /**
@@ -774,4 +790,4 @@ declare const TEST_ENV_DEFAULTS: {
774
790
  /** Default location of the DDL snapshot written by `generate-types`. */
775
791
  declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
776
792
 
777
- 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
@@ -652,6 +652,20 @@ interface TestStarlens {
652
652
  clear(): void;
653
653
  get count(): number;
654
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
+ }
655
669
  interface TestAppOptions {
656
670
  /**
657
671
  * The LIFF ID the platform forwards to the app for a LINE MINI App shop. It is
@@ -704,6 +718,8 @@ interface TestApp {
704
718
  edge: TestEdge;
705
719
  /** Scripted replies and captured calls for the Starlens SDK. */
706
720
  starlens: TestStarlens;
721
+ /** Wakes the app asked of its adaptive schedules (`wakeSchedule`). */
722
+ schedules: TestSchedules;
707
723
  /** Convenience for raw SQL: `app.query("SELECT ...", [param])`. */
708
724
  query<T = Record<string, unknown>>(sql: string, params?: unknown[]): Promise<T[]>;
709
725
  /**
@@ -774,4 +790,4 @@ declare const TEST_ENV_DEFAULTS: {
774
790
  /** Default location of the DDL snapshot written by `generate-types`. */
775
791
  declare const DEFAULT_SCHEMA_PATH = "./src/generated/data-store-schema.sql";
776
792
 
777
- 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(),
@@ -3626,6 +3627,32 @@ function createEdge() {
3626
3627
  };
3627
3628
  }
3628
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
+
3629
3656
  // src/simulator/starlens.ts
3630
3657
  var LATEST_VERSION = "v2";
3631
3658
  function starlensFailure(error, status, code) {
@@ -3790,8 +3817,10 @@ function requiresDeploymentHmac(request, url) {
3790
3817
  );
3791
3818
  const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
3792
3819
  const isStarlens = url.pathname === "/api/starlens/extract";
3793
- return !!(isStarlens || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
3820
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
3821
+ return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
3794
3822
  }
3823
+ var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
3795
3824
  function deploymentIdFromPath(url) {
3796
3825
  const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
3797
3826
  if (!match) return null;
@@ -3856,6 +3885,10 @@ async function handleSimulatedRequest(request, url) {
3856
3885
  if (edgeMatch) {
3857
3886
  return handleEdgeRequest(request, edgeMatch[1] ?? "");
3858
3887
  }
3888
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
3889
+ if (scheduleWakeMatch) {
3890
+ return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
3891
+ }
3859
3892
  if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
3860
3893
  return handleStarlensExtract(request, signedDeploymentId);
3861
3894
  }
@@ -3880,7 +3913,7 @@ async function handleSimulatedRequest(request, url) {
3880
3913
  }
3881
3914
  }
3882
3915
  return failure(
3883
- `[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.`,
3884
3917
  404
3885
3918
  );
3886
3919
  }
@@ -4059,6 +4092,7 @@ async function createTestApp(options = {}) {
4059
4092
  const messages = createMessages();
4060
4093
  const edge = createEdge();
4061
4094
  const starlens = createStarlens();
4095
+ const schedules = createSchedules();
4062
4096
  const app = {
4063
4097
  db,
4064
4098
  inbox,
@@ -4068,6 +4102,7 @@ async function createTestApp(options = {}) {
4068
4102
  messages,
4069
4103
  edge,
4070
4104
  starlens,
4105
+ schedules,
4071
4106
  async query(sql, params = []) {
4072
4107
  const result = await db.query(sql, params);
4073
4108
  return result.rows;
@@ -4116,6 +4151,7 @@ async function createTestApp(options = {}) {
4116
4151
  messages.clear();
4117
4152
  edge.clear();
4118
4153
  starlens.clear();
4154
+ schedules.clear();
4119
4155
  },
4120
4156
  async close() {
4121
4157
  state.db = null;
@@ -4131,6 +4167,7 @@ async function createTestApp(options = {}) {
4131
4167
  messages.clear();
4132
4168
  edge.clear();
4133
4169
  starlens.clear();
4170
+ schedules.clear();
4134
4171
  uninstallFetchRouter();
4135
4172
  await db.close();
4136
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(),
@@ -3587,6 +3588,32 @@ function createEdge() {
3587
3588
  };
3588
3589
  }
3589
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
+
3590
3617
  // src/simulator/starlens.ts
3591
3618
  var LATEST_VERSION = "v2";
3592
3619
  function starlensFailure(error, status, code) {
@@ -3751,8 +3778,10 @@ function requiresDeploymentHmac(request, url) {
3751
3778
  );
3752
3779
  const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
3753
3780
  const isStarlens = url.pathname === "/api/starlens/extract";
3754
- return !!(isStarlens || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
3781
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
3782
+ return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
3755
3783
  }
3784
+ var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
3756
3785
  function deploymentIdFromPath(url) {
3757
3786
  const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
3758
3787
  if (!match) return null;
@@ -3817,6 +3846,10 @@ async function handleSimulatedRequest(request, url) {
3817
3846
  if (edgeMatch) {
3818
3847
  return handleEdgeRequest(request, edgeMatch[1] ?? "");
3819
3848
  }
3849
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
3850
+ if (scheduleWakeMatch) {
3851
+ return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
3852
+ }
3820
3853
  if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
3821
3854
  return handleStarlensExtract(request, signedDeploymentId);
3822
3855
  }
@@ -3841,7 +3874,7 @@ async function handleSimulatedRequest(request, url) {
3841
3874
  }
3842
3875
  }
3843
3876
  return failure(
3844
- `[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.`,
3845
3878
  404
3846
3879
  );
3847
3880
  }
@@ -4020,6 +4053,7 @@ async function createTestApp(options = {}) {
4020
4053
  const messages = createMessages();
4021
4054
  const edge = createEdge();
4022
4055
  const starlens = createStarlens();
4056
+ const schedules = createSchedules();
4023
4057
  const app = {
4024
4058
  db,
4025
4059
  inbox,
@@ -4029,6 +4063,7 @@ async function createTestApp(options = {}) {
4029
4063
  messages,
4030
4064
  edge,
4031
4065
  starlens,
4066
+ schedules,
4032
4067
  async query(sql, params = []) {
4033
4068
  const result = await db.query(sql, params);
4034
4069
  return result.rows;
@@ -4077,6 +4112,7 @@ async function createTestApp(options = {}) {
4077
4112
  messages.clear();
4078
4113
  edge.clear();
4079
4114
  starlens.clear();
4115
+ schedules.clear();
4080
4116
  },
4081
4117
  async close() {
4082
4118
  state.db = null;
@@ -4092,6 +4128,7 @@ async function createTestApp(options = {}) {
4092
4128
  messages.clear();
4093
4129
  edge.clear();
4094
4130
  starlens.clear();
4131
+ schedules.clear();
4095
4132
  uninstallFetchRouter();
4096
4133
  await db.close();
4097
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(),
@@ -2707,6 +2708,16 @@ async function handleEdgeRequest(request, subPath) {
2707
2708
  return edgeFailure(`No edge simulator for ${method} .../edge${subPath}`, 404);
2708
2709
  }
2709
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
+
2710
2721
  // src/simulator/starlens.ts
2711
2722
  var LATEST_VERSION = "v2";
2712
2723
  function starlensFailure(error, status, code) {
@@ -2844,8 +2855,10 @@ function requiresDeploymentHmac(request, url) {
2844
2855
  );
2845
2856
  const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
2846
2857
  const isStarlens = url.pathname === "/api/starlens/extract";
2847
- return !!(isStarlens || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
2858
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
2859
+ return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
2848
2860
  }
2861
+ var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
2849
2862
  function deploymentIdFromPath(url) {
2850
2863
  const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
2851
2864
  if (!match) return null;
@@ -2910,6 +2923,10 @@ async function handleSimulatedRequest(request, url) {
2910
2923
  if (edgeMatch) {
2911
2924
  return handleEdgeRequest(request, edgeMatch[1] ?? "");
2912
2925
  }
2926
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
2927
+ if (scheduleWakeMatch) {
2928
+ return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
2929
+ }
2913
2930
  if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
2914
2931
  return handleStarlensExtract(request, signedDeploymentId);
2915
2932
  }
@@ -2934,7 +2951,7 @@ async function handleSimulatedRequest(request, url) {
2934
2951
  }
2935
2952
  }
2936
2953
  return failure(
2937
- `[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.`,
2938
2955
  404
2939
2956
  );
2940
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(),
@@ -2683,6 +2684,16 @@ async function handleEdgeRequest(request, subPath) {
2683
2684
  return edgeFailure(`No edge simulator for ${method} .../edge${subPath}`, 404);
2684
2685
  }
2685
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
+
2686
2697
  // src/simulator/starlens.ts
2687
2698
  var LATEST_VERSION = "v2";
2688
2699
  function starlensFailure(error, status, code) {
@@ -2820,8 +2831,10 @@ function requiresDeploymentHmac(request, url) {
2820
2831
  );
2821
2832
  const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
2822
2833
  const isStarlens = url.pathname === "/api/starlens/extract";
2823
- return !!(isStarlens || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
2834
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
2835
+ return !!(isStarlens || scheduleWakeMatch || dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
2824
2836
  }
2837
+ var SCHEDULE_WAKE_PATH = /^\/api\/deployments\/[^/]+\/schedules\/([^/]+)\/wake$/;
2825
2838
  function deploymentIdFromPath(url) {
2826
2839
  const match = url.pathname.match(/\/api\/deployments\/([^/]+)(?:\/|$)/);
2827
2840
  if (!match) return null;
@@ -2886,6 +2899,10 @@ async function handleSimulatedRequest(request, url) {
2886
2899
  if (edgeMatch) {
2887
2900
  return handleEdgeRequest(request, edgeMatch[1] ?? "");
2888
2901
  }
2902
+ const scheduleWakeMatch = url.pathname.match(SCHEDULE_WAKE_PATH);
2903
+ if (scheduleWakeMatch) {
2904
+ return handleScheduleWake(request, decodeURIComponent(scheduleWakeMatch[1]));
2905
+ }
2889
2906
  if (url.pathname === "/api/starlens/extract" && request.method === "POST") {
2890
2907
  return handleStarlensExtract(request, signedDeploymentId);
2891
2908
  }
@@ -2910,7 +2927,7 @@ async function handleSimulatedRequest(request, url) {
2910
2927
  }
2911
2928
  }
2912
2929
  return failure(
2913
- `[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.`,
2914
2931
  404
2915
2932
  );
2916
2933
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stardeck-customer-apps/testing",
3
- "version": "0.25.1",
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",