@stardeck-customer-apps/testing 0.4.0 → 0.5.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/dist/index.mjs CHANGED
@@ -64,6 +64,13 @@ var state = globalSingleton("state", () => ({
64
64
  storageFiles: /* @__PURE__ */ new Map(),
65
65
  presignPending: /* @__PURE__ */ new Map(),
66
66
  messages: [],
67
+ edgePrints: [],
68
+ edgeDisplays: [],
69
+ edgeTestPrints: [],
70
+ edgePrintCounter: 0,
71
+ edgeDevices: [],
72
+ edgePeripherals: [],
73
+ edgeBindings: /* @__PURE__ */ new Map(),
67
74
  allowNetwork: false
68
75
  }));
69
76
  function requireDb() {
@@ -126,8 +133,8 @@ function verifyDeploymentAuthHeader(secret, header) {
126
133
  return null;
127
134
  }
128
135
  if (payload.type !== "deployment-request") return null;
129
- const now2 = Math.floor(Date.now() / 1e3);
130
- if (Math.abs(now2 - payload.timestamp) > TIMESTAMP_TOLERANCE_SECONDS) return null;
136
+ const now3 = Math.floor(Date.now() / 1e3);
137
+ if (Math.abs(now3 - payload.timestamp) > TIMESTAMP_TOLERANCE_SECONDS) return null;
131
138
  return payload;
132
139
  }
133
140
 
@@ -1429,6 +1436,224 @@ function createMessages() {
1429
1436
  };
1430
1437
  }
1431
1438
 
