@lunora/do 1.0.0-alpha.21 → 1.0.0-alpha.23
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 +92 -90
- package/dist/index.d.ts +92 -90
- package/dist/index.mjs +19 -19
- package/dist/packem_shared/{ADMIN_FUNCTIONS-DSUQ5fX9.mjs → ADMIN_FUNCTIONS-BbQdj8h1.mjs} +5 -0
- package/dist/packem_shared/{AGGREGATE_SQL_FUNCTION-CFk6adSu.mjs → AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs} +5 -3
- package/dist/packem_shared/{CDC_LOG_TABLE-DSycmnDf.mjs → CDC_LOG_TABLE-DZSVKRr7.mjs} +1 -1
- package/dist/packem_shared/{ConflictError-C0STs6bU.mjs → ConflictError-CLoq37xH.mjs} +4 -5
- package/dist/packem_shared/{CountRlsUnsupportedError-28ZvvwKS.mjs → CountRlsUnsupportedError-BGxj0pgS.mjs} +4 -4
- package/dist/packem_shared/{DATA_MIGRATION_STATE_TABLE-DfPxn8I0.mjs → DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs} +3 -1
- package/dist/packem_shared/{DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs → DEFAULT_MAX_RELATION_KEYS-CjM9Y1_G.mjs} +8 -6
- package/dist/packem_shared/NotFoundError-C70b9hLw.mjs +9 -0
- package/dist/packem_shared/{NotUniqueError-Do5h_jiW.mjs → NotUniqueError-D1U5SBFR.mjs} +63 -55
- package/dist/packem_shared/{RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs → RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs} +6 -5
- package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-BfPNp3Jh.mjs → ROOT_DO_SIZE_WARN_BYTES-BM4TOOvf.mjs} +388 -49
- package/dist/packem_shared/{applyOnDelete-BQ-8ZlZ1.mjs → applyOnDelete-CAwZfp-5.mjs} +4 -3
- package/dist/packem_shared/{backfillAggregateIndexes-BZsOqDXP.mjs → backfillAggregateIndexes-DDoT-UUI.mjs} +1 -1
- package/dist/packem_shared/{compileWhereSql-MW_Lk8nJ.mjs → compileWhereSql-DE6yfRcQ.mjs} +2 -1
- package/dist/packem_shared/{createSystemReader-8CzSZP9V.mjs → createSystemReader-D12eNH13.mjs} +4 -2
- package/dist/packem_shared/{ctx-db-shapes-0RaIOy7J.mjs → ctx-db-shapes-Cz9dHyh1.mjs} +1 -1
- package/dist/packem_shared/{isSourceDue-9mJRJ9Ld.mjs → isSourceDue-BptUN8CR.mjs} +3 -2
- package/dist/packem_shared/{materializeExternalRows-Bj6EXy50.mjs → materializeExternalRows-DNcvoLRT.mjs} +2 -2
- package/dist/packem_shared/{runShardMigrations-nIwoQeOK.mjs → runShardMigrations-DeZr0KZp.mjs} +1 -1
- package/dist/packem_shared/{serveRelationFanout-C5axmGDj.mjs → serveRelationFanout-BhZF9AuB.mjs} +1 -1
- package/package.json +2 -1
- package/dist/packem_shared/NotFoundError-CMuMZt81.mjs +0 -10
|
@@ -7,6 +7,7 @@ const ADMIN_FUNCTIONS = {
|
|
|
7
7
|
applyCdc: "__lunora_admin__:applyCdc",
|
|
8
8
|
cdcSync: "__lunora_admin__:cdcSync",
|
|
9
9
|
clearCapturedMail: "__lunora_admin__:clearCapturedMail",
|
|
10
|
+
clearQueueMessages: "__lunora_admin__:clearQueueMessages",
|
|
10
11
|
clearTable: "__lunora_admin__:clearTable",
|
|
11
12
|
createWorkflowInstance: "__lunora_admin__:createWorkflowInstance",
|
|
12
13
|
deleteRows: "__lunora_admin__:deleteRows",
|
|
@@ -25,6 +26,7 @@ const ADMIN_FUNCTIONS = {
|
|
|
25
26
|
getLogs: "__lunora_admin__:getLogs",
|
|
26
27
|
getMetrics: "__lunora_admin__:getMetrics",
|
|
27
28
|
getPitrBookmark: "__lunora_admin__:getPitrBookmark",
|
|
29
|
+
getQueueMessages: "__lunora_admin__:getQueueMessages",
|
|
28
30
|
getRequestLog: "__lunora_admin__:getRequestLog",
|
|
29
31
|
getSecurityAudit: "__lunora_admin__:getSecurityAudit",
|
|
30
32
|
getSettings: "__lunora_admin__:getSettings",
|
|
@@ -44,10 +46,13 @@ const ADMIN_FUNCTIONS = {
|
|
|
44
46
|
recordAuthEvent: "__lunora_admin__:recordAuthEvent",
|
|
45
47
|
recordContainerEvent: "__lunora_admin__:recordContainerEvent",
|
|
46
48
|
recordMail: "__lunora_admin__:recordMail",
|
|
49
|
+
recordQueueMessage: "__lunora_admin__:recordQueueMessage",
|
|
50
|
+
replayQueueMessage: "__lunora_admin__:replayQueueMessage",
|
|
47
51
|
rlsPolicies: "__lunora_admin__:rlsPolicies",
|
|
48
52
|
runAs: "__lunora_admin__:runAs",
|
|
49
53
|
runMigration: "__lunora_admin__:runMigration",
|
|
50
54
|
runSql: "__lunora_admin__:runSql",
|
|
55
|
+
sendQueueMessage: "__lunora_admin__:sendQueueMessage",
|
|
51
56
|
sendTestMail: "__lunora_admin__:sendTestMail",
|
|
52
57
|
storageOrphans: "__lunora_admin__:storageOrphans",
|
|
53
58
|
storageReferences: "__lunora_admin__:storageReferences",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const COUNT_OPTION_KEYS = /* @__PURE__ */ new Set(["baseWhere", "relationBaseWhere", "restrictsCounts", "where"]);
|
|
2
4
|
const matchesStaticWhere = (document, predicate) => {
|
|
3
5
|
for (const [field, expected] of Object.entries(predicate)) {
|
|
@@ -38,16 +40,16 @@ const AGGREGATE_SQL_FUNCTION = { avg: "AVG", count: "COUNT", max: "MAX", min: "M
|
|
|
38
40
|
const aggregateSqlFunction = (op) => {
|
|
39
41
|
const sqlFunction = AGGREGATE_SQL_FUNCTION[op];
|
|
40
42
|
if (sqlFunction === void 0) {
|
|
41
|
-
throw new
|
|
43
|
+
throw new LunoraError("INTERNAL", `unknown aggregate op "${op}": expected one of ${Object.keys(AGGREGATE_SQL_FUNCTION).join(", ")}`);
|
|
42
44
|
}
|
|
43
45
|
return sqlFunction;
|
|
44
46
|
};
|
|
45
47
|
const throwingScheduler = {
|
|
46
48
|
runAfter: () => {
|
|
47
|
-
throw new
|
|
49
|
+
throw new LunoraError("INTERNAL", "ctx.scheduler: no scheduler configured for triggers. Pass `scheduler` to the ctx-db factory.");
|
|
48
50
|
},
|
|
49
51
|
runAt: () => {
|
|
50
|
-
throw new
|
|
52
|
+
throw new LunoraError("INTERNAL", "ctx.scheduler: no scheduler configured for triggers. Pass `scheduler` to the ctx-db factory.");
|
|
51
53
|
}
|
|
52
54
|
};
|
|
53
55
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { sql } from 'drizzle-orm';
|
|
2
2
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
3
|
-
import { ConflictError } from './ConflictError-
|
|
3
|
+
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
4
4
|
|
|
5
5
|
const CDC_LOG_TABLE = "__cdc_log";
|
|
6
6
|
const migrateCdcLog = (sql$1) => {
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
3
|
+
class ConflictError extends LunoraError {
|
|
3
4
|
/** Why the conflict fired; `occ` is the contention signal the metrics layer counts. */
|
|
4
5
|
kind;
|
|
5
|
-
status = 409;
|
|
6
6
|
constructor(message = "Optimistic concurrency conflict", kind = "conflict") {
|
|
7
|
-
super(message);
|
|
8
|
-
this.name = "ConflictError";
|
|
7
|
+
super("CONFLICT", message, { name: "ConflictError" });
|
|
9
8
|
this.kind = kind;
|
|
10
9
|
}
|
|
11
10
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
status = 422;
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
3
|
+
class CountRlsUnsupportedError extends LunoraError {
|
|
5
4
|
constructor(table) {
|
|
6
5
|
super(
|
|
6
|
+
"COUNT_RLS_UNSUPPORTED",
|
|
7
7
|
table === void 0 ? "count() is not supported in an RLS-restricted context" : `count() is not supported on table "${table}" inside an RLS-restricted context`
|
|
8
8
|
);
|
|
9
9
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const DATA_MIGRATION_STATE_TABLE = "__lunora_migrations";
|
|
2
4
|
const DEFAULT_BATCH_SIZE = 100;
|
|
3
5
|
const STALE_CLAIM_TIMEOUT_MS = 3e4;
|
|
@@ -128,7 +130,7 @@ const runDataMigration = async (options) => {
|
|
|
128
130
|
const batchSize = options.batchSize ?? migration.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
129
131
|
const transform = direction === "up" ? migration.up : migration.down;
|
|
130
132
|
if (!transform) {
|
|
131
|
-
throw new
|
|
133
|
+
throw new LunoraError("INTERNAL", `data migration "${migration.id}" has no \`${direction}\` transform`);
|
|
132
134
|
}
|
|
133
135
|
let cursor = null;
|
|
134
136
|
let processed = 0;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
import { distinctValues } from './applyOnDelete-CAwZfp-5.mjs';
|
|
2
3
|
|
|
3
4
|
const RELATION_EXISTS_KEY = "__relationExists";
|
|
4
5
|
|
|
@@ -43,7 +44,7 @@ const containsRelationPredicate = (where, schema, tableName) => {
|
|
|
43
44
|
};
|
|
44
45
|
const assertFlatPredicate = (where, schema, tableName, op) => {
|
|
45
46
|
if (where && containsRelationPredicate(where, schema, tableName)) {
|
|
46
|
-
throw new
|
|
47
|
+
throw new LunoraError("INTERNAL", `relation-crossing predicates are not supported in ${op}() — use them in findMany/findFirst or an RLS read policy`);
|
|
47
48
|
}
|
|
48
49
|
};
|
|
49
50
|
const projectChildKeys = async (relation, childWhere, projectField, context, escalatable) => {
|
|
@@ -58,7 +59,8 @@ const projectChildKeys = async (relation, childWhere, projectField, context, esc
|
|
|
58
59
|
if (escalatable) {
|
|
59
60
|
return KEY_OVERFLOW;
|
|
60
61
|
}
|
|
61
|
-
throw new
|
|
62
|
+
throw new LunoraError(
|
|
63
|
+
"INTERNAL",
|
|
62
64
|
`relation predicate on "${relation.table}" matched ${String(keys.length)} rows, exceeding the ${String(context.maxRelationKeys)}-key limit; narrow the predicate (a same-shard EXISTS push-down lifts this cap)`
|
|
63
65
|
);
|
|
64
66
|
}
|
|
@@ -67,7 +69,7 @@ const projectChildKeys = async (relation, childWhere, projectField, context, esc
|
|
|
67
69
|
const compileOperator = async (operator, relation, childWhere, context, escalatable) => {
|
|
68
70
|
const meta = RELATION_OPERATOR_META[operator];
|
|
69
71
|
if (!meta) {
|
|
70
|
-
throw new
|
|
72
|
+
throw new LunoraError("INTERNAL", `unknown relation operator "${operator}"`);
|
|
71
73
|
}
|
|
72
74
|
const { clause, project } = joinColumns(relation);
|
|
73
75
|
const keys = await projectChildKeys(relation, meta.negateChild ? { NOT: childWhere } : childWhere, project, context, escalatable);
|
|
@@ -85,7 +87,7 @@ const compileOperator = async (operator, relation, childWhere, context, escalata
|
|
|
85
87
|
const buildExistsMarker = async (operator, relation, childWhere, parentTable, context) => {
|
|
86
88
|
const meta = RELATION_OPERATOR_META[operator];
|
|
87
89
|
if (!meta) {
|
|
88
|
-
throw new
|
|
90
|
+
throw new LunoraError("INTERNAL", `unknown relation operator "${operator}"`);
|
|
89
91
|
}
|
|
90
92
|
const base = context.relationBaseWhere?.(relation.table);
|
|
91
93
|
const predicatePart = meta.negateChild ? { NOT: childWhere } : childWhere;
|
|
@@ -97,7 +99,7 @@ const buildExistsMarker = async (operator, relation, childWhere, parentTable, co
|
|
|
97
99
|
const assertCardinality = (operator, name, relation) => {
|
|
98
100
|
const meta = RELATION_OPERATOR_META[operator];
|
|
99
101
|
if (meta && meta.kind !== relation.kind) {
|
|
100
|
-
throw new
|
|
102
|
+
throw new LunoraError("INTERNAL", `relation operator "${operator}" requires a to-${meta.kind} relation, but "${name}" is to-${relation.kind}`);
|
|
101
103
|
}
|
|
102
104
|
};
|
|
103
105
|
const resolveRelationNode = async (name, relation, predicate, parentTable, context) => {
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
1
2
|
import { sql } from 'drizzle-orm';
|
|
2
|
-
import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './AGGREGATE_SQL_FUNCTION-
|
|
3
|
+
import { matchesStaticWhere, aggregateSqlFunction, normalizeCountArgument, throwingScheduler } from './AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs';
|
|
3
4
|
import { encodeAggregateKey, foldAggregateTally, aggregateTableName, coerceAggregateNumber, readAggregateValue } from './aggregateTableName-CxNqY1Sl.mjs';
|
|
4
|
-
import { mergeWhere, CountRlsUnsupportedError, selectIndexForGroupBy, selectIndexForCount, selectIndexForAggregate } from './CountRlsUnsupportedError-
|
|
5
|
-
import { appendCdcChange } from './CDC_LOG_TABLE-
|
|
6
|
-
export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-
|
|
5
|
+
import { mergeWhere, CountRlsUnsupportedError, selectIndexForGroupBy, selectIndexForCount, selectIndexForAggregate } from './CountRlsUnsupportedError-BGxj0pgS.mjs';
|
|
6
|
+
import { appendCdcChange } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
7
|
+
export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-DZSVKRr7.mjs';
|
|
7
8
|
import { r as runDrizzle } from './do-exec-5eQy5cEi.mjs';
|
|
8
9
|
import { i as isFtsAvailable, D as DOC_COLUMN$1, r as rowToDocument, A as AGG_KEY, a as AGG_VALUE, b as AGG_COUNT, d as aggUpsertSql, j as jsonPathSql, q as quoteIdentifier, t as tableColumns, e as qualifiedJsonPathSql } from './do-sql-BCHCWtrD.mjs';
|
|
9
10
|
import { param } from './renderSql-D6eUcn2N.mjs';
|
|
@@ -12,18 +13,18 @@ import { stringifySearchText, ftsTableName, tokenizeSearch, buildFtsMatch, score
|
|
|
12
13
|
import { s as serializeSqlValue } from './serialize-sql-BlRUoiQe.mjs';
|
|
13
14
|
import { SCAN_DEP } from './SCAN_DEP-DLJF8dsj.mjs';
|
|
14
15
|
import { decodeCursor, normalizeOrderKeys, buildSeekWhere, applySelect, encodeCursor, softDeleteScope, buildSeekBeforeWhere } from './applySelect-BvZdFUBT.mjs';
|
|
15
|
-
import NotFoundError from './NotFoundError-
|
|
16
|
-
import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-
|
|
17
|
-
import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-
|
|
18
|
-
import { guardWriter } from './RLS_UNWRAP_SYMBOL-
|
|
19
|
-
import { createSystemReader } from './createSystemReader-
|
|
20
|
-
import { ConflictError } from './ConflictError-
|
|
16
|
+
import NotFoundError from './NotFoundError-C70b9hLw.mjs';
|
|
17
|
+
import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-CjM9Y1_G.mjs';
|
|
18
|
+
import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-CAwZfp-5.mjs';
|
|
19
|
+
import { guardWriter } from './RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs';
|
|
20
|
+
import { createSystemReader } from './createSystemReader-D12eNH13.mjs';
|
|
21
|
+
import { ConflictError } from './ConflictError-CLoq37xH.mjs';
|
|
21
22
|
import { runTriggers } from './hasTrigger-5N6_Fx0A.mjs';
|
|
22
|
-
import { compileWhereSql } from './compileWhereSql-
|
|
23
|
-
export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-
|
|
23
|
+
import { compileWhereSql } from './compileWhereSql-DE6yfRcQ.mjs';
|
|
24
|
+
export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-DDoT-UUI.mjs';
|
|
24
25
|
export { C as CLIENT_WATERMARK_TABLE, G as GLOBAL_SHAPE_SNAPSHOT_TABLE, I as IDEMPOTENCY_TABLE, c as advanceClientWatermark, d as deleteGlobalShapeSnapshot, e as deleteGlobalShapeSnapshotsForConnection, m as migrateClientWatermark, b as migrateGlobalShapeSnapshot, r as readClientWatermark, f as readGlobalShapeSnapshot, g as readIdempotent, t as trimIdempotent, w as writeGlobalShapeSnapshot, h as writeIdempotent } from './ctx-db-idempotency-BdcNpvY4.mjs';
|
|
25
|
-
export { runShardMigrations } from './runShardMigrations-
|
|
26
|
-
export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-
|
|
26
|
+
export { runShardMigrations } from './runShardMigrations-DeZr0KZp.mjs';
|
|
27
|
+
export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-Cz9dHyh1.mjs';
|
|
27
28
|
|
|
28
29
|
const rankIndexFieldsUnchanged = (index, previous, next) => {
|
|
29
30
|
const fields = [...index.partitionBy ?? [], ...index.sortBy.map((key) => key.field), ...index.where ? Object.keys(index.where) : []];
|
|
@@ -422,11 +423,11 @@ const computeRankPage = (deps, tableName, indexName, rankPageOptions) => {
|
|
|
422
423
|
const { assertRankPartitionLocal, ensureRankBackfilled, onRead, schema } = deps;
|
|
423
424
|
const definition = schema.tables[tableName];
|
|
424
425
|
if (!definition) {
|
|
425
|
-
throw new
|
|
426
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
426
427
|
}
|
|
427
428
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
428
429
|
if (!index) {
|
|
429
|
-
throw new
|
|
430
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
430
431
|
}
|
|
431
432
|
assertRankPartitionLocal(tableName, definition, index);
|
|
432
433
|
onRead(tableName, SCAN_DEP);
|
|
@@ -474,7 +475,7 @@ const computeRankPage = (deps, tableName, indexName, rankPageOptions) => {
|
|
|
474
475
|
const CLIENT_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
475
476
|
const assertValidClientId = (clientId) => {
|
|
476
477
|
if (!CLIENT_ID_PATTERN.test(clientId)) {
|
|
477
|
-
throw new
|
|
478
|
+
throw new LunoraError("INTERNAL", `invalid clientId ${JSON.stringify(clientId)}: a client-supplied row id must be a UUID`);
|
|
478
479
|
}
|
|
479
480
|
};
|
|
480
481
|
const MAX_TRIGGER_DEPTH = 50;
|
|
@@ -518,14 +519,17 @@ const createSearchBuilder = (search, tableName) => {
|
|
|
518
519
|
const builder = {
|
|
519
520
|
eq: (field, value) => {
|
|
520
521
|
if (!search.definition.filterFields?.includes(field)) {
|
|
521
|
-
throw new
|
|
522
|
+
throw new LunoraError("INTERNAL", `field "${field}" is not a filter field of search index "${search.indexName}" on table "${tableName}"`);
|
|
522
523
|
}
|
|
523
524
|
search.filters.push({ field, value });
|
|
524
525
|
return builder;
|
|
525
526
|
},
|
|
526
527
|
search: (field, query) => {
|
|
527
528
|
if (field !== search.definition.field) {
|
|
528
|
-
throw new
|
|
529
|
+
throw new LunoraError(
|
|
530
|
+
"INTERNAL",
|
|
531
|
+
`search index "${search.indexName}" on table "${tableName}" indexes "${search.definition.field}", not "${field}"`
|
|
532
|
+
);
|
|
529
533
|
}
|
|
530
534
|
const stage = search;
|
|
531
535
|
stage.field = field;
|
|
@@ -706,19 +710,16 @@ const paginateStage = (sql$1, tableName, stage, options, scopeCondition) => {
|
|
|
706
710
|
page
|
|
707
711
|
};
|
|
708
712
|
};
|
|
709
|
-
class NotUniqueError extends
|
|
710
|
-
code = "NOT_UNIQUE";
|
|
711
|
-
status = 400;
|
|
713
|
+
class NotUniqueError extends LunoraError {
|
|
712
714
|
constructor(message = "unique() found more than one matching document") {
|
|
713
|
-
super(message);
|
|
714
|
-
this.name = "NotUniqueError";
|
|
715
|
+
super("NOT_UNIQUE", message, { name: "NotUniqueError" });
|
|
715
716
|
}
|
|
716
717
|
}
|
|
717
718
|
const ID_WHITESPACE_PATTERN = /\s/u;
|
|
718
719
|
const NUL_CHARACTER = String.fromCodePoint(0);
|
|
719
720
|
const normalizeIdStructurally = (schema, tableName, id) => {
|
|
720
721
|
if (!schema.tables[tableName]) {
|
|
721
|
-
throw new
|
|
722
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
722
723
|
}
|
|
723
724
|
if (typeof id !== "string" || id.length === 0 || ID_WHITESPACE_PATTERN.test(id) || id.includes(NUL_CHARACTER)) {
|
|
724
725
|
return null;
|
|
@@ -728,7 +729,7 @@ const normalizeIdStructurally = (schema, tableName, id) => {
|
|
|
728
729
|
const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
729
730
|
const tableDefinition = schema.tables[tableName];
|
|
730
731
|
if (!tableDefinition) {
|
|
731
|
-
throw new
|
|
732
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
732
733
|
}
|
|
733
734
|
const scopeWhere = softDeleteScope(tableDefinition.softDeleteMode, void 0);
|
|
734
735
|
const scopeCondition = scopeWhere ? compileWhereSql(scopeWhere, doWhereSqlStrategy) : void 0;
|
|
@@ -742,7 +743,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
742
743
|
const runSearchFetch = (limit) => {
|
|
743
744
|
const { search } = stage;
|
|
744
745
|
if (!search) {
|
|
745
|
-
throw new
|
|
746
|
+
throw new LunoraError("INTERNAL", "runSearchFetch called without a staged search");
|
|
746
747
|
}
|
|
747
748
|
const filtered = stage.inMemoryFilters.length > 0;
|
|
748
749
|
const engineLimit = filtered ? void 0 : limit;
|
|
@@ -825,7 +826,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
825
826
|
// eslint-disable-next-line @typescript-eslint/require-await -- TableReaderLike returns Promises (the D1 twin awaits real I/O); the DO impl is synchronous over local SQLite
|
|
826
827
|
async paginate(options) {
|
|
827
828
|
if (stage.search) {
|
|
828
|
-
throw new
|
|
829
|
+
throw new LunoraError("INTERNAL", "pagination is not supported on search queries; use .take(n) or .collect()");
|
|
829
830
|
}
|
|
830
831
|
return paginateStage(sql$1, tableName, stage, options, scopeCondition);
|
|
831
832
|
},
|
|
@@ -844,7 +845,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
844
845
|
withIndex(indexName, range) {
|
|
845
846
|
const definition = tableDefinition.indexes.find((index) => index.name === indexName);
|
|
846
847
|
if (!definition) {
|
|
847
|
-
throw new
|
|
848
|
+
throw new LunoraError("INTERNAL", `unknown index "${indexName}" on table "${tableName}"`);
|
|
848
849
|
}
|
|
849
850
|
onIndexUse(tableName, indexName, "index");
|
|
850
851
|
stage.indexName = indexName;
|
|
@@ -857,7 +858,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
857
858
|
withSearchIndex(indexName, search) {
|
|
858
859
|
const definition = (tableDefinition.searchIndexes ?? []).find((index) => index.name === indexName);
|
|
859
860
|
if (!definition) {
|
|
860
|
-
throw new
|
|
861
|
+
throw new LunoraError("INTERNAL", `unknown search index "${indexName}" on table "${tableName}"`);
|
|
861
862
|
}
|
|
862
863
|
onIndexUse(tableName, indexName, "search");
|
|
863
864
|
const searchStage = {
|
|
@@ -871,7 +872,7 @@ const buildReader = (sql$1, schema, tableName, onIndexUse = () => void 0) => {
|
|
|
871
872
|
stage.search = searchStage;
|
|
872
873
|
search(createSearchBuilder(searchStage, tableName));
|
|
873
874
|
if (!searchStage.hasQuery) {
|
|
874
|
-
throw new
|
|
875
|
+
throw new LunoraError("INTERNAL", `search index "${indexName}" on table "${tableName}" requires a .search(field, query) call`);
|
|
875
876
|
}
|
|
876
877
|
return reader;
|
|
877
878
|
}
|
|
@@ -913,7 +914,10 @@ const applyOnUpdate = (definition, provided, target, auth) => {
|
|
|
913
914
|
const assertNoExplicitUndefined = (op, document) => {
|
|
914
915
|
for (const field of Object.keys(document)) {
|
|
915
916
|
if (document[field] === void 0) {
|
|
916
|
-
throw new
|
|
917
|
+
throw new LunoraError(
|
|
918
|
+
"INTERNAL",
|
|
919
|
+
`Cannot ${op} field '${field}' to undefined — use null to clear a nullable field, or omit the key to leave it unchanged.`
|
|
920
|
+
);
|
|
917
921
|
}
|
|
918
922
|
}
|
|
919
923
|
};
|
|
@@ -993,7 +997,10 @@ const createShardCtxDb = (options) => {
|
|
|
993
997
|
const routeBackend = (table, op) => {
|
|
994
998
|
if (isGlobalTable(table)) {
|
|
995
999
|
if (!globalDb) {
|
|
996
|
-
throw new
|
|
1000
|
+
throw new LunoraError(
|
|
1001
|
+
"INTERNAL",
|
|
1002
|
+
`cross-backend ${op} for global table '${table}' requires a globalDb writer — pass one to createShardCtxDb({ globalDb })`
|
|
1003
|
+
);
|
|
997
1004
|
}
|
|
998
1005
|
return globalDb;
|
|
999
1006
|
}
|
|
@@ -1005,7 +1012,7 @@ const createShardCtxDb = (options) => {
|
|
|
1005
1012
|
return void 0;
|
|
1006
1013
|
}
|
|
1007
1014
|
if (!globalDb) {
|
|
1008
|
-
throw new
|
|
1015
|
+
throw new LunoraError("INTERNAL", `${op} on global table '${tableName}' requires a globalDb writer — pass one to createShardCtxDb({ globalDb })`);
|
|
1009
1016
|
}
|
|
1010
1017
|
return globalDb;
|
|
1011
1018
|
};
|
|
@@ -1036,7 +1043,7 @@ const createShardCtxDb = (options) => {
|
|
|
1036
1043
|
}
|
|
1037
1044
|
const definition = schema.tables[relationTable];
|
|
1038
1045
|
if (!definition) {
|
|
1039
|
-
throw new
|
|
1046
|
+
throw new LunoraError("INTERNAL", `unknown table: ${relationTable}`);
|
|
1040
1047
|
}
|
|
1041
1048
|
onRead(relationTable, SCAN_DEP);
|
|
1042
1049
|
const softScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
@@ -1153,7 +1160,7 @@ const createShardCtxDb = (options) => {
|
|
|
1153
1160
|
}
|
|
1154
1161
|
const definition = schema.tables[tableName];
|
|
1155
1162
|
if (!definition) {
|
|
1156
|
-
throw new
|
|
1163
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1157
1164
|
}
|
|
1158
1165
|
aggregateSqlFunction(aggOptions.op);
|
|
1159
1166
|
if (aggOptions.op === "count") {
|
|
@@ -1165,7 +1172,7 @@ const createShardCtxDb = (options) => {
|
|
|
1165
1172
|
});
|
|
1166
1173
|
}
|
|
1167
1174
|
if (!aggOptions.field) {
|
|
1168
|
-
throw new
|
|
1175
|
+
throw new LunoraError("INTERNAL", `aggregate(${tableName}, { op: "${aggOptions.op}" }): "field" is required for non-count reducers`);
|
|
1169
1176
|
}
|
|
1170
1177
|
onRead(tableName, SCAN_DEP);
|
|
1171
1178
|
const aggScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
@@ -1207,7 +1214,7 @@ const createShardCtxDb = (options) => {
|
|
|
1207
1214
|
}
|
|
1208
1215
|
const definition = schema.tables[tableName];
|
|
1209
1216
|
if (!definition) {
|
|
1210
|
-
throw new
|
|
1217
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1211
1218
|
}
|
|
1212
1219
|
const countOptions = normalizeCountArgument(whereOrOptions);
|
|
1213
1220
|
if (countOptions.restrictsCounts) {
|
|
@@ -1338,7 +1345,7 @@ const createShardCtxDb = (options) => {
|
|
|
1338
1345
|
}
|
|
1339
1346
|
const findManyDefinition = schema.tables[tableName];
|
|
1340
1347
|
if (!findManyDefinition) {
|
|
1341
|
-
throw new
|
|
1348
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1342
1349
|
}
|
|
1343
1350
|
const isFullScan = !args.where && !args.baseWhere;
|
|
1344
1351
|
if (isFullScan) {
|
|
@@ -1451,13 +1458,13 @@ const createShardCtxDb = (options) => {
|
|
|
1451
1458
|
}
|
|
1452
1459
|
const definition = schema.tables[tableName];
|
|
1453
1460
|
if (!definition) {
|
|
1454
|
-
throw new
|
|
1461
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1455
1462
|
}
|
|
1456
1463
|
onRead(tableName, SCAN_DEP);
|
|
1457
1464
|
const agg = groupOptions.agg ?? { op: "count" };
|
|
1458
1465
|
aggregateSqlFunction(agg.op);
|
|
1459
1466
|
if (agg.op !== "count" && !agg.field) {
|
|
1460
|
-
throw new
|
|
1467
|
+
throw new LunoraError("INTERNAL", `groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
|
|
1461
1468
|
}
|
|
1462
1469
|
const groupScope = softDeleteScope(definition.softDeleteMode, void 0);
|
|
1463
1470
|
const effective = mergeWhere(mergeWhere(groupOptions.baseWhere, groupOptions.where), groupScope);
|
|
@@ -1502,7 +1509,7 @@ const createShardCtxDb = (options) => {
|
|
|
1502
1509
|
} else {
|
|
1503
1510
|
const { field } = agg;
|
|
1504
1511
|
if (field === void 0) {
|
|
1505
|
-
throw new
|
|
1512
|
+
throw new LunoraError("INTERNAL", `groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
|
|
1506
1513
|
}
|
|
1507
1514
|
select.push(sql`${sql.raw(aggregateSqlFunction(agg.op))}(${jsonPathSql(field)}) AS value`);
|
|
1508
1515
|
}
|
|
@@ -1535,7 +1542,7 @@ const createShardCtxDb = (options) => {
|
|
|
1535
1542
|
}
|
|
1536
1543
|
const definition = schema.tables[tableName];
|
|
1537
1544
|
if (!definition) {
|
|
1538
|
-
throw new
|
|
1545
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1539
1546
|
}
|
|
1540
1547
|
const withDefaults = applyInsertDefaults(definition, document, auth);
|
|
1541
1548
|
runRowValidators(definition, withDefaults);
|
|
@@ -1584,7 +1591,7 @@ const createShardCtxDb = (options) => {
|
|
|
1584
1591
|
}
|
|
1585
1592
|
const definition = schema.tables[tableName];
|
|
1586
1593
|
if (!definition) {
|
|
1587
|
-
throw new
|
|
1594
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1588
1595
|
}
|
|
1589
1596
|
ensureBackfilledForTable(tableName);
|
|
1590
1597
|
ensureRankBackfilledForTable(tableName);
|
|
@@ -1624,12 +1631,12 @@ const createShardCtxDb = (options) => {
|
|
|
1624
1631
|
await global.patch(id, patch);
|
|
1625
1632
|
return;
|
|
1626
1633
|
}
|
|
1627
|
-
throw new
|
|
1634
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1628
1635
|
}
|
|
1629
1636
|
const { docJson: existingJson, row: existing, tableName } = located;
|
|
1630
1637
|
const tableDefinition = schema.tables[tableName];
|
|
1631
1638
|
if (!tableDefinition) {
|
|
1632
|
-
throw new
|
|
1639
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1633
1640
|
}
|
|
1634
1641
|
onRead(tableName, id);
|
|
1635
1642
|
assertNoExplicitUndefined("patch", patch);
|
|
@@ -1681,11 +1688,11 @@ const createShardCtxDb = (options) => {
|
|
|
1681
1688
|
onIndexUse(tableName, indexName, "rank");
|
|
1682
1689
|
const definition = schema.tables[tableName];
|
|
1683
1690
|
if (!definition) {
|
|
1684
|
-
throw new
|
|
1691
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1685
1692
|
}
|
|
1686
1693
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
1687
1694
|
if (!index) {
|
|
1688
|
-
throw new
|
|
1695
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
1689
1696
|
}
|
|
1690
1697
|
assertRankPartitionLocal(tableName, definition, index);
|
|
1691
1698
|
if (rankOptions.restrictsCounts) {
|
|
@@ -1726,17 +1733,18 @@ const createShardCtxDb = (options) => {
|
|
|
1726
1733
|
// eslint-disable-next-line @typescript-eslint/require-await -- DatabaseWriterLike returns Promises (the D1 twin awaits I/O); the body is synchronous SQLite
|
|
1727
1734
|
async rankBefore(tableName, indexName, rankBeforeOptions) {
|
|
1728
1735
|
if (isGlobalTable(tableName)) {
|
|
1729
|
-
throw new
|
|
1736
|
+
throw new LunoraError(
|
|
1737
|
+
"INTERNAL",
|
|
1730
1738
|
`rankBefore is not supported on the global (.global()) table '${tableName}' — cross-shard rank cursors apply only to sharded tables`
|
|
1731
1739
|
);
|
|
1732
1740
|
}
|
|
1733
1741
|
const definition = schema.tables[tableName];
|
|
1734
1742
|
if (!definition) {
|
|
1735
|
-
throw new
|
|
1743
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1736
1744
|
}
|
|
1737
1745
|
const index = definition.rankIndexes?.find((i) => i.name === indexName);
|
|
1738
1746
|
if (!index) {
|
|
1739
|
-
throw new
|
|
1747
|
+
throw new LunoraError("INTERNAL", `unknown rankIndex "${indexName}" on table "${tableName}"`);
|
|
1740
1748
|
}
|
|
1741
1749
|
if (rankBeforeOptions.restrictsCounts) {
|
|
1742
1750
|
throw new CountRlsUnsupportedError(tableName);
|
|
@@ -1774,11 +1782,11 @@ const createShardCtxDb = (options) => {
|
|
|
1774
1782
|
await global.restore(id);
|
|
1775
1783
|
return;
|
|
1776
1784
|
}
|
|
1777
|
-
throw new
|
|
1785
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1778
1786
|
}
|
|
1779
1787
|
const field = schema.tables[located.tableName]?.softDeleteMode?.field;
|
|
1780
1788
|
if (!field) {
|
|
1781
|
-
throw new
|
|
1789
|
+
throw new LunoraError("INTERNAL", `ctx.db.restore: table "${located.tableName}" is not a .softDelete() table`);
|
|
1782
1790
|
}
|
|
1783
1791
|
const wasDeleted = located.row[field] !== null && located.row[field] !== void 0;
|
|
1784
1792
|
await writer.patch(id, { [field]: null }, expectedTable);
|
|
@@ -1794,12 +1802,12 @@ const createShardCtxDb = (options) => {
|
|
|
1794
1802
|
await global.replace(id, document);
|
|
1795
1803
|
return;
|
|
1796
1804
|
}
|
|
1797
|
-
throw new
|
|
1805
|
+
throw new LunoraError("INTERNAL", `document not found: ${id}`);
|
|
1798
1806
|
}
|
|
1799
1807
|
const { docJson: existingJson, row: previous, tableName } = located;
|
|
1800
1808
|
const tableDefinition = schema.tables[tableName];
|
|
1801
1809
|
if (!tableDefinition) {
|
|
1802
|
-
throw new
|
|
1810
|
+
throw new LunoraError("INTERNAL", `unknown table: ${tableName}`);
|
|
1803
1811
|
}
|
|
1804
1812
|
assertNoExplicitUndefined("replace", document);
|
|
1805
1813
|
const creationTime = typeof document["_creationTime"] === "number" ? document["_creationTime"] : clock();
|
package/dist/packem_shared/{RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs → RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs}
RENAMED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
+
import { LunoraError } from '@lunora/errors';
|
|
2
|
+
|
|
1
3
|
const RLS_UNWRAP_SYMBOL = /* @__PURE__ */ Symbol.for("lunora.ctxdb.rls-unwrap");
|
|
2
|
-
class RlsRequiredError extends
|
|
3
|
-
code = "RLS_REQUIRED";
|
|
4
|
-
status = 403;
|
|
4
|
+
class RlsRequiredError extends LunoraError {
|
|
5
5
|
table;
|
|
6
6
|
constructor(table) {
|
|
7
7
|
super(
|
|
8
|
-
|
|
8
|
+
"RLS_REQUIRED",
|
|
9
|
+
`ctx.db access to "${table}" is denied: the schema is marked .rls("required"), so this table is protected. Apply RLS with .use(rls(policies)) in the procedure, or mark the table .public() to opt it out.`,
|
|
10
|
+
{ name: "RlsRequiredError" }
|
|
9
11
|
);
|
|
10
|
-
this.name = "RlsRequiredError";
|
|
11
12
|
this.table = table;
|
|
12
13
|
}
|
|
13
14
|
}
|