@lunora/do 1.0.0-alpha.23 → 1.0.0-alpha.25
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/LICENSE.md +6 -0
- package/dist/index.d.mts +40 -80
- package/dist/index.d.ts +40 -80
- package/dist/index.mjs +10 -10
- package/dist/packem_shared/{ADMIN_FUNCTIONS-BbQdj8h1.mjs → ADMIN_FUNCTIONS-Bxdijn66.mjs} +7 -5
- package/dist/packem_shared/{MAX_SQL_ROWS-dDcFE1YZ.mjs → MAX_SQL_ROWS-D57CJaT9.mjs} +3 -1
- package/dist/packem_shared/{NotUniqueError-D1U5SBFR.mjs → NotUniqueError-Dmf-HNdQ.mjs} +60 -7
- package/dist/packem_shared/{RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs → RLS_UNWRAP_SYMBOL-G1eNK4DQ.mjs} +8 -0
- package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-BM4TOOvf.mjs → ROOT_DO_SIZE_WARN_BYTES-CpURtawE.mjs} +79 -133
- package/dist/packem_shared/{SESSION_DO_TTL_DEFAULT-ilPZsVwu.mjs → SESSION_DO_TTL_DEFAULT-D71QAL5h.mjs} +15 -17
- package/dist/packem_shared/{SHARD_REGISTRY_DO_NAME-BsAbi5Mn.mjs → SHARD_REGISTRY_DO_NAME-D99roc-r.mjs} +12 -14
- package/dist/packem_shared/{armRestore-BJk53Ro8.mjs → armRestore-4Px61hHS.mjs} +4 -10
- package/dist/packem_shared/{exportShardRows-DZEhUeyI.mjs → exportShardRows-Dy3oFZ26.mjs} +4 -3
- package/dist/packem_shared/json-response-BdbtpOhm.mjs +3 -0
- package/dist/packem_shared/{serveRelationFanout-BhZF9AuB.mjs → serveRelationFanout-C56hKu1O.mjs} +4 -7
- package/package.json +2 -2
|
@@ -1,20 +1,21 @@
|
|
|
1
1
|
import { LunoraError, toErrorBody } from '@lunora/errors';
|
|
2
2
|
import { drizzle } from 'drizzle-orm/durable-sqlite';
|
|
3
|
+
import { j as jsonResponse } from './json-response-BdbtpOhm.mjs';
|
|
3
4
|
import { e as encodeWire, a as awaitWsDrain, t as trySendFrame, d as decodeWire, s as subscriptionListDeltas, b as sendDeltaFrames } from './subscription-delivery-CK8qga-k.mjs';
|
|
4
|
-
import { parseExportShardArgs, parseImportShardArgs } from './exportShardRows-
|
|
5
|
+
import { parseExportShardArgs, parseImportShardArgs } from './exportShardRows-Dy3oFZ26.mjs';
|
|
5
6
|
import { recordAuthEvent, readAuthMetrics } from './AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs';
|
|
6
7
|
import { DATA_MIGRATION_STATE_TABLE, readMigrationStatus } from './DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs';
|
|
7
8
|
import { SCAN_DEP, createDependencyTracker, tableFromDepKey } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
8
9
|
import { readFunctionMetricsTotals, readFunctionMetricIndexHits, recordFunctionMetric, mergeScanAttribution, readFunctionMetrics, readFunctionMetricBuckets } from './FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
9
|
-
import { createFanoutCounters, ADMIN_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, selectMatchingIds, ADMIN_FUNCTIONS, findStorageReferences, listTables, summarizeSubscriptions, summarizeFanoutTopics, readTablePage, facetColumn, FLAGS_FUNCTION_PREFIX, recordFanoutPass, MAX_PAGE_SIZE } from './ADMIN_FUNCTIONS-
|
|
10
|
+
import { createFanoutCounters, ADMIN_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, selectMatchingIds, ADMIN_FUNCTIONS, findStorageReferences, listTables, summarizeSubscriptions, summarizeFanoutTopics, readTablePage, facetColumn, FLAGS_FUNCTION_PREFIX, recordFanoutPass, MAX_PAGE_SIZE } from './ADMIN_FUNCTIONS-Bxdijn66.mjs';
|
|
10
11
|
import { LogBuffer } from './LogBuffer-B_Ezju_N.mjs';
|
|
11
12
|
import { recordCapturedMail, clearCapturedMail, readCapturedMail, MAIL_TABLE } from './MAIL_RETENTION-CPpgl-dX.mjs';
|
|
12
|
-
import { readBookmark, armRestore } from './armRestore-
|
|
13
|
+
import { readBookmark, armRestore } from './armRestore-4Px61hHS.mjs';
|
|
13
14
|
import { ReactiveCache, reactiveCacheKey } from './ReactiveCache-BYlSGY0N.mjs';
|
|
14
15
|
import { stableStringify } from './stableStringify-MydiuScU.mjs';
|
|
15
16
|
import { redact, standardRules } from '@visulima/redact';
|
|
16
17
|
import { i as isDevEnvironment, c as buildSettings, b as buildSecurityAudit } from './security-audit-CucgBice.mjs';
|
|
17
|
-
import { runReadonlySql } from './MAX_SQL_ROWS-
|
|
18
|
+
import { runReadonlySql } from './MAX_SQL_ROWS-D57CJaT9.mjs';
|
|
18
19
|
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
19
20
|
import { e as deleteGlobalShapeSnapshotsForConnection, g as readIdempotent, h as writeIdempotent, t as trimIdempotent, r as readClientWatermark, m as migrateClientWatermark, c as advanceClientWatermark, d as deleteGlobalShapeSnapshot, f as readGlobalShapeSnapshot, w as writeGlobalShapeSnapshot } from './ctx-db-idempotency-BdcNpvY4.mjs';
|
|
20
21
|
import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
@@ -764,7 +765,8 @@ class OwnerRelay extends RelayLink {
|
|
|
764
765
|
try {
|
|
765
766
|
resolved = this.host.resolveShape(request.name, request.args, identity);
|
|
766
767
|
} catch (error) {
|
|
767
|
-
|
|
768
|
+
const { body } = toErrorBody(error, { fallbackCode: "SHAPE_RESOLVE_FAILED", redactedMessage: "shape resolution failed" });
|
|
769
|
+
return { error: { code: body.code, message: body.message } };
|
|
768
770
|
}
|
|
769
771
|
if (resolved === void 0 || resolved.global === true) {
|
|
770
772
|
return { error: { code: "SHAPE_NOT_FOUND", message: `shape not relayable: ${request.name}` } };
|
|
@@ -1402,7 +1404,7 @@ const setsIntersect = (a, b) => {
|
|
|
1402
1404
|
const parseRunMigrationArgs = (args) => {
|
|
1403
1405
|
const id = typeof args["id"] === "string" ? args["id"] : "";
|
|
1404
1406
|
if (id.trim() === "") {
|
|
1405
|
-
throw
|
|
1407
|
+
throw new LunoraError("MIGRATION_ID_REQUIRED", "runMigration: `id` is required", { status: 400 });
|
|
1406
1408
|
}
|
|
1407
1409
|
return {
|
|
1408
1410
|
batchSize: typeof args["batchSize"] === "number" ? args["batchSize"] : void 0,
|
|
@@ -1417,25 +1419,25 @@ const parseWriteRowArgs = (args) => {
|
|
|
1417
1419
|
const { op } = args;
|
|
1418
1420
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|
|
1419
1421
|
if (op !== "insert" && op !== "patch" && op !== "replace" && op !== "delete") {
|
|
1420
|
-
throw
|
|
1422
|
+
throw new LunoraError("BAD_REQUEST", "writeRow: `op` must be insert|patch|replace|delete");
|
|
1421
1423
|
}
|
|
1422
1424
|
if (table.trim() === "") {
|
|
1423
|
-
throw
|
|
1425
|
+
throw new LunoraError("BAD_REQUEST", "writeRow: `table` is required");
|
|
1424
1426
|
}
|
|
1425
1427
|
const id = typeof args["id"] === "string" ? args["id"] : void 0;
|
|
1426
1428
|
const record = typeof args["doc"] === "object" && args["doc"] !== null && !Array.isArray(args["doc"]) ? args["doc"] : void 0;
|
|
1427
1429
|
if (op !== "insert" && (id === void 0 || id === "")) {
|
|
1428
|
-
throw
|
|
1430
|
+
throw new LunoraError("BAD_REQUEST", `writeRow: \`id\` is required for op "${op}"`);
|
|
1429
1431
|
}
|
|
1430
1432
|
if (op !== "delete" && record === void 0) {
|
|
1431
|
-
throw
|
|
1433
|
+
throw new LunoraError("BAD_REQUEST", `writeRow: \`doc\` is required for op "${op}"`);
|
|
1432
1434
|
}
|
|
1433
1435
|
return { doc: record, id, op, table };
|
|
1434
1436
|
};
|
|
1435
1437
|
const parseCreateWorkflowInstanceArgs = (args) => {
|
|
1436
1438
|
const exportName = typeof args["exportName"] === "string" ? args["exportName"].trim() : "";
|
|
1437
1439
|
if (exportName === "") {
|
|
1438
|
-
throw
|
|
1440
|
+
throw new LunoraError("BAD_REQUEST", "createWorkflowInstance: `exportName` is required");
|
|
1439
1441
|
}
|
|
1440
1442
|
const id = typeof args["id"] === "string" && args["id"] !== "" ? args["id"] : void 0;
|
|
1441
1443
|
return { exportName, id, params: args["params"] };
|
|
@@ -1444,10 +1446,10 @@ const parseGetWorkflowInstanceStatusArgs = (args) => {
|
|
|
1444
1446
|
const exportName = typeof args["exportName"] === "string" ? args["exportName"].trim() : "";
|
|
1445
1447
|
const id = typeof args["id"] === "string" ? args["id"].trim() : "";
|
|
1446
1448
|
if (exportName === "") {
|
|
1447
|
-
throw
|
|
1449
|
+
throw new LunoraError("BAD_REQUEST", "getWorkflowInstanceStatus: `exportName` is required");
|
|
1448
1450
|
}
|
|
1449
1451
|
if (id === "") {
|
|
1450
|
-
throw
|
|
1452
|
+
throw new LunoraError("BAD_REQUEST", "getWorkflowInstanceStatus: `id` is required");
|
|
1451
1453
|
}
|
|
1452
1454
|
return { exportName, id };
|
|
1453
1455
|
};
|
|
@@ -1502,7 +1504,7 @@ const parseTablePageOrderBy = (raw) => {
|
|
|
1502
1504
|
const parseBulkDeleteArgs = (args) => {
|
|
1503
1505
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|
|
1504
1506
|
if (table.trim() === "") {
|
|
1505
|
-
throw
|
|
1507
|
+
throw new LunoraError("BAD_REQUEST", "deleteRows: `table` is required");
|
|
1506
1508
|
}
|
|
1507
1509
|
return {
|
|
1508
1510
|
filters: parseTablePageFilters(args["filters"]),
|
|
@@ -1514,31 +1516,27 @@ const parseBulkDeleteArgs = (args) => {
|
|
|
1514
1516
|
const parseClearTableArgs = (args) => {
|
|
1515
1517
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|
|
1516
1518
|
if (table.trim() === "") {
|
|
1517
|
-
throw
|
|
1519
|
+
throw new LunoraError("BAD_REQUEST", "clearTable: `table` is required");
|
|
1518
1520
|
}
|
|
1519
1521
|
return { limit: typeof args["limit"] === "number" ? args["limit"] : void 0, table };
|
|
1520
1522
|
};
|
|
1521
1523
|
const parseRecordAuthEventArgs = (args) => {
|
|
1522
1524
|
const { outcome } = args;
|
|
1523
1525
|
if (outcome !== "ok" && outcome !== "fail") {
|
|
1524
|
-
throw
|
|
1526
|
+
throw new LunoraError("BAD_REQUEST", 'recordAuthEvent: `outcome` must be "ok" or "fail"');
|
|
1525
1527
|
}
|
|
1526
1528
|
return { outcome };
|
|
1527
1529
|
};
|
|
1528
1530
|
const parseRecordContainerEventArgs = (args) => {
|
|
1529
1531
|
const raw = args["event"];
|
|
1530
1532
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
1531
|
-
throw
|
|
1533
|
+
throw new LunoraError("BAD_REQUEST", "recordContainerEvent: `event` must be an object");
|
|
1532
1534
|
}
|
|
1533
1535
|
const envelope = raw;
|
|
1534
1536
|
const container = typeof envelope["container"] === "string" ? envelope["container"] : "";
|
|
1535
1537
|
const event = typeof envelope["event"] === "string" ? envelope["event"] : "";
|
|
1536
1538
|
if (container.trim() === "" || event.trim() === "") {
|
|
1537
|
-
throw
|
|
1538
|
-
code: "BAD_REQUEST",
|
|
1539
|
-
name: "LunoraError",
|
|
1540
|
-
status: 400
|
|
1541
|
-
});
|
|
1539
|
+
throw new LunoraError("BAD_REQUEST", "recordContainerEvent: `event.container` and `event.event` are required");
|
|
1542
1540
|
}
|
|
1543
1541
|
const level = envelope["level"] === "error" ? "error" : "info";
|
|
1544
1542
|
const detail = typeof envelope["message"] === "string" ? envelope["message"] : void 0;
|
|
@@ -1554,21 +1552,21 @@ const parseRunAsArgs = (args) => {
|
|
|
1554
1552
|
const functionPath = typeof args["functionPath"] === "string" ? args["functionPath"] : "";
|
|
1555
1553
|
const userId = typeof args["userId"] === "string" ? args["userId"] : "";
|
|
1556
1554
|
if (functionPath.trim() === "") {
|
|
1557
|
-
throw
|
|
1555
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `functionPath` is required");
|
|
1558
1556
|
}
|
|
1559
1557
|
if (functionPath.startsWith(ADMIN_FUNCTION_PREFIX)) {
|
|
1560
|
-
throw
|
|
1558
|
+
throw new LunoraError("BAD_REQUEST", "runAs: cannot target a reserved admin function");
|
|
1561
1559
|
}
|
|
1562
1560
|
if (userId.trim() === "") {
|
|
1563
|
-
throw
|
|
1561
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `userId` is required");
|
|
1564
1562
|
}
|
|
1565
1563
|
const rawArgs = args["args"];
|
|
1566
1564
|
if (rawArgs !== void 0 && (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs))) {
|
|
1567
|
-
throw
|
|
1565
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `args` must be an object");
|
|
1568
1566
|
}
|
|
1569
1567
|
const rawIdentity = args["identity"];
|
|
1570
1568
|
if (rawIdentity !== void 0 && (typeof rawIdentity !== "object" || rawIdentity === null || Array.isArray(rawIdentity))) {
|
|
1571
|
-
throw
|
|
1569
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `identity` must be an object");
|
|
1572
1570
|
}
|
|
1573
1571
|
return {
|
|
1574
1572
|
args: rawArgs === void 0 ? {} : rawArgs,
|
|
@@ -1579,7 +1577,7 @@ const parseRunAsArgs = (args) => {
|
|
|
1579
1577
|
};
|
|
1580
1578
|
const parseRecordMailArgs = (args) => {
|
|
1581
1579
|
const bad = (message) => {
|
|
1582
|
-
throw
|
|
1580
|
+
throw new LunoraError("BAD_REQUEST", `recordMail: ${message}`);
|
|
1583
1581
|
};
|
|
1584
1582
|
const { bcc, cc, from, headers, html, replyTo, subject, text, to } = args;
|
|
1585
1583
|
if (typeof subject !== "string") {
|
|
@@ -1620,7 +1618,7 @@ const TEST_MAIL_DEFAULT_TO = "test@lunora.sh";
|
|
|
1620
1618
|
const buildTestMailInput = (args) => {
|
|
1621
1619
|
const { to } = args;
|
|
1622
1620
|
if (to !== void 0 && typeof to !== "string") {
|
|
1623
|
-
throw
|
|
1621
|
+
throw new LunoraError("BAD_REQUEST", "sendTestMail: `to` must be a string");
|
|
1624
1622
|
}
|
|
1625
1623
|
const recipient = to ?? TEST_MAIL_DEFAULT_TO;
|
|
1626
1624
|
const link = "https://example.test/verify?token=demo";
|
|
@@ -1636,7 +1634,7 @@ Verify your email: ${link}`,
|
|
|
1636
1634
|
};
|
|
1637
1635
|
const parseRecordQueueMessageArgs = (args) => {
|
|
1638
1636
|
const bad = (message) => {
|
|
1639
|
-
throw
|
|
1637
|
+
throw new LunoraError("BAD_REQUEST", `recordQueueMessage: ${message}`);
|
|
1640
1638
|
};
|
|
1641
1639
|
const raw = args["messages"];
|
|
1642
1640
|
if (!Array.isArray(raw)) {
|
|
@@ -1678,23 +1676,15 @@ const MAX_QUEUE_SEND_BATCH = 100;
|
|
|
1678
1676
|
const parseSendQueueMessageArgs = (args) => {
|
|
1679
1677
|
const exportName = typeof args["exportName"] === "string" ? args["exportName"].trim() : "";
|
|
1680
1678
|
if (exportName === "") {
|
|
1681
|
-
throw
|
|
1679
|
+
throw new LunoraError("BAD_REQUEST", "sendQueueMessage: `exportName` is required");
|
|
1682
1680
|
}
|
|
1683
1681
|
const delayRaw = args["delaySeconds"];
|
|
1684
1682
|
if (delayRaw !== void 0 && (typeof delayRaw !== "number" || !Number.isFinite(delayRaw) || delayRaw < 0)) {
|
|
1685
|
-
throw
|
|
1686
|
-
code: "BAD_REQUEST",
|
|
1687
|
-
name: "LunoraError",
|
|
1688
|
-
status: 400
|
|
1689
|
-
});
|
|
1683
|
+
throw new LunoraError("BAD_REQUEST", "sendQueueMessage: `delaySeconds` must be a non-negative number");
|
|
1690
1684
|
}
|
|
1691
1685
|
const batch = Array.isArray(args["batch"]) ? args["batch"] : void 0;
|
|
1692
1686
|
if (batch !== void 0 && (batch.length === 0 || batch.length > MAX_QUEUE_SEND_BATCH)) {
|
|
1693
|
-
throw
|
|
1694
|
-
code: "BAD_REQUEST",
|
|
1695
|
-
name: "LunoraError",
|
|
1696
|
-
status: 400
|
|
1697
|
-
});
|
|
1687
|
+
throw new LunoraError("BAD_REQUEST", `sendQueueMessage: \`batch\` must contain between 1 and ${String(MAX_QUEUE_SEND_BATCH)} messages`);
|
|
1698
1688
|
}
|
|
1699
1689
|
return {
|
|
1700
1690
|
batch,
|
|
@@ -1707,7 +1697,7 @@ const parseSendQueueMessageArgs = (args) => {
|
|
|
1707
1697
|
const parseReplayQueueMessageArgs = (args) => {
|
|
1708
1698
|
const id = typeof args["id"] === "string" ? args["id"].trim() : "";
|
|
1709
1699
|
if (id === "") {
|
|
1710
|
-
throw
|
|
1700
|
+
throw new LunoraError("BAD_REQUEST", "replayQueueMessage: `id` is required");
|
|
1711
1701
|
}
|
|
1712
1702
|
const target = typeof args["target"] === "string" && args["target"].trim() !== "" ? args["target"].trim() : void 0;
|
|
1713
1703
|
return { id, target };
|
|
@@ -1717,24 +1707,24 @@ const parseRankBeforeArgs = (args) => {
|
|
|
1717
1707
|
const index = typeof args["index"] === "string" ? args["index"] : "";
|
|
1718
1708
|
const rowId = typeof args["rowId"] === "string" ? args["rowId"] : "";
|
|
1719
1709
|
if (table.trim() === "") {
|
|
1720
|
-
throw
|
|
1710
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `table` is required");
|
|
1721
1711
|
}
|
|
1722
1712
|
if (index.trim() === "") {
|
|
1723
|
-
throw
|
|
1713
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `index` is required");
|
|
1724
1714
|
}
|
|
1725
1715
|
if (typeof args["partitionKey"] !== "string") {
|
|
1726
|
-
throw
|
|
1716
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `partitionKey` must be a string");
|
|
1727
1717
|
}
|
|
1728
1718
|
if (rowId.trim() === "") {
|
|
1729
|
-
throw
|
|
1719
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `rowId` is required");
|
|
1730
1720
|
}
|
|
1731
1721
|
if (!Array.isArray(args["sortValues"])) {
|
|
1732
|
-
throw
|
|
1722
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `sortValues` must be an array");
|
|
1733
1723
|
}
|
|
1734
1724
|
return { index, partitionKey: args["partitionKey"], rowId, sortValues: args["sortValues"], table };
|
|
1735
1725
|
};
|
|
1736
1726
|
const badRequest = (message) => {
|
|
1737
|
-
throw
|
|
1727
|
+
throw new LunoraError("BAD_REQUEST", message);
|
|
1738
1728
|
};
|
|
1739
1729
|
const requireNonEmptyString = (value, field) => {
|
|
1740
1730
|
if (typeof value !== "string" || value.trim() === "") {
|
|
@@ -1794,7 +1784,7 @@ const decodeIndexHitKey = (key) => {
|
|
|
1794
1784
|
const parseApplyCdcArgs = (args) => {
|
|
1795
1785
|
const raw = args["changes"];
|
|
1796
1786
|
if (!Array.isArray(raw)) {
|
|
1797
|
-
throw
|
|
1787
|
+
throw new LunoraError("BAD_REQUEST", "applyCdc: `changes` must be an array");
|
|
1798
1788
|
}
|
|
1799
1789
|
const changes = raw.map((entry, index) => {
|
|
1800
1790
|
const record = entry;
|
|
@@ -1802,27 +1792,15 @@ const parseApplyCdcArgs = (args) => {
|
|
|
1802
1792
|
const table = typeof record["table"] === "string" ? record["table"] : "";
|
|
1803
1793
|
const id = typeof record["id"] === "string" ? record["id"] : "";
|
|
1804
1794
|
if (table === "" || id === "" || op !== "insert" && op !== "update" && op !== "delete") {
|
|
1805
|
-
throw
|
|
1806
|
-
code: "BAD_REQUEST",
|
|
1807
|
-
name: "LunoraError",
|
|
1808
|
-
status: 400
|
|
1809
|
-
});
|
|
1795
|
+
throw new LunoraError("BAD_REQUEST", `applyCdc: changes[${String(index)}] must have a table, id, and op of insert|update|delete`);
|
|
1810
1796
|
}
|
|
1811
1797
|
const rawDocument = record["doc"];
|
|
1812
1798
|
if (rawDocument !== void 0 && (typeof rawDocument !== "object" || rawDocument === null || Array.isArray(rawDocument))) {
|
|
1813
|
-
throw
|
|
1814
|
-
code: "BAD_REQUEST",
|
|
1815
|
-
name: "LunoraError",
|
|
1816
|
-
status: 400
|
|
1817
|
-
});
|
|
1799
|
+
throw new LunoraError("BAD_REQUEST", `applyCdc: changes[${String(index)}].doc must be an object`);
|
|
1818
1800
|
}
|
|
1819
1801
|
const document = rawDocument;
|
|
1820
1802
|
if (document !== void 0 && typeof document["_id"] === "string" && document["_id"] !== id) {
|
|
1821
|
-
throw
|
|
1822
|
-
code: "BAD_REQUEST",
|
|
1823
|
-
name: "LunoraError",
|
|
1824
|
-
status: 400
|
|
1825
|
-
});
|
|
1803
|
+
throw new LunoraError("BAD_REQUEST", `applyCdc: changes[${String(index)}].doc._id must match the entry id`);
|
|
1826
1804
|
}
|
|
1827
1805
|
return {
|
|
1828
1806
|
doc: document,
|
|
@@ -1842,13 +1820,7 @@ const parseCdcSyncArgs = (args) => {
|
|
|
1842
1820
|
};
|
|
1843
1821
|
return { limit: toCount(args["limit"]), sinceSeq: toCount(args["sinceSeq"]) ?? 0 };
|
|
1844
1822
|
};
|
|
1845
|
-
const
|
|
1846
|
-
const headers = { "content-type": "application/json" };
|
|
1847
|
-
if (bookmark) {
|
|
1848
|
-
headers["x-d1-bookmark"] = bookmark;
|
|
1849
|
-
}
|
|
1850
|
-
return Response.json(body, { headers, status });
|
|
1851
|
-
};
|
|
1823
|
+
const bookmarkHeaders = (bookmark) => bookmark ? { "x-d1-bookmark": bookmark } : void 0;
|
|
1852
1824
|
const parseIdentityHeader = (raw) => {
|
|
1853
1825
|
if (!raw) {
|
|
1854
1826
|
return void 0;
|
|
@@ -2394,7 +2366,7 @@ class ShardDO {
|
|
|
2394
2366
|
try {
|
|
2395
2367
|
if (payload.functionPath.startsWith(RELATION_FUNCTION_PREFIX)) {
|
|
2396
2368
|
const value = await this.runRelationFanoutRead(payload.functionPath, payload.args ?? {});
|
|
2397
|
-
return jsonResponse(value, 200, this.currentResponseBookmark);
|
|
2369
|
+
return jsonResponse(value, 200, bookmarkHeaders(this.currentResponseBookmark));
|
|
2398
2370
|
}
|
|
2399
2371
|
const mutatorClass = this.isCustomMutator(payload.functionPath) ? this.classifyClientMutation() : void 0;
|
|
2400
2372
|
this.currentMutatorClass = mutatorClass;
|
|
@@ -2684,9 +2656,7 @@ class ShardDO {
|
|
|
2684
2656
|
*/
|
|
2685
2657
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass overrides this with a schema-aware reader that uses `this`
|
|
2686
2658
|
runRelationFanoutRead(_functionPath, _args) {
|
|
2687
|
-
throw
|
|
2688
|
-
code: "NOT_IMPLEMENTED",
|
|
2689
|
-
name: "LunoraError",
|
|
2659
|
+
throw new LunoraError("NOT_IMPLEMENTED", "__lunora_relation__: no schema bound — the base ShardDO cannot serve cross-shard relation reads", {
|
|
2690
2660
|
status: 500
|
|
2691
2661
|
});
|
|
2692
2662
|
}
|
|
@@ -2813,19 +2783,11 @@ class ShardDO {
|
|
|
2813
2783
|
*/
|
|
2814
2784
|
async runInTransaction(handler) {
|
|
2815
2785
|
if (this.transactionDepth > 0) {
|
|
2816
|
-
throw
|
|
2817
|
-
code: "NESTED_TRANSACTION",
|
|
2818
|
-
name: "LunoraError",
|
|
2819
|
-
status: 500
|
|
2820
|
-
});
|
|
2786
|
+
throw new LunoraError("NESTED_TRANSACTION", "nested transactions are not supported in SQLite-in-DO", { status: 500 });
|
|
2821
2787
|
}
|
|
2822
2788
|
const sqlHandle = this.state.storage.sql;
|
|
2823
2789
|
if (!sqlHandle || typeof sqlHandle.exec !== "function") {
|
|
2824
|
-
throw
|
|
2825
|
-
code: "SQL_UNAVAILABLE",
|
|
2826
|
-
name: "LunoraError",
|
|
2827
|
-
status: 500
|
|
2828
|
-
});
|
|
2790
|
+
throw new LunoraError("SQL_UNAVAILABLE", "storage.sql is not available on this ShardDO state", { status: 500 });
|
|
2829
2791
|
}
|
|
2830
2792
|
const transactionalStorage = this.state.storage;
|
|
2831
2793
|
const run = async () => {
|
|
@@ -2905,9 +2867,7 @@ class ShardDO {
|
|
|
2905
2867
|
*/
|
|
2906
2868
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass overrides this and uses `this` to reach the generated migration registry
|
|
2907
2869
|
runShardDataMigration(args) {
|
|
2908
|
-
return Promise.reject(
|
|
2909
|
-
Object.assign(new Error(`data migration "${args.id}" is not registered`), { code: "MIGRATION_NOT_FOUND", name: "LunoraError", status: 404 })
|
|
2910
|
-
);
|
|
2870
|
+
return Promise.reject(new LunoraError("MIGRATION_NOT_FOUND", `data migration "${args.id}" is not registered`, { status: 404 }));
|
|
2911
2871
|
}
|
|
2912
2872
|
/**
|
|
2913
2873
|
* Lazily provision the shard's physical tables before an operation that
|
|
@@ -3165,7 +3125,7 @@ class ShardDO {
|
|
|
3165
3125
|
*/
|
|
3166
3126
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass overrides this and uses `this` to build a schema-aware writer
|
|
3167
3127
|
runShardWrite(args) {
|
|
3168
|
-
return Promise.reject(
|
|
3128
|
+
return Promise.reject(new LunoraError("UNKNOWN_TABLE", `unknown table: ${args.table}`, { status: 404 }));
|
|
3169
3129
|
}
|
|
3170
3130
|
/**
|
|
3171
3131
|
* Delete one row by primary key THROUGH the schema-aware writer — the
|
|
@@ -3180,7 +3140,7 @@ class ShardDO {
|
|
|
3180
3140
|
*/
|
|
3181
3141
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass overrides this and uses `this` to build a schema-aware writer
|
|
3182
3142
|
deleteRowThroughWriter(_table, _id) {
|
|
3183
|
-
return Promise.reject(
|
|
3143
|
+
return Promise.reject(new LunoraError("UNKNOWN_TABLE", `unknown table: ${_table}`, { status: 404 }));
|
|
3184
3144
|
}
|
|
3185
3145
|
/**
|
|
3186
3146
|
* Bulk-delete the rows of `table` matching the active `filters`/`search`
|
|
@@ -3222,9 +3182,7 @@ class ShardDO {
|
|
|
3222
3182
|
*/
|
|
3223
3183
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass overrides this and uses `this` to build a schema-aware writer
|
|
3224
3184
|
runShardRankBefore(_args) {
|
|
3225
|
-
return Promise.reject(
|
|
3226
|
-
Object.assign(new Error("rankBefore is not implemented in base ShardDO"), { code: "NOT_IMPLEMENTED", name: "LunoraError", status: 500 })
|
|
3227
|
-
);
|
|
3185
|
+
return Promise.reject(new LunoraError("NOT_IMPLEMENTED", "rankBefore is not implemented in base ShardDO", { status: 500 }));
|
|
3228
3186
|
}
|
|
3229
3187
|
/**
|
|
3230
3188
|
* Page this shard's local ranked slice under `index`, each row tagged with
|
|
@@ -3238,9 +3196,7 @@ class ShardDO {
|
|
|
3238
3196
|
*/
|
|
3239
3197
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass overrides this and uses `this` to build a schema-aware writer
|
|
3240
3198
|
runShardRankPage(_args) {
|
|
3241
|
-
return Promise.reject(
|
|
3242
|
-
Object.assign(new Error("rankPage is not implemented in base ShardDO"), { code: "NOT_IMPLEMENTED", name: "LunoraError", status: 500 })
|
|
3243
|
-
);
|
|
3199
|
+
return Promise.reject(new LunoraError("NOT_IMPLEMENTED", "rankPage is not implemented in base ShardDO", { status: 500 }));
|
|
3244
3200
|
}
|
|
3245
3201
|
/**
|
|
3246
3202
|
* Page this shard's change-data-capture log past `sinceSeq`. Read-only and
|
|
@@ -3439,7 +3395,7 @@ class ShardDO {
|
|
|
3439
3395
|
}
|
|
3440
3396
|
this.recordFunctionCall(functionPath, Date.now() - dispatchStartedAt, void 0, this.currentScannedTables, this.currentIndexHits);
|
|
3441
3397
|
if (mutatorClass.kind === "already") {
|
|
3442
|
-
return jsonResponse({ lastMutationId: mutatorClass.expected - 1, result: null }, 200, this.currentResponseBookmark);
|
|
3398
|
+
return jsonResponse({ lastMutationId: mutatorClass.expected - 1, result: null }, 200, bookmarkHeaders(this.currentResponseBookmark));
|
|
3443
3399
|
}
|
|
3444
3400
|
return jsonResponse(
|
|
3445
3401
|
{
|
|
@@ -3450,7 +3406,7 @@ class ShardDO {
|
|
|
3450
3406
|
}
|
|
3451
3407
|
},
|
|
3452
3408
|
409,
|
|
3453
|
-
this.currentResponseBookmark
|
|
3409
|
+
bookmarkHeaders(this.currentResponseBookmark)
|
|
3454
3410
|
);
|
|
3455
3411
|
}
|
|
3456
3412
|
/**
|
|
@@ -3469,7 +3425,11 @@ class ShardDO {
|
|
|
3469
3425
|
return this.buildDispatchResponse(mutatorClass, cachedValue);
|
|
3470
3426
|
}
|
|
3471
3427
|
const commitCursor = this.mutationCommitCursor();
|
|
3472
|
-
return jsonResponse(
|
|
3428
|
+
return jsonResponse(
|
|
3429
|
+
commitCursor === void 0 ? { result: cachedValue } : { commitCursor, result: cachedValue },
|
|
3430
|
+
200,
|
|
3431
|
+
bookmarkHeaders(this.currentResponseBookmark)
|
|
3432
|
+
);
|
|
3473
3433
|
}
|
|
3474
3434
|
/**
|
|
3475
3435
|
* The CDC cursor a just-committed plain mutation landed at — the post-write
|
|
@@ -3493,10 +3453,10 @@ class ShardDO {
|
|
|
3493
3453
|
*/
|
|
3494
3454
|
buildDispatchResponse(mutatorClass, result) {
|
|
3495
3455
|
if (mutatorClass?.kind === "next") {
|
|
3496
|
-
return jsonResponse({ lastMutationId: this.currentRequestClientSeq, result }, 200, this.currentResponseBookmark);
|
|
3456
|
+
return jsonResponse({ lastMutationId: this.currentRequestClientSeq, result }, 200, bookmarkHeaders(this.currentResponseBookmark));
|
|
3497
3457
|
}
|
|
3498
3458
|
const commitCursor = this.mutationCommitCursor();
|
|
3499
|
-
return jsonResponse(commitCursor === void 0 ? { result } : { commitCursor, result }, 200, this.currentResponseBookmark);
|
|
3459
|
+
return jsonResponse(commitCursor === void 0 ? { result } : { commitCursor, result }, 200, bookmarkHeaders(this.currentResponseBookmark));
|
|
3500
3460
|
}
|
|
3501
3461
|
/**
|
|
3502
3462
|
* Commit a mutation's replay bookkeeping — the `(identity, mutationId)`
|
|
@@ -3565,9 +3525,7 @@ class ShardDO {
|
|
|
3565
3525
|
*/
|
|
3566
3526
|
// eslint-disable-next-line class-methods-use-this -- base-class override hook: the codegen subclass overrides this and uses `this` to build a schema-aware writer
|
|
3567
3527
|
runShardApplyCdc(_args) {
|
|
3568
|
-
return Promise.reject(
|
|
3569
|
-
Object.assign(new Error("applyCdc is not implemented in base ShardDO"), { code: "NOT_IMPLEMENTED", name: "LunoraError", status: 500 })
|
|
3570
|
-
);
|
|
3528
|
+
return Promise.reject(new LunoraError("NOT_IMPLEMENTED", "applyCdc is not implemented in base ShardDO", { status: 500 }));
|
|
3571
3529
|
}
|
|
3572
3530
|
/**
|
|
3573
3531
|
* Register a subscription on the given socket. Stored via
|
|
@@ -4255,7 +4213,7 @@ class ShardDO {
|
|
|
4255
4213
|
}
|
|
4256
4214
|
results.push({ body: outcome.body, id: outcome.id, status: outcome.status });
|
|
4257
4215
|
}
|
|
4258
|
-
return jsonResponse({ results }, 200, latestBookmark);
|
|
4216
|
+
return jsonResponse({ results }, 200, bookmarkHeaders(latestBookmark));
|
|
4259
4217
|
}
|
|
4260
4218
|
/** Dispatch one batch entry through the single-call `/rpc` path and capture its envelope (plan 088). */
|
|
4261
4219
|
async dispatchBatchEntry(batchRequest, entry) {
|
|
@@ -4263,12 +4221,12 @@ class ShardDO {
|
|
|
4263
4221
|
const response = await this.fetch(buildBatchEntryRequest(batchRequest, entry));
|
|
4264
4222
|
return { body: await response.json(), bookmark: response.headers.get("x-d1-bookmark") ?? void 0, id: entry.id, status: response.status };
|
|
4265
4223
|
} catch (error) {
|
|
4266
|
-
const
|
|
4224
|
+
const { body, status } = toErrorBody(error, { fallbackCode: "BATCH_ENTRY_FAILED" });
|
|
4267
4225
|
return {
|
|
4268
|
-
body: { error:
|
|
4226
|
+
body: { error: body },
|
|
4269
4227
|
bookmark: void 0,
|
|
4270
4228
|
id: entry?.id,
|
|
4271
|
-
status
|
|
4229
|
+
status
|
|
4272
4230
|
};
|
|
4273
4231
|
}
|
|
4274
4232
|
}
|
|
@@ -4477,15 +4435,11 @@ class ShardDO {
|
|
|
4477
4435
|
resolveWorkflowBinding(exportName) {
|
|
4478
4436
|
const metadata = this.workflowsMetadata().workflows.find((workflow) => workflow.exportName === exportName);
|
|
4479
4437
|
if (!metadata) {
|
|
4480
|
-
throw
|
|
4438
|
+
throw new LunoraError("BAD_REQUEST", `workflow "${exportName}" is not declared`);
|
|
4481
4439
|
}
|
|
4482
4440
|
const binding = this.env?.[metadata.binding];
|
|
4483
4441
|
if (typeof binding !== "object" || binding === null || typeof binding.create !== "function" || typeof binding.get !== "function") {
|
|
4484
|
-
throw
|
|
4485
|
-
code: "BAD_REQUEST",
|
|
4486
|
-
name: "LunoraError",
|
|
4487
|
-
status: 400
|
|
4488
|
-
});
|
|
4442
|
+
throw new LunoraError("BAD_REQUEST", `workflow binding "${metadata.binding}" is not available on this deployment`);
|
|
4489
4443
|
}
|
|
4490
4444
|
return binding;
|
|
4491
4445
|
}
|
|
@@ -4665,25 +4619,21 @@ class ShardDO {
|
|
|
4665
4619
|
const parsed = parseReplayQueueMessageArgs(args);
|
|
4666
4620
|
const row = readQueueMessageById(this.state.storage.sql, parsed.id);
|
|
4667
4621
|
if (row === void 0) {
|
|
4668
|
-
throw
|
|
4669
|
-
code: "BAD_REQUEST",
|
|
4670
|
-
name: "LunoraError",
|
|
4671
|
-
status: 404
|
|
4672
|
-
});
|
|
4622
|
+
throw new LunoraError("BAD_REQUEST", `replayQueueMessage: captured message "${parsed.id}" was not found`, { status: 404 });
|
|
4673
4623
|
}
|
|
4674
4624
|
if (isLossyBody(row.body)) {
|
|
4675
|
-
throw
|
|
4676
|
-
|
|
4677
|
-
|
|
4625
|
+
throw new LunoraError(
|
|
4626
|
+
"BAD_REQUEST",
|
|
4627
|
+
`replayQueueMessage: captured message "${parsed.id}" has a truncated or unserializable body and can't be replayed faithfully`,
|
|
4628
|
+
{ status: 422 }
|
|
4678
4629
|
);
|
|
4679
4630
|
}
|
|
4680
4631
|
const target = parsed.target ?? this.resolveReplayTarget(row.queue) ?? row.exportName;
|
|
4681
4632
|
if (typeof target !== "string" || target === "") {
|
|
4682
|
-
throw
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
});
|
|
4633
|
+
throw new LunoraError(
|
|
4634
|
+
"BAD_REQUEST",
|
|
4635
|
+
`replayQueueMessage: captured message "${parsed.id}" has no declared producer to replay onto (pass \`target\`)`
|
|
4636
|
+
);
|
|
4687
4637
|
}
|
|
4688
4638
|
const { binding } = this.resolveQueueBinding(target);
|
|
4689
4639
|
await binding.send(row.body);
|
|
@@ -4701,15 +4651,11 @@ class ShardDO {
|
|
|
4701
4651
|
resolveQueueBinding(exportName) {
|
|
4702
4652
|
const metadata = this.queuesMetadata().queues.find((queue) => queue.exportName === exportName);
|
|
4703
4653
|
if (!metadata) {
|
|
4704
|
-
throw
|
|
4654
|
+
throw new LunoraError("BAD_REQUEST", `queue "${exportName}" is not declared`);
|
|
4705
4655
|
}
|
|
4706
4656
|
const binding = this.env?.[metadata.binding];
|
|
4707
4657
|
if (typeof binding !== "object" || binding === null || typeof binding.send !== "function") {
|
|
4708
|
-
throw
|
|
4709
|
-
code: "BAD_REQUEST",
|
|
4710
|
-
name: "LunoraError",
|
|
4711
|
-
status: 400
|
|
4712
|
-
});
|
|
4658
|
+
throw new LunoraError("BAD_REQUEST", `queue binding "${metadata.binding}" is not available on this deployment`);
|
|
4713
4659
|
}
|
|
4714
4660
|
return { binding, metadata };
|
|
4715
4661
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { j as jsonResponse } from './json-response-BdbtpOhm.mjs';
|
|
2
|
+
|
|
1
3
|
const SESSION_DO_TTL_DEFAULT = 7 * 24 * 60 * 60;
|
|
2
4
|
const SESSION_DO_TTL_MAX = 90 * 24 * 60 * 60;
|
|
3
5
|
const SESSION_GC_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
@@ -7,10 +9,6 @@ const SESSION_TOKEN_PATTERN = /^[\w-]+$/;
|
|
|
7
9
|
const MIN_TOKEN_LENGTH = 32;
|
|
8
10
|
const MAX_TOKEN_LENGTH = 256;
|
|
9
11
|
const MAX_USER_ID_LENGTH = 256;
|
|
10
|
-
const jsonResponse = (status, body) => Response.json(body, {
|
|
11
|
-
headers: { "content-type": "application/json" },
|
|
12
|
-
status
|
|
13
|
-
});
|
|
14
12
|
const constantTimeEqual = (a, b) => {
|
|
15
13
|
const max = Math.max(a.length, b.length);
|
|
16
14
|
let diff = a.length ^ b.length;
|
|
@@ -68,7 +66,7 @@ class SessionDO {
|
|
|
68
66
|
async fetch(request) {
|
|
69
67
|
const env = this.env ?? {};
|
|
70
68
|
if (!isAuthorized(request, env)) {
|
|
71
|
-
return jsonResponse(
|
|
69
|
+
return jsonResponse({ error: { code: "UNAUTHORIZED", message: "missing or invalid SessionDO secret" } }, 401);
|
|
72
70
|
}
|
|
73
71
|
const url = new URL(request.url);
|
|
74
72
|
if (request.method === "POST" && url.pathname === "/create") {
|
|
@@ -80,7 +78,7 @@ class SessionDO {
|
|
|
80
78
|
if (request.method === "DELETE" && url.pathname === "/revoke") {
|
|
81
79
|
return this.handleRevoke(request);
|
|
82
80
|
}
|
|
83
|
-
return jsonResponse(
|
|
81
|
+
return jsonResponse({ error: { code: "NOT_FOUND", message: "no such session route" } }, 404);
|
|
84
82
|
}
|
|
85
83
|
/**
|
|
86
84
|
* Sweep expired session records. Lazy expiry-on-read ({@link handleGet})
|
|
@@ -116,25 +114,25 @@ class SessionDO {
|
|
|
116
114
|
try {
|
|
117
115
|
body = await request.json();
|
|
118
116
|
} catch {
|
|
119
|
-
return jsonResponse(
|
|
117
|
+
return jsonResponse({ error: "invalid_request" }, 400);
|
|
120
118
|
}
|
|
121
119
|
const token = validateToken(body.token);
|
|
122
120
|
if (token === void 0) {
|
|
123
|
-
return jsonResponse(
|
|
121
|
+
return jsonResponse({ error: "invalid_request" }, 400);
|
|
124
122
|
}
|
|
125
123
|
const { userId } = body;
|
|
126
124
|
if (typeof userId !== "string" || userId.length === 0 || userId.length > MAX_USER_ID_LENGTH) {
|
|
127
|
-
return jsonResponse(
|
|
125
|
+
return jsonResponse({ error: "invalid_request" }, 400);
|
|
128
126
|
}
|
|
129
127
|
const ttlSeconds = resolveTtlSeconds(body.ttlSeconds);
|
|
130
128
|
if (ttlSeconds === void 0) {
|
|
131
|
-
return jsonResponse(
|
|
129
|
+
return jsonResponse({ error: "invalid_request" }, 400);
|
|
132
130
|
}
|
|
133
131
|
const now = Date.now();
|
|
134
132
|
const record = { createdAt: now, expiresAt: now + ttlSeconds * 1e3, userId };
|
|
135
133
|
await this.state.storage.put(`s:${token}`, record);
|
|
136
134
|
await this.armGcAlarm();
|
|
137
|
-
return jsonResponse(
|
|
135
|
+
return jsonResponse({ token, ...record }, 201);
|
|
138
136
|
}
|
|
139
137
|
/**
|
|
140
138
|
* Ensure a GC alarm is pending. Only sets one when none is currently
|
|
@@ -155,25 +153,25 @@ class SessionDO {
|
|
|
155
153
|
async handleGet(request) {
|
|
156
154
|
const token = request.headers.get(SESSION_TOKEN_HEADER);
|
|
157
155
|
if (!token) {
|
|
158
|
-
return jsonResponse(
|
|
156
|
+
return jsonResponse({ error: { code: "INVALID_INPUT", message: "token required" } }, 400);
|
|
159
157
|
}
|
|
160
158
|
const record = await this.state.storage.get(`s:${token}`);
|
|
161
159
|
if (!record) {
|
|
162
|
-
return jsonResponse(
|
|
160
|
+
return jsonResponse({ error: { code: "NOT_FOUND", message: "session not found" } }, 404);
|
|
163
161
|
}
|
|
164
162
|
if (record.expiresAt < Date.now()) {
|
|
165
163
|
await this.state.storage.delete(`s:${token}`);
|
|
166
|
-
return jsonResponse(
|
|
164
|
+
return jsonResponse({ error: { code: "EXPIRED", message: "session expired" } }, 404);
|
|
167
165
|
}
|
|
168
|
-
return jsonResponse(
|
|
166
|
+
return jsonResponse({ token, ...record }, 200);
|
|
169
167
|
}
|
|
170
168
|
async handleRevoke(request) {
|
|
171
169
|
const token = request.headers.get(SESSION_TOKEN_HEADER);
|
|
172
170
|
if (!token) {
|
|
173
|
-
return jsonResponse(
|
|
171
|
+
return jsonResponse({ error: { code: "INVALID_INPUT", message: "token required" } }, 400);
|
|
174
172
|
}
|
|
175
173
|
await this.state.storage.delete(`s:${token}`);
|
|
176
|
-
return jsonResponse(
|
|
174
|
+
return jsonResponse({ ok: true }, 200);
|
|
177
175
|
}
|
|
178
176
|
}
|
|
179
177
|
|