1439
+ // src/simulator/edge.ts
1440
+ function edgeFailure(error, status = 400, code) {
1441
+ return json({ success: false, error, ...code ? { code } : {} }, status);
1442
+ }
1443
+ function bindingNotFound(alias) {
1444
+ return edgeFailure(`No peripheral is paired to alias "${alias}"`, 404, "BINDING_NOT_FOUND");
1445
+ }
1446
+ function now2() {
1447
+ return (/* @__PURE__ */ new Date()).toISOString();
1448
+ }
1449
+ function nextJobId() {
1450
+ state.edgePrintCounter += 1;
1451
+ return `job_${state.edgePrintCounter}`;
1452
+ }
1453
+ function nextConfigVersion() {
1454
+ return state.edgeDisplays.length + 1;
1455
+ }
1456
+ function findPeripheral(id) {
1457
+ return state.edgePeripherals.find((p) => p.id === id);
1458
+ }
1459
+ function buildBinding(alias, peripheralId) {
1460
+ const peripheral = findPeripheral(peripheralId);
1461
+ return {
1462
+ alias,
1463
+ state: peripheral ? "ok" : "peripheral_missing",
1464
+ peripheral: peripheral ? {
1465
+ id: peripheral.id,
1466
+ displayName: peripheral.displayName,
1467
+ driver: peripheral.driver,
1468
+ connected: peripheral.connected
1469
+ } : null,
1470
+ device: peripheral ? {
1471
+ id: peripheral.device.id,
1472
+ displayName: peripheral.device.displayName,
1473
+ status: peripheral.device.status
1474
+ } : null,
1475
+ updatedAt: now2()
1476
+ };
1477
+ }
1478
+ function handleListDevices() {
1479
+ return success({ devices: [...state.edgeDevices] });
1480
+ }
1481
+ function handleListPeripherals(request) {
1482
+ const deviceId = new URL(request.url).searchParams.get("deviceId");
1483
+ const peripherals = deviceId ? state.edgePeripherals.filter((p) => p.device.id === deviceId) : [...state.edgePeripherals];
1484
+ return success({ peripherals });
1485
+ }
1486
+ function handleListBindings() {
1487
+ return success({ bindings: [...state.edgeBindings.values()] });
1488
+ }
1489
+ function handleGetBinding(alias) {
1490
+ const binding = state.edgeBindings.get(alias);
1491
+ if (!binding) return bindingNotFound(alias);
1492
+ return success({ binding });
1493
+ }
1494
+ async function handlePair(request) {
1495
+ const body = await readJsonBody(request);
1496
+ const alias = String(body.alias ?? "");
1497
+ const peripheralId = String(body.peripheralId ?? "");
1498
+ if (!alias) return edgeFailure("alias is required");
1499
+ if (!peripheralId) return edgeFailure("peripheralId is required");
1500
+ if (!findPeripheral(peripheralId)) {
1501
+ return edgeFailure("Peripheral not found or its device is not granted to this project", 404);
1502
+ }
1503
+ const binding = buildBinding(alias, peripheralId);
1504
+ state.edgeBindings.set(alias, binding);
1505
+ return success({ binding });
1506
+ }
1507
+ function handleUnpair(alias) {
1508
+ const existed = state.edgeBindings.delete(alias);
1509
+ if (!existed) return bindingNotFound(alias);
1510
+ return success({ deleted: true });
1511
+ }
1512
+ async function handlePrint(request) {
1513
+ const body = await readJsonBody(request);
1514
+ const jobId = nextJobId();
1515
+ const captured = {
1516
+ jobId,
1517
+ deploymentId: String(body.deploymentId ?? ""),
1518
+ alias: body.alias ? String(body.alias) : void 0,
1519
+ deviceId: body.deviceId ? String(body.deviceId) : void 0,
1520
+ peripheralId: body.peripheralId ? String(body.peripheralId) : void 0,
1521
+ receipt: body.receipt ?? {},
1522
+ openDrawer: body.openDrawer === true,
1523
+ logo: body.logo === true ? true : body.logo === false ? false : void 0,
1524
+ copies: typeof body.copies === "number" ? body.copies : 1
1525
+ };
1526
+ state.edgePrints.push(captured);
1527
+ return success({
1528
+ jobId,
1529
+ status: "completed"
1530
+ });
1531
+ }
1532
+ async function handleShowDisplay(request) {
1533
+ const body = await readJsonBody(request);
1534
+ const captured = {
1535
+ action: "show",
1536
+ alias: body.alias ? String(body.alias) : void 0,
1537
+ peripheralId: body.peripheralId ? String(body.peripheralId) : void 0,
1538
+ url: body.url ? String(body.url) : void 0
1539
+ };
1540
+ state.edgeDisplays.push(captured);
1541
+ return success({
1542
+ configVersion: nextConfigVersion(),
1543
+ pushed: true,
1544
+ state: "showing"
1545
+ });
1546
+ }
1547
+ function handleClearDisplay(request) {
1548
+ const url = new URL(request.url);
1549
+ const alias = url.searchParams.get("alias");
1550
+ const peripheralId = url.searchParams.get("peripheralId");
1551
+ const captured = {
1552
+ action: "clear",
1553
+ alias: alias ?? void 0,
1554
+ peripheralId: peripheralId ?? void 0
1555
+ };
1556
+ state.edgeDisplays.push(captured);
1557
+ return success({
1558
+ configVersion: nextConfigVersion(),
1559
+ pushed: true,
1560
+ state: "cleared"
1561
+ });
1562
+ }
1563
+ async function handleTestPrint(request) {
1564
+ const body = await readJsonBody(request);
1565
+ const captured = {
1566
+ alias: body.alias ? String(body.alias) : void 0,
1567
+ deviceId: body.deviceId ? String(body.deviceId) : void 0,
1568
+ peripheralId: body.peripheralId ? String(body.peripheralId) : void 0
1569
+ };
1570
+ state.edgeTestPrints.push(captured);
1571
+ return success({
1572
+ status: "ok",
1573
+ peripheralId: captured.peripheralId ?? captured.alias ?? "default"
1574
+ });
1575
+ }
1576
+ async function handleEdgeRequest(request, subPath) {
1577
+ const method = request.method;
1578
+ if (subPath === "/print" && method === "POST") {
1579
+ return handlePrint(request);
1580
+ }
1581
+ if (subPath === "/devices" && method === "GET") {
1582
+ return handleListDevices();
1583
+ }
1584
+ if (subPath === "/peripherals" && method === "GET") {
1585
+ return handleListPeripherals(request);
1586
+ }
1587
+ if (subPath === "/bindings" && method === "GET") {
1588
+ return handleListBindings();
1589
+ }
1590
+ if (subPath === "/bindings" && method === "PUT") {
1591
+ return handlePair(request);
1592
+ }
1593
+ const bindingMatch = subPath.match(/^\/bindings\/([^/]+)$/);
1594
+ if (bindingMatch) {
1595
+ const alias = decodeURIComponent(bindingMatch[1]);
1596
+ if (method === "GET") return handleGetBinding(alias);
1597
+ if (method === "DELETE") return handleUnpair(alias);
1598
+ }
1599
+ if (subPath === "/display" && method === "POST") {
1600
+ return handleShowDisplay(request);
1601
+ }
1602
+ if (subPath === "/display" && method === "DELETE") {
1603
+ return handleClearDisplay(request);
1604
+ }
1605
+ if (subPath === "/test-print" && method === "POST") {
1606
+ return handleTestPrint(request);
1607
+ }
1608
+ return edgeFailure(`No edge simulator for ${method} .../edge${subPath}`, 404);
1609
+ }
1610
+ function createEdge() {
1611
+ return {
1612
+ get prints() {
1613
+ return [...state.edgePrints];
1614
+ },
1615
+ get displays() {
1616
+ return [...state.edgeDisplays];
1617
+ },
1618
+ get testPrints() {
1619
+ return [...state.edgeTestPrints];
1620
+ },
1621
+ latestPrint() {
1622
+ return state.edgePrints[state.edgePrints.length - 1];
1623
+ },
1624
+ latestDisplay() {
1625
+ return state.edgeDisplays[state.edgeDisplays.length - 1];
1626
+ },
1627
+ get bindings() {
1628
+ return [...state.edgeBindings.values()];
1629
+ },
1630
+ seedDevices(devices) {
1631
+ state.edgeDevices = [...devices];
1632
+ },
1633
+ seedPeripherals(peripherals) {
1634
+ state.edgePeripherals = [...peripherals];
1635
+ },
1636
+ seedBindings(bindings) {
1637
+ state.edgeBindings.clear();
1638
+ for (const binding of bindings) {
1639
+ state.edgeBindings.set(binding.alias, binding);
1640
+ }
1641
+ },
1642
+ clear() {
1643
+ state.edgePrints = [];
1644
+ state.edgeDisplays = [];
1645
+ state.edgeTestPrints = [];
1646
+ state.edgePrintCounter = 0;
1647
+ state.edgeDevices = [];
1648
+ state.edgePeripherals = [];
1649
+ state.edgeBindings.clear();
1650
+ },
1651
+ get count() {
1652
+ return state.edgePrints.length + state.edgeDisplays.length + state.edgeTestPrints.length;
1653
+ }
1654
+ };
1655
+ }
1656
+
1432
1657
  // src/simulator/router.ts
