@lunora/do 1.0.0-alpha.24 → 1.0.0-alpha.26
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.d.mts +40 -7
- package/dist/index.d.ts +40 -7
- package/dist/index.mjs +10 -10
- package/dist/packem_shared/{ADMIN_FUNCTIONS-BbQdj8h1.mjs → ADMIN_FUNCTIONS-Bxdijn66.mjs} +7 -5
- package/dist/packem_shared/{DEFAULT_MAX_RELATION_KEYS-CjM9Y1_G.mjs → DEFAULT_MAX_RELATION_KEYS-BEan1CRD.mjs} +1 -1
- package/dist/packem_shared/{MAX_SQL_ROWS-dDcFE1YZ.mjs → MAX_SQL_ROWS-D57CJaT9.mjs} +3 -1
- package/dist/packem_shared/{NotUniqueError-D1U5SBFR.mjs → NotUniqueError-BdDLev9w.mjs} +63 -10
- 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-KQQiPDQ3.mjs → ROOT_DO_SIZE_WARN_BYTES-CpURtawE.mjs} +60 -114
- package/dist/packem_shared/{applyOnDelete-CAwZfp-5.mjs → applyOnDelete-BXSq3S70.mjs} +1 -1
- package/dist/packem_shared/{applySelect-BvZdFUBT.mjs → applySelect-WQY8m62C.mjs} +3 -1
- package/dist/packem_shared/{armRestore-BJk53Ro8.mjs → armRestore-4Px61hHS.mjs} +4 -10
- package/dist/packem_shared/{serveRelationFanout-BhZF9AuB.mjs → serveRelationFanout-C56hKu1O.mjs} +4 -7
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1679,6 +1679,18 @@ interface DatabaseWriterLike {
|
|
|
1679
1679
|
}, expectedTable?: string) => Promise<{
|
|
1680
1680
|
deleted: number;
|
|
1681
1681
|
}>;
|
|
1682
|
+
/**
|
|
1683
|
+
* Delete every row matching `where` in one call. Matching rows are resolved
|
|
1684
|
+
* first, then each row is deleted through the single-row delete pipeline so
|
|
1685
|
+
* companions, CDC, and broadcast stay correct. **Atomic within a mutation** —
|
|
1686
|
+
* the DO wraps a mutation's dispatch in a BEGIN/COMMIT span, so a mid-batch
|
|
1687
|
+
* throw rolls the whole mutation back. (An action has no transaction span.)
|
|
1688
|
+
*/
|
|
1689
|
+
deleteWhere?: (tableName: string, where: WhereInput, options?: {
|
|
1690
|
+
limit?: number;
|
|
1691
|
+
}) => Promise<{
|
|
1692
|
+
deleted: number;
|
|
1693
|
+
}>;
|
|
1682
1694
|
findFirst: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown> | null>;
|
|
1683
1695
|
findFirstOrThrow: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown>>;
|
|
1684
1696
|
findMany: (tableName: string, args?: QueryArgs) => Promise<QueryPage>;
|
|
@@ -1714,11 +1726,13 @@ interface DatabaseWriterLike {
|
|
|
1714
1726
|
* Insert many documents into one table (a loop over `insert()`),
|
|
1715
1727
|
* returning the minted ids in input order. Each row gets defaults,
|
|
1716
1728
|
* validators, triggers, companion sync, CDC, and broadcast exactly as a
|
|
1717
|
-
* single insert; the caller pays one round-trip instead of N.
|
|
1718
|
-
*
|
|
1719
|
-
*
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1729
|
+
* single insert; the caller pays one round-trip instead of N. Pass
|
|
1730
|
+
* `options.skipDuplicates: true` to turn UNIQUE-constraint breaches into
|
|
1731
|
+
* `null` results for that row instead of failing the whole batch.
|
|
1732
|
+
* **Atomic within a mutation** — the DO wraps a mutation's dispatch in a
|
|
1733
|
+
* BEGIN/COMMIT span, so a mid-batch throw rolls the whole mutation back. (An
|
|
1734
|
+
* action has no transaction span — there, the prior inserts persist; the
|
|
1735
|
+
* in-memory test harness mirrors the span.)
|
|
1722
1736
|
* Rejects a batch larger than `options.limit` (default {@link DEFAULT_BATCH_LIMIT}).
|
|
1723
1737
|
*
|
|
1724
1738
|
* Optional on the interface (like `rankBefore`): the DO writer implements it;
|
|
@@ -1728,7 +1742,8 @@ interface DatabaseWriterLike {
|
|
|
1728
1742
|
*/
|
|
1729
1743
|
insertMany?: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
1730
1744
|
limit?: number;
|
|
1731
|
-
|
|
1745
|
+
skipDuplicates?: boolean;
|
|
1746
|
+
}) => Promise<(string | null)[]>;
|
|
1732
1747
|
/**
|
|
1733
1748
|
* Trusted bulk insert: one multi-row `INSERT` that **skips per-row `.check()`
|
|
1734
1749
|
* validators and before/after triggers** for throughput on data the caller
|
|
@@ -1783,7 +1798,25 @@ interface DatabaseWriterLike {
|
|
|
1783
1798
|
patch: Record<string, unknown>;
|
|
1784
1799
|
}>, options?: {
|
|
1785
1800
|
limit?: number;
|
|
1786
|
-
}, expectedTable?: string) => Promise<
|
|
1801
|
+
}, expectedTable?: string) => Promise<{
|
|
1802
|
+
patched: number;
|
|
1803
|
+
}>;
|
|
1804
|
+
/**
|
|
1805
|
+
* Patch every row matching `where` with the same `patch` in one call.
|
|
1806
|
+
* Matching rows are resolved first, then each row is patched through the
|
|
1807
|
+
* single-row patch pipeline so companions, CDC, and broadcast stay correct.
|
|
1808
|
+
* **Atomic within a mutation** — the DO wraps a mutation's dispatch in a
|
|
1809
|
+
* BEGIN/COMMIT span, so a mid-batch throw rolls the whole mutation back. (An
|
|
1810
|
+
* action has no transaction span.)
|
|
1811
|
+
*/
|
|
1812
|
+
patchWhere?: (tableName: string, args: {
|
|
1813
|
+
patch: Record<string, unknown>;
|
|
1814
|
+
where: WhereInput;
|
|
1815
|
+
}, options?: {
|
|
1816
|
+
limit?: number;
|
|
1817
|
+
}) => Promise<{
|
|
1818
|
+
patched: number;
|
|
1819
|
+
}>;
|
|
1787
1820
|
query: (tableName: string) => TableReaderLike;
|
|
1788
1821
|
/**
|
|
1789
1822
|
* Return the 1-based position of `options.row` within its partition under
|
package/dist/index.d.ts
CHANGED
|
@@ -1679,6 +1679,18 @@ interface DatabaseWriterLike {
|
|
|
1679
1679
|
}, expectedTable?: string) => Promise<{
|
|
1680
1680
|
deleted: number;
|
|
1681
1681
|
}>;
|
|
1682
|
+
/**
|
|
1683
|
+
* Delete every row matching `where` in one call. Matching rows are resolved
|
|
1684
|
+
* first, then each row is deleted through the single-row delete pipeline so
|
|
1685
|
+
* companions, CDC, and broadcast stay correct. **Atomic within a mutation** —
|
|
1686
|
+
* the DO wraps a mutation's dispatch in a BEGIN/COMMIT span, so a mid-batch
|
|
1687
|
+
* throw rolls the whole mutation back. (An action has no transaction span.)
|
|
1688
|
+
*/
|
|
1689
|
+
deleteWhere?: (tableName: string, where: WhereInput, options?: {
|
|
1690
|
+
limit?: number;
|
|
1691
|
+
}) => Promise<{
|
|
1692
|
+
deleted: number;
|
|
1693
|
+
}>;
|
|
1682
1694
|
findFirst: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown> | null>;
|
|
1683
1695
|
findFirstOrThrow: (tableName: string, args?: QueryArgs) => Promise<Record<string, unknown>>;
|
|
1684
1696
|
findMany: (tableName: string, args?: QueryArgs) => Promise<QueryPage>;
|
|
@@ -1714,11 +1726,13 @@ interface DatabaseWriterLike {
|
|
|
1714
1726
|
* Insert many documents into one table (a loop over `insert()`),
|
|
1715
1727
|
* returning the minted ids in input order. Each row gets defaults,
|
|
1716
1728
|
* validators, triggers, companion sync, CDC, and broadcast exactly as a
|
|
1717
|
-
* single insert; the caller pays one round-trip instead of N.
|
|
1718
|
-
*
|
|
1719
|
-
*
|
|
1720
|
-
*
|
|
1721
|
-
*
|
|
1729
|
+
* single insert; the caller pays one round-trip instead of N. Pass
|
|
1730
|
+
* `options.skipDuplicates: true` to turn UNIQUE-constraint breaches into
|
|
1731
|
+
* `null` results for that row instead of failing the whole batch.
|
|
1732
|
+
* **Atomic within a mutation** — the DO wraps a mutation's dispatch in a
|
|
1733
|
+
* BEGIN/COMMIT span, so a mid-batch throw rolls the whole mutation back. (An
|
|
1734
|
+
* action has no transaction span — there, the prior inserts persist; the
|
|
1735
|
+
* in-memory test harness mirrors the span.)
|
|
1722
1736
|
* Rejects a batch larger than `options.limit` (default {@link DEFAULT_BATCH_LIMIT}).
|
|
1723
1737
|
*
|
|
1724
1738
|
* Optional on the interface (like `rankBefore`): the DO writer implements it;
|
|
@@ -1728,7 +1742,8 @@ interface DatabaseWriterLike {
|
|
|
1728
1742
|
*/
|
|
1729
1743
|
insertMany?: (tableName: string, documents: ReadonlyArray<Record<string, unknown>>, options?: {
|
|
1730
1744
|
limit?: number;
|
|
1731
|
-
|
|
1745
|
+
skipDuplicates?: boolean;
|
|
1746
|
+
}) => Promise<(string | null)[]>;
|
|
1732
1747
|
/**
|
|
1733
1748
|
* Trusted bulk insert: one multi-row `INSERT` that **skips per-row `.check()`
|
|
1734
1749
|
* validators and before/after triggers** for throughput on data the caller
|
|
@@ -1783,7 +1798,25 @@ interface DatabaseWriterLike {
|
|
|
1783
1798
|
patch: Record<string, unknown>;
|
|
1784
1799
|
}>, options?: {
|
|
1785
1800
|
limit?: number;
|
|
1786
|
-
}, expectedTable?: string) => Promise<
|
|
1801
|
+
}, expectedTable?: string) => Promise<{
|
|
1802
|
+
patched: number;
|
|
1803
|
+
}>;
|
|
1804
|
+
/**
|
|
1805
|
+
* Patch every row matching `where` with the same `patch` in one call.
|
|
1806
|
+
* Matching rows are resolved first, then each row is patched through the
|
|
1807
|
+
* single-row patch pipeline so companions, CDC, and broadcast stay correct.
|
|
1808
|
+
* **Atomic within a mutation** — the DO wraps a mutation's dispatch in a
|
|
1809
|
+
* BEGIN/COMMIT span, so a mid-batch throw rolls the whole mutation back. (An
|
|
1810
|
+
* action has no transaction span.)
|
|
1811
|
+
*/
|
|
1812
|
+
patchWhere?: (tableName: string, args: {
|
|
1813
|
+
patch: Record<string, unknown>;
|
|
1814
|
+
where: WhereInput;
|
|
1815
|
+
}, options?: {
|
|
1816
|
+
limit?: number;
|
|
1817
|
+
}) => Promise<{
|
|
1818
|
+
patched: number;
|
|
1819
|
+
}>;
|
|
1787
1820
|
query: (tableName: string) => TableReaderLike;
|
|
1788
1821
|
/**
|
|
1789
1822
|
* Return the 1-based position of `options.row` within its partition under
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, norma
|
|
|
3
3
|
export { aggregateTableName, coerceAggregateNumber, encodeAggregateKey, foldAggregateTally, readAggregateValue } from './packem_shared/aggregateTableName-CxNqY1Sl.mjs';
|
|
4
4
|
export { CountRlsUnsupportedError, mergeWhere, planAggregateLookup, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy } from './packem_shared/CountRlsUnsupportedError-BGxj0pgS.mjs';
|
|
5
5
|
export { AUTH_METRICS_BUCKETS_TABLE, AUTH_METRICS_BUCKET_MS, AUTH_METRICS_BUCKET_RETENTION, AUTH_METRICS_TABLE, ensureAuthMetricsTables, readAuthMetrics, recordAuthEvent } from './packem_shared/AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs';
|
|
6
|
-
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-
|
|
6
|
+
export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/NotUniqueError-BdDLev9w.mjs';
|
|
7
7
|
export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs';
|
|
8
8
|
export { SCAN_DEP, createDependencyTracker, depKey } from './packem_shared/SCAN_DEP-DLJF8dsj.mjs';
|
|
9
9
|
export { renderSql } from './packem_shared/renderSql-D6eUcn2N.mjs';
|
|
@@ -11,24 +11,24 @@ export { diffExternalSource } from './packem_shared/diffExternalSource-Cx9HUPJj.
|
|
|
11
11
|
export { materializeExternalRows, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-DNcvoLRT.mjs';
|
|
12
12
|
export { isSourceDue, liftSourceId, pullExternalSourceTick } from './packem_shared/isSourceDue-BptUN8CR.mjs';
|
|
13
13
|
export { FUNCTION_METRICS_BUCKETS_TABLE, FUNCTION_METRICS_BUCKET_MS, FUNCTION_METRICS_BUCKET_RETENTION, FUNCTION_METRICS_INDEX_TABLE, FUNCTION_METRICS_TABLE, ensureFunctionMetricsTables, readFunctionMetricBuckets, readFunctionMetricIndexHits, readFunctionMetrics, readFunctionMetricsTotals, recordFunctionMetric } from './packem_shared/FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
14
|
-
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, FLAGS_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTIONS-
|
|
14
|
+
export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, FLAGS_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTIONS-Bxdijn66.mjs';
|
|
15
15
|
export { LogBuffer } from './packem_shared/LogBuffer-B_Ezju_N.mjs';
|
|
16
16
|
export { MAIL_RETENTION, MAIL_TABLE, clearCapturedMail, ensureMailTable, readCapturedMail, recordCapturedMail } from './packem_shared/MAIL_RETENTION-CPpgl-dX.mjs';
|
|
17
17
|
export { default as NotFoundError } from './packem_shared/NotFoundError-C70b9hLw.mjs';
|
|
18
|
-
export { armRestore, readBookmark } from './packem_shared/armRestore-
|
|
19
|
-
export { applySelect, buildSeekWhere, decodeCursor, encodeCursor, normalizeOrderKeys, softDeleteScope } from './packem_shared/applySelect-
|
|
18
|
+
export { armRestore, readBookmark } from './packem_shared/armRestore-4Px61hHS.mjs';
|
|
19
|
+
export { applySelect, buildSeekWhere, decodeCursor, encodeCursor, normalizeOrderKeys, softDeleteScope } from './packem_shared/applySelect-WQY8m62C.mjs';
|
|
20
20
|
export { RANK_TIEBREAK, encodePartitionKey, matchesRankStaticWhere, rankTableName, resolveRankPartition, sortColumnName } from './packem_shared/RANK_TIEBREAK-CXhdcA1o.mjs';
|
|
21
21
|
export { ReactiveCache, reactiveCacheKey } from './packem_shared/ReactiveCache-BYlSGY0N.mjs';
|
|
22
|
-
export { serveRelationFanout } from './packem_shared/serveRelationFanout-
|
|
23
|
-
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/DEFAULT_MAX_RELATION_KEYS-
|
|
24
|
-
export { applyOnDelete, fanOutScalarCounts, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-
|
|
25
|
-
export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-
|
|
22
|
+
export { serveRelationFanout } from './packem_shared/serveRelationFanout-C56hKu1O.mjs';
|
|
23
|
+
export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/DEFAULT_MAX_RELATION_KEYS-BEan1CRD.mjs';
|
|
24
|
+
export { applyOnDelete, fanOutScalarCounts, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-BXSq3S70.mjs';
|
|
25
|
+
export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/RLS_UNWRAP_SYMBOL-G1eNK4DQ.mjs';
|
|
26
26
|
export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/buildFtsMatch-BLEMawrp.mjs';
|
|
27
27
|
export { M as MIN_ADMIN_TOKEN_LENGTH, a as MIN_AUTH_SECRET_LENGTH, b as buildSecurityAudit } from './packem_shared/security-audit-CucgBice.mjs';
|
|
28
28
|
export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-D71QAL5h.mjs';
|
|
29
|
-
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-
|
|
29
|
+
export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-CpURtawE.mjs';
|
|
30
30
|
export { SHARD_REGISTRY_DO_NAME, ShardRegistryDO } from './packem_shared/SHARD_REGISTRY_DO_NAME-D99roc-r.mjs';
|
|
31
|
-
export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/MAX_SQL_ROWS-
|
|
31
|
+
export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/MAX_SQL_ROWS-D57CJaT9.mjs';
|
|
32
32
|
export { createSystemReader } from './packem_shared/createSystemReader-D12eNH13.mjs';
|
|
33
33
|
export { ConflictError } from './packem_shared/ConflictError-CLoq37xH.mjs';
|
|
34
34
|
export { hasTrigger, runTriggers } from './packem_shared/hasTrigger-5N6_Fx0A.mjs';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const quoteIdentifier = (name) => `"${name.replaceAll('"', '""')}"`;
|
|
2
4
|
|
|
3
5
|
const ADMIN_FUNCTION_PREFIX = "__lunora_admin__:";
|
|
@@ -179,7 +181,7 @@ const buildOrderBy = (orderBy, physicalColumns) => {
|
|
|
179
181
|
const readTablePage = (sql, options) => {
|
|
180
182
|
const { table } = options;
|
|
181
183
|
if (isInternalTable(table) || !tableExists(sql, table)) {
|
|
182
|
-
throw
|
|
184
|
+
throw new LunoraError("UNKNOWN_TABLE", `unknown table: ${table}`, { status: 404 });
|
|
183
185
|
}
|
|
184
186
|
const limit = clamp(Math.trunc(options.limit ?? DEFAULT_PAGE_SIZE), 1, MAX_PAGE_SIZE);
|
|
185
187
|
const offset = Math.max(0, Math.trunc(options.offset ?? 0));
|
|
@@ -215,7 +217,7 @@ const readTablePage = (sql, options) => {
|
|
|
215
217
|
const selectMatchingIds = (sql, options) => {
|
|
216
218
|
const { table } = options;
|
|
217
219
|
if (isInternalTable(table) || !tableExists(sql, table)) {
|
|
218
|
-
throw
|
|
220
|
+
throw new LunoraError("UNKNOWN_TABLE", `unknown table: ${table}`, { status: 404 });
|
|
219
221
|
}
|
|
220
222
|
const limit = clamp(Math.trunc(options.limit ?? MAX_PAGE_SIZE), 1, MAX_PAGE_SIZE);
|
|
221
223
|
const quoted = quoteIdentifier(table);
|
|
@@ -246,16 +248,16 @@ const knownDisplayColumns = (sql, quotedTable, physicalColumns) => {
|
|
|
246
248
|
const facetColumn = (sql, options) => {
|
|
247
249
|
const { column, table } = options;
|
|
248
250
|
if (isInternalTable(table) || !tableExists(sql, table)) {
|
|
249
|
-
throw
|
|
251
|
+
throw new LunoraError("UNKNOWN_TABLE", `unknown table: ${table}`, { status: 404 });
|
|
250
252
|
}
|
|
251
253
|
const quoted = quoteIdentifier(table);
|
|
252
254
|
const physicalColumns = sql.exec(`PRAGMA table_info(${quoted})`).toArray().map((info) => info.name);
|
|
253
255
|
if (!knownDisplayColumns(sql, quoted, physicalColumns).has(column)) {
|
|
254
|
-
throw
|
|
256
|
+
throw new LunoraError("UNKNOWN_COLUMN", `unknown column: ${column}`, { status: 404 });
|
|
255
257
|
}
|
|
256
258
|
const resolved = resolveColumnExpression(column, physicalColumns);
|
|
257
259
|
if (resolved === void 0) {
|
|
258
|
-
throw
|
|
260
|
+
throw new LunoraError("UNKNOWN_COLUMN", `unknown column: ${column}`, { status: 404 });
|
|
259
261
|
}
|
|
260
262
|
const limit = clamp(Math.trunc(options.limit ?? DEFAULT_FACET_LIMIT), 1, MAX_FACET_LIMIT);
|
|
261
263
|
const needle = options.search?.trim() ?? "";
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const MAX_SQL_ROWS = 1e3;
|
|
2
4
|
const READONLY_LEAD = /^(?:explain\s+(?:query\s+plan\s+)?)?(?:select|with)\b/iu;
|
|
3
5
|
const FORBIDDEN_KEYWORD = /\b(?:alter|attach|create|delete|detach|drop|insert|pragma|reindex|replace|truncate|update|vacuum)\b/iu;
|
|
4
6
|
const LEADING_NOISE = /^(?:\s|--[^\n]*\n?|\/\*[\s\S]*?\*\/)+/u;
|
|
5
7
|
const TRAILING_SEMICOLON = /;\s*$/u;
|
|
6
8
|
const stripLeading = (sql) => sql.replace(LEADING_NOISE, "");
|
|
7
|
-
const sqlError = (message, code) =>
|
|
9
|
+
const sqlError = (message, code) => new LunoraError(code, message, { status: 400 });
|
|
8
10
|
const assertReadonly = (query) => {
|
|
9
11
|
const trimmed = stripLeading(query).trim();
|
|
10
12
|
if (trimmed === "") {
|
|
@@ -12,11 +12,11 @@ import { sortColumnName, matchesRankStaticWhere, encodePartitionKey, rankTableNa
|
|
|
12
12
|
import { stringifySearchText, ftsTableName, tokenizeSearch, buildFtsMatch, scoreDocument } from './buildFtsMatch-BLEMawrp.mjs';
|
|
13
13
|
import { s as serializeSqlValue } from './serialize-sql-BlRUoiQe.mjs';
|
|
14
14
|
import { SCAN_DEP } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
15
|
-
import { decodeCursor, normalizeOrderKeys, buildSeekWhere, applySelect, encodeCursor, softDeleteScope, buildSeekBeforeWhere } from './applySelect-
|
|
15
|
+
import { decodeCursor, normalizeOrderKeys, buildSeekWhere, applySelect, encodeCursor, softDeleteScope, buildSeekBeforeWhere } from './applySelect-WQY8m62C.mjs';
|
|
16
16
|
import NotFoundError from './NotFoundError-C70b9hLw.mjs';
|
|
17
|
-
import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-
|
|
18
|
-
import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-
|
|
19
|
-
import { guardWriter } from './RLS_UNWRAP_SYMBOL-
|
|
17
|
+
import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-BEan1CRD.mjs';
|
|
18
|
+
import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-BXSq3S70.mjs';
|
|
19
|
+
import { guardWriter } from './RLS_UNWRAP_SYMBOL-G1eNK4DQ.mjs';
|
|
20
20
|
import { createSystemReader } from './createSystemReader-D12eNH13.mjs';
|
|
21
21
|
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
22
22
|
import { runTriggers } from './hasTrigger-5N6_Fx0A.mjs';
|
|
@@ -483,11 +483,11 @@ const DEFAULT_BATCH_LIMIT = 500;
|
|
|
483
483
|
const assertBatchLimit = (count, limit, op) => {
|
|
484
484
|
const cap = limit ?? DEFAULT_BATCH_LIMIT;
|
|
485
485
|
if (count > cap) {
|
|
486
|
-
throw
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
status: 400
|
|
490
|
-
|
|
486
|
+
throw new LunoraError(
|
|
487
|
+
"BATCH_LIMIT_EXCEEDED",
|
|
488
|
+
`${op}: batch of ${String(count)} exceeds the limit of ${String(cap)} (raise options.limit or chunk the call)`,
|
|
489
|
+
{ status: 400 }
|
|
490
|
+
);
|
|
491
491
|
}
|
|
492
492
|
};
|
|
493
493
|
const createRangeBuilder = (stage) => {
|
|
@@ -1325,6 +1325,25 @@ const createShardCtxDb = (options) => {
|
|
|
1325
1325
|
}
|
|
1326
1326
|
return { deleted: ids.length };
|
|
1327
1327
|
},
|
|
1328
|
+
async deleteWhere(tableName, where, batchOptions) {
|
|
1329
|
+
const global = globalWriterFor(tableName, "deleteWhere");
|
|
1330
|
+
let ids;
|
|
1331
|
+
if (global) {
|
|
1332
|
+
const rows = await global.findMany(tableName, { where });
|
|
1333
|
+
ids = rows.page.map((row) => String(row["_id"]));
|
|
1334
|
+
} else {
|
|
1335
|
+
if (!schema.tables[tableName]) {
|
|
1336
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1337
|
+
}
|
|
1338
|
+
const page = await writer.findMany(tableName, { where });
|
|
1339
|
+
ids = page.page.map((row) => String(row["_id"]));
|
|
1340
|
+
}
|
|
1341
|
+
assertBatchLimit(ids.length, batchOptions?.limit, "deleteWhere");
|
|
1342
|
+
if (writer.deleteMany === void 0) {
|
|
1343
|
+
throw new LunoraError("INTERNAL", `ctx.db.${tableName}.deleteMany is unavailable: this writer has no batch delete`);
|
|
1344
|
+
}
|
|
1345
|
+
return writer.deleteMany(ids, batchOptions);
|
|
1346
|
+
},
|
|
1328
1347
|
async findFirst(tableName, args = {}) {
|
|
1329
1348
|
const result = await writer.findMany(tableName, { ...args, limit: 1 });
|
|
1330
1349
|
return result.page[0] ?? null;
|
|
@@ -1614,9 +1633,18 @@ const createShardCtxDb = (options) => {
|
|
|
1614
1633
|
},
|
|
1615
1634
|
async insertMany(tableName, documents, batchOptions) {
|
|
1616
1635
|
assertBatchLimit(documents.length, batchOptions?.limit, "insertMany");
|
|
1636
|
+
const skipDuplicates = batchOptions?.skipDuplicates === true;
|
|
1617
1637
|
const ids = [];
|
|
1618
1638
|
for (const document of documents) {
|
|
1619
|
-
|
|
1639
|
+
try {
|
|
1640
|
+
ids.push(await writer.insert(tableName, document));
|
|
1641
|
+
} catch (error) {
|
|
1642
|
+
if (skipDuplicates && error instanceof ConflictError && error.kind === "unique") {
|
|
1643
|
+
ids.push(null);
|
|
1644
|
+
} else {
|
|
1645
|
+
throw error;
|
|
1646
|
+
}
|
|
1647
|
+
}
|
|
1620
1648
|
}
|
|
1621
1649
|
return ids;
|
|
1622
1650
|
},
|
|
@@ -1669,6 +1697,31 @@ const createShardCtxDb = (options) => {
|
|
|
1669
1697
|
for (const entry of patches) {
|
|
1670
1698
|
await writer.patch(entry.id, entry.patch, expectedTable);
|
|
1671
1699
|
}
|
|
1700
|
+
return { patched: patches.length };
|
|
1701
|
+
},
|
|
1702
|
+
async patchWhere(tableName, args, batchOptions) {
|
|
1703
|
+
const global = globalWriterFor(tableName, "patchWhere");
|
|
1704
|
+
let patches;
|
|
1705
|
+
if (global) {
|
|
1706
|
+
const rows = await global.findMany(tableName, { where: args.where });
|
|
1707
|
+
patches = rows.page.map((row) => {
|
|
1708
|
+
return { id: String(row["_id"]), patch: args.patch };
|
|
1709
|
+
});
|
|
1710
|
+
} else {
|
|
1711
|
+
if (!schema.tables[tableName]) {
|
|
1712
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1713
|
+
}
|
|
1714
|
+
const page = await writer.findMany(tableName, { where: args.where });
|
|
1715
|
+
patches = page.page.map((row) => {
|
|
1716
|
+
return { id: String(row["_id"]), patch: args.patch };
|
|
1717
|
+
});
|
|
1718
|
+
}
|
|
1719
|
+
assertBatchLimit(patches.length, batchOptions?.limit, "patchWhere");
|
|
1720
|
+
if (writer.patchMany === void 0) {
|
|
1721
|
+
throw new LunoraError("INTERNAL", `ctx.db.${tableName}.patchMany is unavailable: this writer has no batch patch`);
|
|
1722
|
+
}
|
|
1723
|
+
await writer.patchMany(patches, batchOptions);
|
|
1724
|
+
return { patched: patches.length };
|
|
1672
1725
|
},
|
|
1673
1726
|
query(tableName) {
|
|
1674
1727
|
const global = globalWriterFor(tableName, "query");
|
package/dist/packem_shared/{RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs → RLS_UNWRAP_SYMBOL-G1eNK4DQ.mjs}
RENAMED
|
@@ -58,6 +58,10 @@ const guardWriter = (raw, schema, tableOfId) => {
|
|
|
58
58
|
}
|
|
59
59
|
return base.deleteMany(ids, options, expectedTable);
|
|
60
60
|
},
|
|
61
|
+
deleteWhere: base.deleteWhere ? async (tableName, where, options) => {
|
|
62
|
+
guardTable(tableName);
|
|
63
|
+
return await base.deleteWhere?.(tableName, where, options);
|
|
64
|
+
} : void 0,
|
|
61
65
|
findFirst: (tableName, args) => {
|
|
62
66
|
guardTable(tableName);
|
|
63
67
|
return base.findFirst(tableName, args);
|
|
@@ -100,6 +104,10 @@ const guardWriter = (raw, schema, tableOfId) => {
|
|
|
100
104
|
}
|
|
101
105
|
return base.patchMany(patches, options, expectedTable);
|
|
102
106
|
},
|
|
107
|
+
patchWhere: base.patchWhere ? async (tableName, args, options) => {
|
|
108
|
+
guardTable(tableName);
|
|
109
|
+
return await base.patchWhere?.(tableName, args, options);
|
|
110
|
+
} : void 0,
|
|
103
111
|
query: (tableName) => {
|
|
104
112
|
guardTable(tableName);
|
|
105
113
|
return base.query(tableName);
|
|
@@ -7,15 +7,15 @@ import { recordAuthEvent, readAuthMetrics } from './AUTH_METRICS_BUCKETS_TABLE-C
|
|
|
7
7
|
import { DATA_MIGRATION_STATE_TABLE, readMigrationStatus } from './DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs';
|
|
8
8
|
import { SCAN_DEP, createDependencyTracker, tableFromDepKey } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
9
9
|
import { readFunctionMetricsTotals, readFunctionMetricIndexHits, recordFunctionMetric, mergeScanAttribution, readFunctionMetrics, readFunctionMetricBuckets } from './FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs';
|
|
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-
|
|
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';
|
|
11
11
|
import { LogBuffer } from './LogBuffer-B_Ezju_N.mjs';
|
|
12
12
|
import { recordCapturedMail, clearCapturedMail, readCapturedMail, MAIL_TABLE } from './MAIL_RETENTION-CPpgl-dX.mjs';
|
|
13
|
-
import { readBookmark, armRestore } from './armRestore-
|
|
13
|
+
import { readBookmark, armRestore } from './armRestore-4Px61hHS.mjs';
|
|
14
14
|
import { ReactiveCache, reactiveCacheKey } from './ReactiveCache-BYlSGY0N.mjs';
|
|
15
15
|
import { stableStringify } from './stableStringify-MydiuScU.mjs';
|
|
16
16
|
import { redact, standardRules } from '@visulima/redact';
|
|
17
17
|
import { i as isDevEnvironment, c as buildSettings, b as buildSecurityAudit } from './security-audit-CucgBice.mjs';
|
|
18
|
-
import { runReadonlySql } from './MAX_SQL_ROWS-
|
|
18
|
+
import { runReadonlySql } from './MAX_SQL_ROWS-D57CJaT9.mjs';
|
|
19
19
|
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
20
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';
|
|
21
21
|
import { CDC_LOG_TABLE, readCdcChanges, readCdcCursor, readCdcEpoch, minCdcSeq, bumpCdcEpoch } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
@@ -1404,7 +1404,7 @@ const setsIntersect = (a, b) => {
|
|
|
1404
1404
|
const parseRunMigrationArgs = (args) => {
|
|
1405
1405
|
const id = typeof args["id"] === "string" ? args["id"] : "";
|
|
1406
1406
|
if (id.trim() === "") {
|
|
1407
|
-
throw
|
|
1407
|
+
throw new LunoraError("MIGRATION_ID_REQUIRED", "runMigration: `id` is required", { status: 400 });
|
|
1408
1408
|
}
|
|
1409
1409
|
return {
|
|
1410
1410
|
batchSize: typeof args["batchSize"] === "number" ? args["batchSize"] : void 0,
|
|
@@ -1419,25 +1419,25 @@ const parseWriteRowArgs = (args) => {
|
|
|
1419
1419
|
const { op } = args;
|
|
1420
1420
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|
|
1421
1421
|
if (op !== "insert" && op !== "patch" && op !== "replace" && op !== "delete") {
|
|
1422
|
-
throw
|
|
1422
|
+
throw new LunoraError("BAD_REQUEST", "writeRow: `op` must be insert|patch|replace|delete");
|
|
1423
1423
|
}
|
|
1424
1424
|
if (table.trim() === "") {
|
|
1425
|
-
throw
|
|
1425
|
+
throw new LunoraError("BAD_REQUEST", "writeRow: `table` is required");
|
|
1426
1426
|
}
|
|
1427
1427
|
const id = typeof args["id"] === "string" ? args["id"] : void 0;
|
|
1428
1428
|
const record = typeof args["doc"] === "object" && args["doc"] !== null && !Array.isArray(args["doc"]) ? args["doc"] : void 0;
|
|
1429
1429
|
if (op !== "insert" && (id === void 0 || id === "")) {
|
|
1430
|
-
throw
|
|
1430
|
+
throw new LunoraError("BAD_REQUEST", `writeRow: \`id\` is required for op "${op}"`);
|
|
1431
1431
|
}
|
|
1432
1432
|
if (op !== "delete" && record === void 0) {
|
|
1433
|
-
throw
|
|
1433
|
+
throw new LunoraError("BAD_REQUEST", `writeRow: \`doc\` is required for op "${op}"`);
|
|
1434
1434
|
}
|
|
1435
1435
|
return { doc: record, id, op, table };
|
|
1436
1436
|
};
|
|
1437
1437
|
const parseCreateWorkflowInstanceArgs = (args) => {
|
|
1438
1438
|
const exportName = typeof args["exportName"] === "string" ? args["exportName"].trim() : "";
|
|
1439
1439
|
if (exportName === "") {
|
|
1440
|
-
throw
|
|
1440
|
+
throw new LunoraError("BAD_REQUEST", "createWorkflowInstance: `exportName` is required");
|
|
1441
1441
|
}
|
|
1442
1442
|
const id = typeof args["id"] === "string" && args["id"] !== "" ? args["id"] : void 0;
|
|
1443
1443
|
return { exportName, id, params: args["params"] };
|
|
@@ -1446,10 +1446,10 @@ const parseGetWorkflowInstanceStatusArgs = (args) => {
|
|
|
1446
1446
|
const exportName = typeof args["exportName"] === "string" ? args["exportName"].trim() : "";
|
|
1447
1447
|
const id = typeof args["id"] === "string" ? args["id"].trim() : "";
|
|
1448
1448
|
if (exportName === "") {
|
|
1449
|
-
throw
|
|
1449
|
+
throw new LunoraError("BAD_REQUEST", "getWorkflowInstanceStatus: `exportName` is required");
|
|
1450
1450
|
}
|
|
1451
1451
|
if (id === "") {
|
|
1452
|
-
throw
|
|
1452
|
+
throw new LunoraError("BAD_REQUEST", "getWorkflowInstanceStatus: `id` is required");
|
|
1453
1453
|
}
|
|
1454
1454
|
return { exportName, id };
|
|
1455
1455
|
};
|
|
@@ -1504,7 +1504,7 @@ const parseTablePageOrderBy = (raw) => {
|
|
|
1504
1504
|
const parseBulkDeleteArgs = (args) => {
|
|
1505
1505
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|
|
1506
1506
|
if (table.trim() === "") {
|
|
1507
|
-
throw
|
|
1507
|
+
throw new LunoraError("BAD_REQUEST", "deleteRows: `table` is required");
|
|
1508
1508
|
}
|
|
1509
1509
|
return {
|
|
1510
1510
|
filters: parseTablePageFilters(args["filters"]),
|
|
@@ -1516,31 +1516,27 @@ const parseBulkDeleteArgs = (args) => {
|
|
|
1516
1516
|
const parseClearTableArgs = (args) => {
|
|
1517
1517
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|
|
1518
1518
|
if (table.trim() === "") {
|
|
1519
|
-
throw
|
|
1519
|
+
throw new LunoraError("BAD_REQUEST", "clearTable: `table` is required");
|
|
1520
1520
|
}
|
|
1521
1521
|
return { limit: typeof args["limit"] === "number" ? args["limit"] : void 0, table };
|
|
1522
1522
|
};
|
|
1523
1523
|
const parseRecordAuthEventArgs = (args) => {
|
|
1524
1524
|
const { outcome } = args;
|
|
1525
1525
|
if (outcome !== "ok" && outcome !== "fail") {
|
|
1526
|
-
throw
|
|
1526
|
+
throw new LunoraError("BAD_REQUEST", 'recordAuthEvent: `outcome` must be "ok" or "fail"');
|
|
1527
1527
|
}
|
|
1528
1528
|
return { outcome };
|
|
1529
1529
|
};
|
|
1530
1530
|
const parseRecordContainerEventArgs = (args) => {
|
|
1531
1531
|
const raw = args["event"];
|
|
1532
1532
|
if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
|
|
1533
|
-
throw
|
|
1533
|
+
throw new LunoraError("BAD_REQUEST", "recordContainerEvent: `event` must be an object");
|
|
1534
1534
|
}
|
|
1535
1535
|
const envelope = raw;
|
|
1536
1536
|
const container = typeof envelope["container"] === "string" ? envelope["container"] : "";
|
|
1537
1537
|
const event = typeof envelope["event"] === "string" ? envelope["event"] : "";
|
|
1538
1538
|
if (container.trim() === "" || event.trim() === "") {
|
|
1539
|
-
throw
|
|
1540
|
-
code: "BAD_REQUEST",
|
|
1541
|
-
name: "LunoraError",
|
|
1542
|
-
status: 400
|
|
1543
|
-
});
|
|
1539
|
+
throw new LunoraError("BAD_REQUEST", "recordContainerEvent: `event.container` and `event.event` are required");
|
|
1544
1540
|
}
|
|
1545
1541
|
const level = envelope["level"] === "error" ? "error" : "info";
|
|
1546
1542
|
const detail = typeof envelope["message"] === "string" ? envelope["message"] : void 0;
|
|
@@ -1556,21 +1552,21 @@ const parseRunAsArgs = (args) => {
|
|
|
1556
1552
|
const functionPath = typeof args["functionPath"] === "string" ? args["functionPath"] : "";
|
|
1557
1553
|
const userId = typeof args["userId"] === "string" ? args["userId"] : "";
|
|
1558
1554
|
if (functionPath.trim() === "") {
|
|
1559
|
-
throw
|
|
1555
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `functionPath` is required");
|
|
1560
1556
|
}
|
|
1561
1557
|
if (functionPath.startsWith(ADMIN_FUNCTION_PREFIX)) {
|
|
1562
|
-
throw
|
|
1558
|
+
throw new LunoraError("BAD_REQUEST", "runAs: cannot target a reserved admin function");
|
|
1563
1559
|
}
|
|
1564
1560
|
if (userId.trim() === "") {
|
|
1565
|
-
throw
|
|
1561
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `userId` is required");
|
|
1566
1562
|
}
|
|
1567
1563
|
const rawArgs = args["args"];
|
|
1568
1564
|
if (rawArgs !== void 0 && (typeof rawArgs !== "object" || rawArgs === null || Array.isArray(rawArgs))) {
|
|
1569
|
-
throw
|
|
1565
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `args` must be an object");
|
|
1570
1566
|
}
|
|
1571
1567
|
const rawIdentity = args["identity"];
|
|
1572
1568
|
if (rawIdentity !== void 0 && (typeof rawIdentity !== "object" || rawIdentity === null || Array.isArray(rawIdentity))) {
|
|
1573
|
-
throw
|
|
1569
|
+
throw new LunoraError("BAD_REQUEST", "runAs: `identity` must be an object");
|
|
1574
1570
|
}
|
|
1575
1571
|
return {
|
|
1576
1572
|
args: rawArgs === void 0 ? {} : rawArgs,
|
|
@@ -1581,7 +1577,7 @@ const parseRunAsArgs = (args) => {
|
|
|
1581
1577
|
};
|
|
1582
1578
|
const parseRecordMailArgs = (args) => {
|
|
1583
1579
|
const bad = (message) => {
|
|
1584
|
-
throw
|
|
1580
|
+
throw new LunoraError("BAD_REQUEST", `recordMail: ${message}`);
|
|
1585
1581
|
};
|
|
1586
1582
|
const { bcc, cc, from, headers, html, replyTo, subject, text, to } = args;
|
|
1587
1583
|
if (typeof subject !== "string") {
|
|
@@ -1622,7 +1618,7 @@ const TEST_MAIL_DEFAULT_TO = "test@lunora.sh";
|
|
|
1622
1618
|
const buildTestMailInput = (args) => {
|
|
1623
1619
|
const { to } = args;
|
|
1624
1620
|
if (to !== void 0 && typeof to !== "string") {
|
|
1625
|
-
throw
|
|
1621
|
+
throw new LunoraError("BAD_REQUEST", "sendTestMail: `to` must be a string");
|
|
1626
1622
|
}
|
|
1627
1623
|
const recipient = to ?? TEST_MAIL_DEFAULT_TO;
|
|
1628
1624
|
const link = "https://example.test/verify?token=demo";
|
|
@@ -1638,7 +1634,7 @@ Verify your email: ${link}`,
|
|
|
1638
1634
|
};
|
|
1639
1635
|
const parseRecordQueueMessageArgs = (args) => {
|
|
1640
1636
|
const bad = (message) => {
|
|
1641
|
-
throw
|
|
1637
|
+
throw new LunoraError("BAD_REQUEST", `recordQueueMessage: ${message}`);
|
|
1642
1638
|
};
|
|
1643
1639
|
const raw = args["messages"];
|
|
1644
1640
|
if (!Array.isArray(raw)) {
|
|
@@ -1680,23 +1676,15 @@ const MAX_QUEUE_SEND_BATCH = 100;
|
|
|
1680
1676
|
const parseSendQueueMessageArgs = (args) => {
|
|
1681
1677
|
const exportName = typeof args["exportName"] === "string" ? args["exportName"].trim() : "";
|
|
1682
1678
|
if (exportName === "") {
|
|
1683
|
-
throw
|
|
1679
|
+
throw new LunoraError("BAD_REQUEST", "sendQueueMessage: `exportName` is required");
|
|
1684
1680
|
}
|
|
1685
1681
|
const delayRaw = args["delaySeconds"];
|
|
1686
1682
|
if (delayRaw !== void 0 && (typeof delayRaw !== "number" || !Number.isFinite(delayRaw) || delayRaw < 0)) {
|
|
1687
|
-
throw
|
|
1688
|
-
code: "BAD_REQUEST",
|
|
1689
|
-
name: "LunoraError",
|
|
1690
|
-
status: 400
|
|
1691
|
-
});
|
|
1683
|
+
throw new LunoraError("BAD_REQUEST", "sendQueueMessage: `delaySeconds` must be a non-negative number");
|
|
1692
1684
|
}
|
|
1693
1685
|
const batch = Array.isArray(args["batch"]) ? args["batch"] : void 0;
|
|
1694
1686
|
if (batch !== void 0 && (batch.length === 0 || batch.length > MAX_QUEUE_SEND_BATCH)) {
|
|
1695
|
-
throw
|
|
1696
|
-
code: "BAD_REQUEST",
|
|
1697
|
-
name: "LunoraError",
|
|
1698
|
-
status: 400
|
|
1699
|
-
});
|
|
1687
|
+
throw new LunoraError("BAD_REQUEST", `sendQueueMessage: \`batch\` must contain between 1 and ${String(MAX_QUEUE_SEND_BATCH)} messages`);
|
|
1700
1688
|
}
|
|
1701
1689
|
return {
|
|
1702
1690
|
batch,
|
|
@@ -1709,7 +1697,7 @@ const parseSendQueueMessageArgs = (args) => {
|
|
|
1709
1697
|
const parseReplayQueueMessageArgs = (args) => {
|
|
1710
1698
|
const id = typeof args["id"] === "string" ? args["id"].trim() : "";
|
|
1711
1699
|
if (id === "") {
|
|
1712
|
-
throw
|
|
1700
|
+
throw new LunoraError("BAD_REQUEST", "replayQueueMessage: `id` is required");
|
|
1713
1701
|
}
|
|
1714
1702
|
const target = typeof args["target"] === "string" && args["target"].trim() !== "" ? args["target"].trim() : void 0;
|
|
1715
1703
|
return { id, target };
|
|
@@ -1719,24 +1707,24 @@ const parseRankBeforeArgs = (args) => {
|
|
|
1719
1707
|
const index = typeof args["index"] === "string" ? args["index"] : "";
|
|
1720
1708
|
const rowId = typeof args["rowId"] === "string" ? args["rowId"] : "";
|
|
1721
1709
|
if (table.trim() === "") {
|
|
1722
|
-
throw
|
|
1710
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `table` is required");
|
|
1723
1711
|
}
|
|
1724
1712
|
if (index.trim() === "") {
|
|
1725
|
-
throw
|
|
1713
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `index` is required");
|
|
1726
1714
|
}
|
|
1727
1715
|
if (typeof args["partitionKey"] !== "string") {
|
|
1728
|
-
throw
|
|
1716
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `partitionKey` must be a string");
|
|
1729
1717
|
}
|
|
1730
1718
|
if (rowId.trim() === "") {
|
|
1731
|
-
throw
|
|
1719
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `rowId` is required");
|
|
1732
1720
|
}
|
|
1733
1721
|
if (!Array.isArray(args["sortValues"])) {
|
|
1734
|
-
throw
|
|
1722
|
+
throw new LunoraError("BAD_REQUEST", "rankBefore: `sortValues` must be an array");
|
|
1735
1723
|
}
|
|
1736
1724
|
return { index, partitionKey: args["partitionKey"], rowId, sortValues: args["sortValues"], table };
|
|
1737
1725
|
};
|
|
1738
1726
|
const badRequest = (message) => {
|
|
1739
|
-
throw
|
|
1727
|
+
throw new LunoraError("BAD_REQUEST", message);
|
|
1740
1728
|
};
|
|
1741
1729
|
const requireNonEmptyString = (value, field) => {
|
|
1742
1730
|
if (typeof value !== "string" || value.trim() === "") {
|
|
@@ -1796,7 +1784,7 @@ const decodeIndexHitKey = (key) => {
|
|
|
1796
1784
|
const parseApplyCdcArgs = (args) => {
|
|
1797
1785
|
const raw = args["changes"];
|
|
1798
1786
|
if (!Array.isArray(raw)) {
|
|
1799
|
-
throw
|
|
1787
|
+
throw new LunoraError("BAD_REQUEST", "applyCdc: `changes` must be an array");
|
|
1800
1788
|
}
|
|
1801
1789
|
const changes = raw.map((entry, index) => {
|
|
1802
1790
|
const record = entry;
|
|
@@ -1804,27 +1792,15 @@ const parseApplyCdcArgs = (args) => {
|
|
|
1804
1792
|
const table = typeof record["table"] === "string" ? record["table"] : "";
|
|
1805
1793
|
const id = typeof record["id"] === "string" ? record["id"] : "";
|
|
1806
1794
|
if (table === "" || id === "" || op !== "insert" && op !== "update" && op !== "delete") {
|
|
1807
|
-
throw
|
|
1808
|
-
code: "BAD_REQUEST",
|
|
1809
|
-
name: "LunoraError",
|
|
1810
|
-
status: 400
|
|
1811
|
-
});
|
|
1795
|
+
throw new LunoraError("BAD_REQUEST", `applyCdc: changes[${String(index)}] must have a table, id, and op of insert|update|delete`);
|
|
1812
1796
|
}
|
|
1813
1797
|
const rawDocument = record["doc"];
|
|
1814
1798
|
if (rawDocument !== void 0 && (typeof rawDocument !== "object" || rawDocument === null || Array.isArray(rawDocument))) {
|
|
1815
|
-
throw
|
|
1816
|
-
code: "BAD_REQUEST",
|
|
1817
|
-
name: "LunoraError",
|
|
1818
|
-
status: 400
|
|
1819
|
-
});
|
|
1799
|
+
throw new LunoraError("BAD_REQUEST", `applyCdc: changes[${String(index)}].doc must be an object`);
|
|
1820
1800
|
}
|
|
1821
1801
|
const document = rawDocument;
|
|
1822
1802
|
if (document !== void 0 && typeof document["_id"] === "string" && document["_id"] !== id) {
|
|
1823
|
-
throw
|
|
1824
|
-
code: "BAD_REQUEST",
|
|
1825
|
-
name: "LunoraError",
|
|
1826
|
-
status: 400
|
|
1827
|
-
});
|
|
1803
|
+
throw new LunoraError("BAD_REQUEST", `applyCdc: changes[${String(index)}].doc._id must match the entry id`);
|
|
1828
1804
|
}
|
|
1829
1805
|
return {
|
|
1830
1806
|
doc: document,
|
|
@@ -2680,9 +2656,7 @@ class ShardDO {
|
|
|
2680
2656
|
*/
|
|
2681
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`
|
|
2682
2658
|
runRelationFanoutRead(_functionPath, _args) {
|
|
2683
|
-
throw
|
|
2684
|
-
code: "NOT_IMPLEMENTED",
|
|
2685
|
-
name: "LunoraError",
|
|
2659
|
+
throw new LunoraError("NOT_IMPLEMENTED", "__lunora_relation__: no schema bound — the base ShardDO cannot serve cross-shard relation reads", {
|
|
2686
2660
|
status: 500
|
|
2687
2661
|
});
|
|
2688
2662
|
}
|
|
@@ -2809,19 +2783,11 @@ class ShardDO {
|
|
|
2809
2783
|
*/
|
|
2810
2784
|
async runInTransaction(handler) {
|
|
2811
2785
|
if (this.transactionDepth > 0) {
|
|
2812
|
-
throw
|
|
2813
|
-
code: "NESTED_TRANSACTION",
|
|
2814
|
-
name: "LunoraError",
|
|
2815
|
-
status: 500
|
|
2816
|
-
});
|
|
2786
|
+
throw new LunoraError("NESTED_TRANSACTION", "nested transactions are not supported in SQLite-in-DO", { status: 500 });
|
|
2817
2787
|
}
|
|
2818
2788
|
const sqlHandle = this.state.storage.sql;
|
|
2819
2789
|
if (!sqlHandle || typeof sqlHandle.exec !== "function") {
|
|
2820
|
-
throw
|
|
2821
|
-
code: "SQL_UNAVAILABLE",
|
|
2822
|
-
name: "LunoraError",
|
|
2823
|
-
status: 500
|
|
2824
|
-
});
|
|
2790
|
+
throw new LunoraError("SQL_UNAVAILABLE", "storage.sql is not available on this ShardDO state", { status: 500 });
|
|
2825
2791
|
}
|
|
2826
2792
|
const transactionalStorage = this.state.storage;
|
|
2827
2793
|
const run = async () => {
|
|
@@ -2901,9 +2867,7 @@ class ShardDO {
|
|
|
2901
2867
|
*/
|
|
2902
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
|
|
2903
2869
|
runShardDataMigration(args) {
|
|
2904
|
-
return Promise.reject(
|
|
2905
|
-
Object.assign(new Error(`data migration "${args.id}" is not registered`), { code: "MIGRATION_NOT_FOUND", name: "LunoraError", status: 404 })
|
|
2906
|
-
);
|
|
2870
|
+
return Promise.reject(new LunoraError("MIGRATION_NOT_FOUND", `data migration "${args.id}" is not registered`, { status: 404 }));
|
|
2907
2871
|
}
|
|
2908
2872
|
/**
|
|
2909
2873
|
* Lazily provision the shard's physical tables before an operation that
|
|
@@ -3161,7 +3125,7 @@ class ShardDO {
|
|
|
3161
3125
|
*/
|
|
3162
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
|
|
3163
3127
|
runShardWrite(args) {
|
|
3164
|
-
return Promise.reject(
|
|
3128
|
+
return Promise.reject(new LunoraError("UNKNOWN_TABLE", `unknown table: ${args.table}`, { status: 404 }));
|
|
3165
3129
|
}
|
|
3166
3130
|
/**
|
|
3167
3131
|
* Delete one row by primary key THROUGH the schema-aware writer — the
|
|
@@ -3176,7 +3140,7 @@ class ShardDO {
|
|
|
3176
3140
|
*/
|
|
3177
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
|
|
3178
3142
|
deleteRowThroughWriter(_table, _id) {
|
|
3179
|
-
return Promise.reject(
|
|
3143
|
+
return Promise.reject(new LunoraError("UNKNOWN_TABLE", `unknown table: ${_table}`, { status: 404 }));
|
|
3180
3144
|
}
|
|
3181
3145
|
/**
|
|
3182
3146
|
* Bulk-delete the rows of `table` matching the active `filters`/`search`
|
|
@@ -3218,9 +3182,7 @@ class ShardDO {
|
|
|
3218
3182
|
*/
|
|
3219
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
|
|
3220
3184
|
runShardRankBefore(_args) {
|
|
3221
|
-
return Promise.reject(
|
|
3222
|
-
Object.assign(new Error("rankBefore is not implemented in base ShardDO"), { code: "NOT_IMPLEMENTED", name: "LunoraError", status: 500 })
|
|
3223
|
-
);
|
|
3185
|
+
return Promise.reject(new LunoraError("NOT_IMPLEMENTED", "rankBefore is not implemented in base ShardDO", { status: 500 }));
|
|
3224
3186
|
}
|
|
3225
3187
|
/**
|
|
3226
3188
|
* Page this shard's local ranked slice under `index`, each row tagged with
|
|
@@ -3234,9 +3196,7 @@ class ShardDO {
|
|
|
3234
3196
|
*/
|
|
3235
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
|
|
3236
3198
|
runShardRankPage(_args) {
|
|
3237
|
-
return Promise.reject(
|
|
3238
|
-
Object.assign(new Error("rankPage is not implemented in base ShardDO"), { code: "NOT_IMPLEMENTED", name: "LunoraError", status: 500 })
|
|
3239
|
-
);
|
|
3199
|
+
return Promise.reject(new LunoraError("NOT_IMPLEMENTED", "rankPage is not implemented in base ShardDO", { status: 500 }));
|
|
3240
3200
|
}
|
|
3241
3201
|
/**
|
|
3242
3202
|
* Page this shard's change-data-capture log past `sinceSeq`. Read-only and
|
|
@@ -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
|
|
@@ -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,5 +1,5 @@
|
|
|
1
1
|
import { LunoraError } from '@lunora/errors';
|
|
2
|
-
import { applySelect } from './applySelect-
|
|
2
|
+
import { applySelect } from './applySelect-WQY8m62C.mjs';
|
|
3
3
|
|
|
4
4
|
const projectChildren = (documents, nested) => nested.select ? applySelect(documents, nested.select, nested.with) : documents;
|
|
5
5
|
const fanOutScalarCounts = async (counter, tableName, whereField, values, policyWhere) => {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const TIEBREAK_FIELD = "id";
|
|
2
4
|
const ID_FIELDS = /* @__PURE__ */ new Set(["_id", "id"]);
|
|
3
5
|
const normalizeOrderKeys = (orderBy) => {
|
|
@@ -30,7 +32,7 @@ const encodeCursor = (record, keys) => {
|
|
|
30
32
|
values.push(record["_id"]);
|
|
31
33
|
return toBase64(JSON.stringify(values));
|
|
32
34
|
};
|
|
33
|
-
const invalidCursor = () =>
|
|
35
|
+
const invalidCursor = () => new LunoraError("BAD_REQUEST", "invalid cursor");
|
|
34
36
|
const decodeCursor = (cursor) => {
|
|
35
37
|
let decoded;
|
|
36
38
|
try {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const pitrUnavailable = () => Object.assign(
|
|
2
4
|
new Error("native PITR is unavailable here (local dev or a non-SQLite Durable Object); use `lunora backup restore` for off-platform recovery"),
|
|
3
5
|
{
|
|
@@ -12,11 +14,7 @@ const toTime = (time) => {
|
|
|
12
14
|
}
|
|
13
15
|
const parsed = Date.parse(time);
|
|
14
16
|
if (Number.isNaN(parsed)) {
|
|
15
|
-
throw
|
|
16
|
-
code: "BAD_REQUEST",
|
|
17
|
-
name: "LunoraError",
|
|
18
|
-
status: 400
|
|
19
|
-
});
|
|
17
|
+
throw new LunoraError("BAD_REQUEST", `pitr: invalid time "${time}" — expected epoch-ms or an ISO timestamp`);
|
|
20
18
|
}
|
|
21
19
|
return parsed;
|
|
22
20
|
};
|
|
@@ -37,11 +35,7 @@ const armRestore = async (storage, args) => {
|
|
|
37
35
|
let target = args.bookmark;
|
|
38
36
|
if (target === void 0) {
|
|
39
37
|
if (args.time === void 0) {
|
|
40
|
-
throw
|
|
41
|
-
code: "BAD_REQUEST",
|
|
42
|
-
name: "LunoraError",
|
|
43
|
-
status: 400
|
|
44
|
-
});
|
|
38
|
+
throw new LunoraError("BAD_REQUEST", "pitrRestore: provide a `bookmark` or a `time` to restore to");
|
|
45
39
|
}
|
|
46
40
|
if (!storage.getBookmarkForTime) {
|
|
47
41
|
throw pitrUnavailable();
|
package/dist/packem_shared/{serveRelationFanout-BhZF9AuB.mjs → serveRelationFanout-C56hKu1O.mjs}
RENAMED
|
@@ -1,17 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { RELATION_FUNCTION_PREFIX } from './ADMIN_FUNCTIONS-Bxdijn66.mjs';
|
|
2
3
|
|
|
3
4
|
const serveRelationFanout = async (schema, database, functionPath, args) => {
|
|
4
5
|
const table = typeof args["table"] === "string" ? args["table"] : "";
|
|
5
6
|
const definition = schema.tables[table];
|
|
6
7
|
if (!definition) {
|
|
7
|
-
throw
|
|
8
|
+
throw new LunoraError("UNKNOWN_TABLE", `${RELATION_FUNCTION_PREFIX} unknown table "${table}"`, { status: 404 });
|
|
8
9
|
}
|
|
9
10
|
if (definition.shardMode?.kind === "global") {
|
|
10
|
-
throw
|
|
11
|
-
code: "BAD_REQUEST",
|
|
12
|
-
name: "LunoraError",
|
|
13
|
-
status: 400
|
|
14
|
-
});
|
|
11
|
+
throw new LunoraError("BAD_REQUEST", `${RELATION_FUNCTION_PREFIX} table "${table}" is global, not shard-local`);
|
|
15
12
|
}
|
|
16
13
|
const where = args["where"] ?? void 0;
|
|
17
14
|
if (functionPath === `${RELATION_FUNCTION_PREFIX}count`) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/do",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.26",
|
|
4
4
|
"description": "Lunora Durable Objects: ShardDO (SQLite, OCC, hibernated WebSocket subscriptions) and SessionDO",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare",
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"access": "public"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@lunora/errors": "1.0.0-alpha.
|
|
50
|
-
"@visulima/redact": "3.0.0
|
|
49
|
+
"@lunora/errors": "1.0.0-alpha.3",
|
|
50
|
+
"@visulima/redact": "3.0.0",
|
|
51
51
|
"drizzle-orm": "^0.45.2"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|