@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.
Files changed (25) hide show
  1. package/dist/index.d.mts +92 -90
  2. package/dist/index.d.ts +92 -90
  3. package/dist/index.mjs +19 -19
  4. package/dist/packem_shared/{ADMIN_FUNCTIONS-DSUQ5fX9.mjs → ADMIN_FUNCTIONS-BbQdj8h1.mjs} +5 -0
  5. package/dist/packem_shared/{AGGREGATE_SQL_FUNCTION-CFk6adSu.mjs → AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs} +5 -3
  6. package/dist/packem_shared/{CDC_LOG_TABLE-DSycmnDf.mjs → CDC_LOG_TABLE-DZSVKRr7.mjs} +1 -1
  7. package/dist/packem_shared/{ConflictError-C0STs6bU.mjs → ConflictError-CLoq37xH.mjs} +4 -5
  8. package/dist/packem_shared/{CountRlsUnsupportedError-28ZvvwKS.mjs → CountRlsUnsupportedError-BGxj0pgS.mjs} +4 -4
  9. package/dist/packem_shared/{DATA_MIGRATION_STATE_TABLE-DfPxn8I0.mjs → DATA_MIGRATION_STATE_TABLE-DB3IYUR3.mjs} +3 -1
  10. package/dist/packem_shared/{DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs → DEFAULT_MAX_RELATION_KEYS-CjM9Y1_G.mjs} +8 -6
  11. package/dist/packem_shared/NotFoundError-C70b9hLw.mjs +9 -0
  12. package/dist/packem_shared/{NotUniqueError-Do5h_jiW.mjs → NotUniqueError-D1U5SBFR.mjs} +63 -55
  13. package/dist/packem_shared/{RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs → RLS_UNWRAP_SYMBOL-DnjkqVgY.mjs} +6 -5
  14. package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-BfPNp3Jh.mjs → ROOT_DO_SIZE_WARN_BYTES-BM4TOOvf.mjs} +388 -49
  15. package/dist/packem_shared/{applyOnDelete-BQ-8ZlZ1.mjs → applyOnDelete-CAwZfp-5.mjs} +4 -3
  16. package/dist/packem_shared/{backfillAggregateIndexes-BZsOqDXP.mjs → backfillAggregateIndexes-DDoT-UUI.mjs} +1 -1
  17. package/dist/packem_shared/{compileWhereSql-MW_Lk8nJ.mjs → compileWhereSql-DE6yfRcQ.mjs} +2 -1
  18. package/dist/packem_shared/{createSystemReader-8CzSZP9V.mjs → createSystemReader-D12eNH13.mjs} +4 -2
  19. package/dist/packem_shared/{ctx-db-shapes-0RaIOy7J.mjs → ctx-db-shapes-Cz9dHyh1.mjs} +1 -1
  20. package/dist/packem_shared/{isSourceDue-9mJRJ9Ld.mjs → isSourceDue-BptUN8CR.mjs} +3 -2
  21. package/dist/packem_shared/{materializeExternalRows-Bj6EXy50.mjs → materializeExternalRows-DNcvoLRT.mjs} +2 -2
  22. package/dist/packem_shared/{runShardMigrations-nIwoQeOK.mjs → runShardMigrations-DeZr0KZp.mjs} +1 -1
  23. package/dist/packem_shared/{serveRelationFanout-C5axmGDj.mjs → serveRelationFanout-BhZF9AuB.mjs} +1 -1
  24. package/package.json +2 -1
  25. 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 Error(`unknown aggregate op "${op}": expected one of ${Object.keys(AGGREGATE_SQL_FUNCTION).join(", ")}`);
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 Error("ctx.scheduler: no scheduler configured for triggers. Pass `scheduler` to the ctx-db factory.");
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 Error("ctx.scheduler: no scheduler configured for triggers. Pass `scheduler` to the ctx-db factory.");
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-C0STs6bU.mjs';
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
- class ConflictError extends Error {
2
- code = "CONFLICT";
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
- class CountRlsUnsupportedError extends Error {
2
- code = "COUNT_RLS_UNSUPPORTED";
3
- name = "LunoraError";
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 Error(`data migration "${migration.id}" has no \`${direction}\` transform`);
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 { distinctValues } from './applyOnDelete-BQ-8ZlZ1.mjs';
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 Error(`relation-crossing predicates are not supported in ${op}() — use them in findMany/findFirst or an RLS read policy`);
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 Error(
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 Error(`unknown relation operator "${operator}"`);
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 Error(`unknown relation operator "${operator}"`);
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 Error(`relation operator "${operator}" requires a to-${meta.kind} relation, but "${name}" is to-${relation.kind}`);
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) => {
@@ -0,0 +1,9 @@
1
+ import { LunoraError } from '@lunora/errors';
2
+
3
+ class NotFoundError extends LunoraError {
4
+ constructor(message = "Document not found") {
5
+ super("NOT_FOUND", message, { name: "NotFoundError" });
6
+ }
7
+ }
8
+
9
+ export { NotFoundError as default };
@@ -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-CFk6adSu.mjs';
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-28ZvvwKS.mjs';
5
- import { appendCdcChange } from './CDC_LOG_TABLE-DSycmnDf.mjs';
6
- export { CDC_LOG_TABLE, applyCdcChanges, bumpCdcEpoch, minCdcSeq, readCdcChanges, readCdcCursor, readCdcEpoch, trimCdcChanges } from './CDC_LOG_TABLE-DSycmnDf.mjs';
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-CMuMZt81.mjs';
16
- import { assertFlatPredicate, resolveRelationPredicates } from './DEFAULT_MAX_RELATION_KEYS-DU-Y4-LJ.mjs';
17
- import { runRowValidators, resolveWith, applyOnDelete, fanOutScalarCounts } from './applyOnDelete-BQ-8ZlZ1.mjs';
18
- import { guardWriter } from './RLS_UNWRAP_SYMBOL-EtGQdC9d.mjs';
19
- import { createSystemReader } from './createSystemReader-8CzSZP9V.mjs';
20
- import { ConflictError } from './ConflictError-C0STs6bU.mjs';
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-MW_Lk8nJ.mjs';
23
- export { backfillAggregateIndexes, backfillRankIndexes } from './backfillAggregateIndexes-BZsOqDXP.mjs';
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-nIwoQeOK.mjs';
26
- export { a as selectShapeMemberIds, s as selectShapeRows } from './ctx-db-shapes-0RaIOy7J.mjs';
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown rankIndex "${indexName}" on table "${tableName}"`);
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 Error(`invalid clientId ${JSON.stringify(clientId)}: a client-supplied row id must be a UUID`);
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 Error(`field "${field}" is not a filter field of search index "${search.indexName}" on table "${tableName}"`);
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 Error(`search index "${search.indexName}" on table "${tableName}" indexes "${search.definition.field}", not "${field}"`);
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 Error {
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown table: ${tableName}`);
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 Error("runSearchFetch called without a staged search");
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 Error("pagination is not supported on search queries; use .take(n) or .collect()");
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 Error(`unknown index "${indexName}" on table "${tableName}"`);
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 Error(`unknown search index "${indexName}" on table "${tableName}"`);
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 Error(`search index "${indexName}" on table "${tableName}" requires a .search(field, query) call`);
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 Error(`Cannot ${op} field '${field}' to undefined — use null to clear a nullable field, or omit the key to leave it unchanged.`);
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 Error(`cross-backend ${op} for global table '${table}' requires a globalDb writer — pass one to createShardCtxDb({ globalDb })`);
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 Error(`${op} on global table '${tableName}' requires a globalDb writer — pass one to createShardCtxDb({ globalDb })`);
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 Error(`unknown table: ${relationTable}`);
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 Error(`unknown table: ${tableName}`);
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 Error(`aggregate(${tableName}, { op: "${aggOptions.op}" }): "field" is required for non-count reducers`);
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown table: ${tableName}`);
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 Error(`groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
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 Error(`groupBy(${tableName}, { agg: { op: "${agg.op}" } }): "field" is required for non-count reducers`);
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown table: ${tableName}`);
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 Error(`document not found: ${id}`);
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown rankIndex "${indexName}" on table "${tableName}"`);
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 Error(
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 Error(`unknown table: ${tableName}`);
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 Error(`unknown rankIndex "${indexName}" on table "${tableName}"`);
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 Error(`document not found: ${id}`);
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 Error(`ctx.db.restore: table "${located.tableName}" is not a .softDelete() table`);
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 Error(`document not found: ${id}`);
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 Error(`unknown table: ${tableName}`);
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();
@@ -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 Error {
3
- code = "RLS_REQUIRED";
4
- status = 403;
4
+ class RlsRequiredError extends LunoraError {
5
5
  table;
6
6
  constructor(table) {
7
7
  super(
8
- `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.`
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
  }