1433
1658
  var fetchHolder = globalSingleton("fetch-holder", () => ({
1434
1659
  originalFetch: null
@@ -1449,7 +1674,8 @@ function requiresDeploymentHmac(request, url) {
1449
1674
  const messagingMatch = url.pathname.match(
1450
1675
  /^\/api\/deployments\/[^/]+\/integrations\/(slack|line|facebook)(\/.*)?$/
1451
1676
  );
1452
- return !!(dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch);
1677
+ const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
1678
+ return !!(dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
1453
1679
  }
1454
1680
  async function handleSimulatedRequest(request, url) {
1455
1681
  if (url.pathname === "/sql") {
@@ -1466,6 +1692,7 @@ async function handleSimulatedRequest(request, url) {
1466
1692
  const messagingMatch = url.pathname.match(
1467
1693
  /^\/api\/deployments\/[^/]+\/integrations\/(slack|line|facebook)(\/.*)?$/
1468
1694
  );
1695
+ const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
1469
1696
  const isStorageHost = url.hostname === STORAGE_TEST_HOST;
1470
1697
  if (requiresDeploymentHmac(request, url)) {
1471
1698
  const authHeader = request.headers.get("X-Stardeck-Auth");
@@ -1493,6 +1720,9 @@ async function handleSimulatedRequest(request, url) {
1493
1720
  const channel = messagingMatch[1];
1494
1721
  return handleMessagingRequest(request, channel, messagingMatch[2] ?? "");
1495
1722
  }
1723
+ if (edgeMatch) {
1724
+ return handleEdgeRequest(request, edgeMatch[1] ?? "");
1725
+ }
1496
1726
  if (dataStoreMatch) {
1497
1727
  const subPath = dataStoreMatch[1] ?? "";
1498
1728
  const db = requireDb();
@@ -1514,7 +1744,7 @@ async function handleSimulatedRequest(request, url) {
1514
1744
  }
1515
1745
  }
1516
1746
  return failure(
1517
- `[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, auth verify/refresh, Neon /sql.`,
1747
+ `[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, auth verify/refresh, Neon /sql.`,
1518
1748
  404
1519
1749
  );
1520
1750
  }
@@ -1603,6 +1833,7 @@ async function createTestApp(options = {}) {
1603
1833
  const payments = createPayments();
1604
1834
  const storage = createStorage();
1605
1835
  const messages = createMessages();
1836
+ const edge = createEdge();
1606
1837
  const app = {
1607
1838
  db,
1608
1839
  inbox,
@@ -1610,6 +1841,7 @@ async function createTestApp(options = {}) {
1610
1841
  payments,
1611
1842
  storage,
1612
1843
  messages,
1844
+ edge,
1613
1845
  async query(sql, params = []) {
1614
1846
  const result = await db.query(sql, params);
1615
1847
  return result.rows;
@@ -1645,6 +1877,7 @@ async function createTestApp(options = {}) {
1645
1877
  payments.clear();
1646
1878
  storage.clear();
1647
1879
  messages.clear();
1880
+ edge.clear();
1648
1881
  },
1649
1882
  async close() {
1650
1883
  state.db = null;
@@ -1658,6 +1891,7 @@ async function createTestApp(options = {}) {
1658
1891
  payments.clear();
1659
1892
  storage.clear();
1660
1893
  messages.clear();
1894
+ edge.clear();
1661
1895
  uninstallFetchRouter();
1662
1896
  await db.close();
1663
1897
  }
@@ -56,6 +56,13 @@ var state = globalSingleton("state", () => ({
56
56
  storageFiles: /* @__PURE__ */ new Map(),
57
57
  presignPending: /* @__PURE__ */ new Map(),
58
58
  messages: [],
59
+ edgePrints: [],
60
+ edgeDisplays: [],
61
+ edgeTestPrints: [],
62
+ edgePrintCounter: 0,
63
+ edgeDevices: [],
64
+ edgePeripherals: [],
65
+ edgeBindings: /* @__PURE__ */ new Map(),
59
66
  allowNetwork: false
60
67
  }));
61
68
 
@@ -29,6 +29,13 @@ var state = globalSingleton("state", () => ({
29
29
  storageFiles: /* @__PURE__ */ new Map(),
30
30
  presignPending: /* @__PURE__ */ new Map(),
31
31
  messages: [],
32
+ edgePrints: [],
33
+ edgeDisplays: [],
34
+ edgeTestPrints: [],
35
+ edgePrintCounter: 0,
36
+ edgeDevices: [],
37
+ edgePeripherals: [],
38
+ edgeBindings: /* @__PURE__ */ new Map(),
32
39
  allowNetwork: false
33
40
  }));
34
41
 
package/dist/setup.js CHANGED
@@ -50,6 +50,13 @@ var state = globalSingleton("state", () => ({
50
50
  storageFiles: /* @__PURE__ */ new Map(),
51
51
  presignPending: /* @__PURE__ */ new Map(),
52
52
  messages: [],
53
+ edgePrints: [],
54
+ edgeDisplays: [],
55
+ edgeTestPrints: [],
56
+ edgePrintCounter: 0,
57
+ edgeDevices: [],
58
+ edgePeripherals: [],
59
+ edgeBindings: /* @__PURE__ */ new Map(),
53
60
  allowNetwork: false
54
61
  }));
55
62
  function requireDb() {
@@ -104,8 +111,8 @@ function verifyDeploymentAuthHeader(secret, header) {
104
111
  return null;
105
112
  }
106
113
  if (payload.type !== "deployment-request") return null;
107
- const now2 = Math.floor(Date.now() / 1e3);
108
- if (Math.abs(now2 - payload.timestamp) > TIMESTAMP_TOLERANCE_SECONDS) return null;
114
+ const now3 = Math.floor(Date.now() / 1e3);
115
+ if (Math.abs(now3 - payload.timestamp) > TIMESTAMP_TOLERANCE_SECONDS) return null;
109
116
  return payload;
110
117
  }
111
118
 
@@ -1159,6 +1166,178 @@ async function handleMessagingRequest(request, channel, subPath) {
1159
1166
  return failure(`No messaging simulator for ${method} .../integrations/${channel}${subPath}`, 404);
1160
1167
  }
1161
1168
 
1169
+ // src/simulator/edge.ts
1170
+ function edgeFailure(error, status = 400, code) {
1171
+ return json({ success: false, error, ...code ? { code } : {} }, status);
1172
+ }
1173
+ function bindingNotFound(alias) {
1174
+ return edgeFailure(`No peripheral is paired to alias "${alias}"`, 404, "BINDING_NOT_FOUND");
1175
+ }
1176
+ function now2() {
1177
+ return (/* @__PURE__ */ new Date()).toISOString();
1178
+ }
1179
+ function nextJobId() {
1180
+ state.edgePrintCounter += 1;
1181
+ return `job_${state.edgePrintCounter}`;
1182
+ }
1183
+ function nextConfigVersion() {
1184
+ return state.edgeDisplays.length + 1;
1185
+ }
1186
+ function findPeripheral(id) {
1187
+ return state.edgePeripherals.find((p) => p.id === id);
1188
+ }
1189
+ function buildBinding(alias, peripheralId) {
1190
+ const peripheral = findPeripheral(peripheralId);
1191
+ return {
1192
+ alias,
1193
+ state: peripheral ? "ok" : "peripheral_missing",
1194
+ peripheral: peripheral ? {
1195
+ id: peripheral.id,
1196
+ displayName: peripheral.displayName,
1197
+ driver: peripheral.driver,
1198
+ connected: peripheral.connected
1199
+ } : null,
1200
+ device: peripheral ? {
1201
+ id: peripheral.device.id,
1202
+ displayName: peripheral.device.displayName,
1203
+ status: peripheral.device.status
1204
+ } : null,
1205
+ updatedAt: now2()
1206
+ };
1207
+ }
1208
+ function handleListDevices() {
1209
+ return success({ devices: [...state.edgeDevices] });
1210
+ }
1211
+ function handleListPeripherals(request) {
1212
+ const deviceId = new URL(request.url).searchParams.get("deviceId");
1213
+ const peripherals = deviceId ? state.edgePeripherals.filter((p) => p.device.id === deviceId) : [...state.edgePeripherals];
1214
+ return success({ peripherals });
1215
+ }
1216
+ function handleListBindings() {
1217
+ return success({ bindings: [...state.edgeBindings.values()] });
1218
+ }
1219
+ function handleGetBinding(alias) {
1220
+ const binding = state.edgeBindings.get(alias);
1221
+ if (!binding) return bindingNotFound(alias);
1222
+ return success({ binding });
1223
+ }
1224
+ async function handlePair(request) {
1225
+ const body = await readJsonBody(request);
1226
+ const alias = String(body.alias ?? "");
1227
+ const peripheralId = String(body.peripheralId ?? "");
1228
+ if (!alias) return edgeFailure("alias is required");
1229
+ if (!peripheralId) return edgeFailure("peripheralId is required");
1230
+ if (!findPeripheral(peripheralId)) {
1231
+ return edgeFailure("Peripheral not found or its device is not granted to this project", 404);
1232
+ }
1233
+ const binding = buildBinding(alias, peripheralId);
1234
+ state.edgeBindings.set(alias, binding);
1235
+ return success({ binding });
1236
+ }
1237
+ function handleUnpair(alias) {
1238
+ const existed = state.edgeBindings.delete(alias);
1239
+ if (!existed) return bindingNotFound(alias);
1240
+ return success({ deleted: true });
1241
+ }
1242
+ async function handlePrint(request) {
1243
+ const body = await readJsonBody(request);
1244
+ const jobId = nextJobId();
1245
+ const captured = {
1246
+ jobId,
1247
+ deploymentId: String(body.deploymentId ?? ""),
1248
+ alias: body.alias ? String(body.alias) : void 0,
1249
+ deviceId: body.deviceId ? String(body.deviceId) : void 0,
1250
+ peripheralId: body.peripheralId ? String(body.peripheralId) : void 0,
1251
+ receipt: body.receipt ?? {},
1252
+ openDrawer: body.openDrawer === true,
1253
+ logo: body.logo === true ? true : body.logo === false ? false : void 0,
1254
+ copies: typeof body.copies === "number" ? body.copies : 1
1255
+ };
1256
+ state.edgePrints.push(captured);
1257
+ return success({
1258
+ jobId,
1259
+ status: "completed"
1260
+ });
1261
+ }
1262
+ async function handleShowDisplay(request) {
1263
+ const body = await readJsonBody(request);
1264
+ const captured = {
1265
+ action: "show",
1266
+ alias: body.alias ? String(body.alias) : void 0,
1267
+ peripheralId: body.peripheralId ? String(body.peripheralId) : void 0,
1268
+ url: body.url ? String(body.url) : void 0
1269
+ };
1270
+ state.edgeDisplays.push(captured);
1271
+ return success({
1272
+ configVersion: nextConfigVersion(),
1273
+ pushed: true,
1274
+ state: "showing"
1275
+ });
1276
+ }
1277
+ function handleClearDisplay(request) {
1278
+ const url = new URL(request.url);
1279
+ const alias = url.searchParams.get("alias");
1280
+ const peripheralId = url.searchParams.get("peripheralId");
1281
+ const captured = {
1282
+ action: "clear",
1283
+ alias: alias ?? void 0,
1284
+ peripheralId: peripheralId ?? void 0
1285
+ };
1286
+ state.edgeDisplays.push(captured);
1287
+ return success({
1288
+ configVersion: nextConfigVersion(),
1289
+ pushed: true,
1290
+ state: "cleared"
1291
+ });
1292
+ }
1293
+ async function handleTestPrint(request) {
1294
+ const body = await readJsonBody(request);
1295
+ const captured = {
1296
+ alias: body.alias ? String(body.alias) : void 0,
1297
+ deviceId: body.deviceId ? String(body.deviceId) : void 0,
1298
+ peripheralId: body.peripheralId ? String(body.peripheralId) : void 0
1299
+ };
1300
+ state.edgeTestPrints.push(captured);
1301
+ return success({
1302
+ status: "ok",
1303
+ peripheralId: captured.peripheralId ?? captured.alias ?? "default"
1304
+ });
1305
+ }
1306
+ async function handleEdgeRequest(request, subPath) {
1307
+ const method = request.method;
1308
+ if (subPath === "/print" && method === "POST") {
1309
+ return handlePrint(request);
1310
+ }
1311
+ if (subPath === "/devices" && method === "GET") {
1312
+ return handleListDevices();
1313
+ }
1314
+ if (subPath === "/peripherals" && method === "GET") {
1315
+ return handleListPeripherals(request);
1316
+ }
1317
+ if (subPath === "/bindings" && method === "GET") {
1318
+ return handleListBindings();
1319
+ }
1320
+ if (subPath === "/bindings" && method === "PUT") {
1321
+ return handlePair(request);
1322
+ }
1323
+ const bindingMatch = subPath.match(/^\/bindings\/([^/]+)$/);
1324
+ if (bindingMatch) {
1325
+ const alias = decodeURIComponent(bindingMatch[1]);
1326
+ if (method === "GET") return handleGetBinding(alias);
1327
+ if (method === "DELETE") return handleUnpair(alias);
1328
+ }
1329
+ if (subPath === "/display" && method === "POST") {
1330
+ return handleShowDisplay(request);
1331
+ }
1332
+ if (subPath === "/display" && method === "DELETE") {
1333
+ return handleClearDisplay(request);
1334
+ }
1335
+ if (subPath === "/test-print" && method === "POST") {
1336
+ return handleTestPrint(request);
1337
+ }
1338
+ return edgeFailure(`No edge simulator for ${method} .../edge${subPath}`, 404);
1339
+ }
1340
+
1162
1341
  // src/simulator/router.ts
1163
1342
  var fetchHolder = globalSingleton("fetch-holder", () => ({
1164
1343
  originalFetch: null
@@ -1179,7 +1358,8 @@ function requiresDeploymentHmac(request, url) {
1179
1358
  const messagingMatch = url.pathname.match(
1180
1359
  /^\/api\/deployments\/[^/]+\/integrations\/(slack|line|facebook)(\/.*)?$/
1181
1360
  );
1182
- return !!(dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch);
1361
+ const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
1362
+ return !!(dataStoreMatch || isEmail || identitiesMatch || storeMatch || messagingMatch || edgeMatch);
1183
1363
  }
1184
1364
  async function handleSimulatedRequest(request, url) {
1185
1365
  if (url.pathname === "/sql") {
@@ -1196,6 +1376,7 @@ async function handleSimulatedRequest(request, url) {
1196
1376
  const messagingMatch = url.pathname.match(
1197
1377
  /^\/api\/deployments\/[^/]+\/integrations\/(slack|line|facebook)(\/.*)?$/
1198
1378
  );
1379
+ const edgeMatch = url.pathname.match(/^\/api\/deployments\/[^/]+\/edge(\/.*)?$/);
1199
1380
  const isStorageHost = url.hostname === STORAGE_TEST_HOST;
1200
1381
  if (requiresDeploymentHmac(request, url)) {
1201
1382
  const authHeader = request.headers.get("X-Stardeck-Auth");
@@ -1223,6 +1404,9 @@ async function handleSimulatedRequest(request, url) {
1223
1404
  const channel = messagingMatch[1];
1224
1405
  return handleMessagingRequest(request, channel, messagingMatch[2] ?? "");
1225
1406
  }
1407
+ if (edgeMatch) {
1408
+ return handleEdgeRequest(request, edgeMatch[1] ?? "");
1409
+ }
1226
1410
  if (dataStoreMatch) {
1227
1411
  const subPath = dataStoreMatch[1] ?? "";
1228
1412
  const db = requireDb();
@@ -1244,7 +1428,7 @@ async function handleSimulatedRequest(request, url) {
1244
1428
  }
1245
1429
  }
1246
1430
  return failure(
1247
- `[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, auth verify/refresh, Neon /sql.`,
1431
+ `[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, auth verify/refresh, Neon /sql.`,
1248
1432
  404
1249
1433
  );
1250
1434
  }