@lunora/do 1.0.0-alpha.3 → 1.0.0-alpha.30

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 (51) hide show
  1. package/LICENSE.md +6 -0
  2. package/__assets__/package-og.svg +1 -1
  3. package/dist/index.d.mts +1375 -289
  4. package/dist/index.d.ts +1375 -289
  5. package/dist/index.mjs +35 -30
  6. package/dist/packem_shared/{ADMIN_FUNCTION_PREFIX-Dzdqq5J2.mjs → ADMIN_FUNCTIONS-CAHLZMj8.mjs} +62 -8
  7. package/dist/packem_shared/{matchesStaticWhere-CFk6adSu.mjs → AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs} +5 -3
  8. package/dist/packem_shared/{applyCdcChanges-Ctdmxmrv.mjs → CDC_LOG_TABLE-DjJEHiM2.mjs} +7 -3
  9. package/dist/packem_shared/{ConflictError-C0STs6bU.mjs → ConflictError-CLoq37xH.mjs} +4 -5
  10. package/dist/packem_shared/{CountRlsUnsupportedError-28ZvvwKS.mjs → CountRlsUnsupportedError-BGxj0pgS.mjs} +4 -4
  11. package/dist/packem_shared/{DATA_MIGRATION_STATE_TABLE-PTtTiQ7U.mjs → DATA_MIGRATION_STATE_TABLE-CYwBpyTr.mjs} +11 -3
  12. package/dist/packem_shared/{assertFlatPredicate-DyVYReuT.mjs → DEFAULT_MAX_RELATION_KEYS-BEan1CRD.mjs} +58 -7
  13. package/dist/packem_shared/{assertReadonly-dDcFE1YZ.mjs → MAX_SQL_ROWS-D57CJaT9.mjs} +3 -1
  14. package/dist/packem_shared/NotFoundError-C70b9hLw.mjs +9 -0
  15. package/dist/packem_shared/{assertValidClientId-CBZ1zC96.mjs → NotUniqueError-BigrdT_W.mjs} +241 -90
  16. package/dist/packem_shared/{rank-CrkEIpF4.mjs → RANK_TIEBREAK-CXhdcA1o.mjs} +2 -13
  17. package/dist/packem_shared/{guardWriter-u3UlnCH5.mjs → RLS_UNWRAP_SYMBOL-DTvHvRzY.mjs} +22 -9
  18. package/dist/packem_shared/{ROOT_DO_SIZE_WARN_BYTES-DQkmGiCS.mjs → ROOT_DO_SIZE_WARN_BYTES-BA8QOChj.mjs} +2878 -326
  19. package/dist/packem_shared/{ReactiveCache-ByVzgH3d.mjs → ReactiveCache-BYlSGY0N.mjs} +1 -28
  20. package/dist/packem_shared/{SESSION_DO_TTL_DEFAULT-ilPZsVwu.mjs → SESSION_DO_TTL_DEFAULT-BnSKgVO4.mjs} +16 -27
  21. package/dist/packem_shared/{SHARD_REGISTRY_DO_NAME-BsAbi5Mn.mjs → SHARD_REGISTRY_DO_NAME-D99roc-r.mjs} +12 -14
  22. package/dist/packem_shared/{applyOnDelete-CMif2RKw.mjs → applyOnDelete-BXSq3S70.mjs} +23 -12
  23. package/dist/packem_shared/{buildSeekWhere-lVsNXSLy.mjs → applySelect-WQY8m62C.mjs} +21 -2
  24. package/dist/packem_shared/{armRestore-BJk53Ro8.mjs → armRestore-4Px61hHS.mjs} +4 -10
  25. package/dist/packem_shared/{backfillAggregateIndexes-BF5eL7kW.mjs → backfillAggregateIndexes-DDoT-UUI.mjs} +3 -2
  26. package/dist/packem_shared/{compileWhereSql-CXrhFA3G.mjs → compileWhereSql-DE6yfRcQ.mjs} +5 -3
  27. package/dist/packem_shared/constant-time-equal-BVRWZgES.mjs +12 -0
  28. package/dist/packem_shared/{createSystemReader-8CzSZP9V.mjs → createSystemReader-D12eNH13.mjs} +4 -2
  29. package/dist/packem_shared/ctx-db-idempotency-BdcNpvY4.mjs +108 -0
  30. package/dist/packem_shared/ctx-db-shapes-Cz9dHyh1.mjs +53 -0
  31. package/dist/packem_shared/diffExternalSource-Cx9HUPJj.mjs +44 -0
  32. package/dist/packem_shared/{exportShardRows-DZEhUeyI.mjs → exportShardRows-Dy3oFZ26.mjs} +4 -3
  33. package/dist/packem_shared/isSourceDue-CYkt7Ru8.mjs +41 -0
  34. package/dist/packem_shared/json-response-BdbtpOhm.mjs +3 -0
  35. package/dist/packem_shared/materializeExternalRows-CTqZisSC.mjs +23 -0
  36. package/dist/packem_shared/{runShardMigrations-C3bn5r93.mjs → runShardMigrations-BGx4v2B6.mjs} +6 -4
  37. package/dist/packem_shared/serialize-sql-BlRUoiQe.mjs +14 -0
  38. package/dist/packem_shared/{serveRelationFanout-Clr1a05L.mjs → serveRelationFanout-BgaNg3Hu.mjs} +4 -7
  39. package/dist/packem_shared/stableStringify-MydiuScU.mjs +40 -0
  40. package/dist/packem_shared/subscription-delivery-CWigSEr3.mjs +348 -0
  41. package/dist/packem_shared/subscriptionListDeltas-DRLvFlM1.mjs +1 -0
  42. package/package.json +5 -3
  43. package/dist/packem_shared/NotFoundError-CMuMZt81.mjs +0 -10
  44. package/dist/packem_shared/ctx-db-idempotency-DkC9rP91.mjs +0 -35
  45. package/dist/packem_shared/encodePartitionKey-C6blLR5K.mjs +0 -1
  46. /package/dist/packem_shared/{AUTH_METRICS_BUCKET_MS-CiHHYeJi.mjs → AUTH_METRICS_BUCKETS_TABLE-CiHHYeJi.mjs} +0 -0
  47. /package/dist/packem_shared/{ensureFunctionMetricsTables-UDNVD7FS.mjs → FUNCTION_METRICS_BUCKETS_TABLE-UDNVD7FS.mjs} +0 -0
  48. /package/dist/packem_shared/{clearCapturedMail-CPpgl-dX.mjs → MAIL_RETENTION-CPpgl-dX.mjs} +0 -0
  49. /package/dist/packem_shared/{buildSecurityAudit-CCAvoFlr.mjs → MIN_ADMIN_TOKEN_LENGTH-CCAvoFlr.mjs} +0 -0
  50. /package/dist/packem_shared/{ftsTableName-BLEMawrp.mjs → buildFtsMatch-BLEMawrp.mjs} +0 -0
  51. /package/dist/packem_shared/{runTriggers-5N6_Fx0A.mjs → hasTrigger-5N6_Fx0A.mjs} +0 -0
package/dist/index.mjs CHANGED
@@ -1,35 +1,40 @@
1
- export { exportShardRows, exportShardTable, importShardRows, parseExportShardArgs, parseImportShardArgs, selectExportTables, validateImportRow } from './packem_shared/exportShardRows-DZEhUeyI.mjs';
2
- export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, normalizeCountArgument, throwingScheduler } from './packem_shared/matchesStaticWhere-CFk6adSu.mjs';
1
+ export { exportShardRows, exportShardTable, importShardRows, parseExportShardArgs, parseImportShardArgs, selectExportTables, validateImportRow } from './packem_shared/exportShardRows-Dy3oFZ26.mjs';
2
+ export { AGGREGATE_SQL_FUNCTION, aggregateSqlFunction, matchesStaticWhere, normalizeCountArgument, throwingScheduler } from './packem_shared/AGGREGATE_SQL_FUNCTION-CQsu2Xga.mjs';
3
3
  export { aggregateTableName, coerceAggregateNumber, encodeAggregateKey, foldAggregateTally, readAggregateValue } from './packem_shared/aggregateTableName-CxNqY1Sl.mjs';
4
- export { CountRlsUnsupportedError, mergeWhere, planAggregateLookup, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy } from './packem_shared/CountRlsUnsupportedError-28ZvvwKS.mjs';
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_BUCKET_MS-CiHHYeJi.mjs';
6
- export { NotUniqueError, assertValidClientId, createShardCtxDb, normalizeIdStructurally } from './packem_shared/assertValidClientId-CBZ1zC96.mjs';
7
- export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-PTtTiQ7U.mjs';
4
+ export { CountRlsUnsupportedError, mergeWhere, planAggregateLookup, selectIndexForAggregate, selectIndexForCount, selectIndexForGroupBy } from './packem_shared/CountRlsUnsupportedError-BGxj0pgS.mjs';
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-BigrdT_W.mjs';
7
+ export { DATA_MIGRATION_STATE_TABLE, readMigrationStatus, runDataMigration } from './packem_shared/DATA_MIGRATION_STATE_TABLE-CYwBpyTr.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';
10
- 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/ensureFunctionMetricsTables-UDNVD7FS.mjs';
11
- export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, RELATION_FUNCTION_PREFIX, facetColumn, listTables, readTablePage, selectMatchingIds } from './packem_shared/ADMIN_FUNCTION_PREFIX-Dzdqq5J2.mjs';
10
+ export { diffExternalSource } from './packem_shared/diffExternalSource-Cx9HUPJj.mjs';
11
+ export { materializeExternalRows, readExternalSourceBaseline, runExternalSourceTick } from './packem_shared/materializeExternalRows-CTqZisSC.mjs';
12
+ export { isSourceDue, liftSourceId, pullExternalSourceTick } from './packem_shared/isSourceDue-CYkt7Ru8.mjs';
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-CAHLZMj8.mjs';
12
15
  export { LogBuffer } from './packem_shared/LogBuffer-B_Ezju_N.mjs';
13
- export { MAIL_RETENTION, MAIL_TABLE, clearCapturedMail, ensureMailTable, readCapturedMail, recordCapturedMail } from './packem_shared/clearCapturedMail-CPpgl-dX.mjs';
14
- export { default as NotFoundError } from './packem_shared/NotFoundError-CMuMZt81.mjs';
15
- export { armRestore, readBookmark } from './packem_shared/armRestore-BJk53Ro8.mjs';
16
- export { buildSeekWhere, decodeCursor, encodeCursor, normalizeOrderKeys } from './packem_shared/buildSeekWhere-lVsNXSLy.mjs';
17
- export { R as RANK_TIEBREAK, e as encodePartitionKey, m as matchesRankStaticWhere, r as rankTableName, a as resolveRankPartition, s as sortColumnName } from './packem_shared/rank-CrkEIpF4.mjs';
18
- export { ReactiveCache, reactiveCacheKey, stableStringify } from './packem_shared/ReactiveCache-ByVzgH3d.mjs';
19
- export { serveRelationFanout } from './packem_shared/serveRelationFanout-Clr1a05L.mjs';
20
- export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates } from './packem_shared/assertFlatPredicate-DyVYReuT.mjs';
21
- export { applyOnDelete, resolveWith, runRowValidators } from './packem_shared/applyOnDelete-CMif2RKw.mjs';
22
- export { RLS_UNWRAP_SYMBOL, RlsRequiredError, guardWriter } from './packem_shared/guardWriter-u3UlnCH5.mjs';
23
- export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/ftsTableName-BLEMawrp.mjs';
16
+ export { MAIL_RETENTION, MAIL_TABLE, clearCapturedMail, ensureMailTable, readCapturedMail, recordCapturedMail } from './packem_shared/MAIL_RETENTION-CPpgl-dX.mjs';
17
+ export { default as NotFoundError } from './packem_shared/NotFoundError-C70b9hLw.mjs';
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
+ export { RANK_TIEBREAK, encodePartitionKey, matchesRankStaticWhere, rankTableName, resolveRankPartition, sortColumnName } from './packem_shared/RANK_TIEBREAK-CXhdcA1o.mjs';
21
+ export { ReactiveCache, reactiveCacheKey } from './packem_shared/ReactiveCache-BYlSGY0N.mjs';
22
+ export { serveRelationFanout } from './packem_shared/serveRelationFanout-BgaNg3Hu.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-DTvHvRzY.mjs';
26
+ export { buildFtsMatch, ftsTableName, scoreDocument, stringifySearchText, tokenizeSearch } from './packem_shared/buildFtsMatch-BLEMawrp.mjs';
24
27
  export { M as MIN_ADMIN_TOKEN_LENGTH, a as MIN_AUTH_SECRET_LENGTH, b as buildSecurityAudit } from './packem_shared/security-audit-CucgBice.mjs';
25
- export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-ilPZsVwu.mjs';
26
- export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO, subscriptionListDeltas } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-DQkmGiCS.mjs';
27
- export { SHARD_REGISTRY_DO_NAME, ShardRegistryDO } from './packem_shared/SHARD_REGISTRY_DO_NAME-BsAbi5Mn.mjs';
28
- export { MAX_SQL_ROWS, assertReadonly, runReadonlySql } from './packem_shared/assertReadonly-dDcFE1YZ.mjs';
29
- export { createSystemReader } from './packem_shared/createSystemReader-8CzSZP9V.mjs';
30
- export { ConflictError } from './packem_shared/ConflictError-C0STs6bU.mjs';
31
- export { hasTrigger, runTriggers } from './packem_shared/runTriggers-5N6_Fx0A.mjs';
32
- export { compileWhereSql } from './packem_shared/compileWhereSql-CXrhFA3G.mjs';
33
- export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/applyCdcChanges-Ctdmxmrv.mjs';
34
- export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-BF5eL7kW.mjs';
35
- export { runShardMigrations } from './packem_shared/runShardMigrations-C3bn5r93.mjs';
28
+ export { SESSION_DO_TTL_DEFAULT, SessionDO } from './packem_shared/SESSION_DO_TTL_DEFAULT-BnSKgVO4.mjs';
29
+ export { ROOT_DO_SIZE_WARN_BYTES, ROOT_SHARD_NAME, ShardDO } from './packem_shared/ROOT_DO_SIZE_WARN_BYTES-BA8QOChj.mjs';
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-D57CJaT9.mjs';
32
+ export { createSystemReader } from './packem_shared/createSystemReader-D12eNH13.mjs';
33
+ export { ConflictError } from './packem_shared/ConflictError-CLoq37xH.mjs';
34
+ export { hasTrigger, runTriggers } from './packem_shared/hasTrigger-5N6_Fx0A.mjs';
35
+ export { compileWhereSql } from './packem_shared/compileWhereSql-DE6yfRcQ.mjs';
36
+ export { CDC_LOG_TABLE, applyCdcChanges, readCdcChanges, trimCdcChanges } from './packem_shared/CDC_LOG_TABLE-DjJEHiM2.mjs';
37
+ export { backfillAggregateIndexes, backfillRankIndexes } from './packem_shared/backfillAggregateIndexes-DDoT-UUI.mjs';
38
+ export { runShardMigrations } from './packem_shared/runShardMigrations-BGx4v2B6.mjs';
39
+ export { stableStringify } from './packem_shared/stableStringify-MydiuScU.mjs';
40
+ export { s as subscriptionListDeltas } from './packem_shared/subscription-delivery-CWigSEr3.mjs';
@@ -1,9 +1,15 @@
1
+ import { LunoraError } from '@lunora/errors';
2
+
3
+ const quoteIdentifier = (name) => `"${name.replaceAll('"', '""')}"`;
4
+
1
5
  const ADMIN_FUNCTION_PREFIX = "__lunora_admin__:";
2
6
  const RELATION_FUNCTION_PREFIX = "__lunora_relation__:";
7
+ const FLAGS_FUNCTION_PREFIX = "__lunora_flags__:";
3
8
  const ADMIN_FUNCTIONS = {
4
9
  applyCdc: "__lunora_admin__:applyCdc",
5
10
  cdcSync: "__lunora_admin__:cdcSync",
6
11
  clearCapturedMail: "__lunora_admin__:clearCapturedMail",
12
+ clearQueueMessages: "__lunora_admin__:clearQueueMessages",
7
13
  clearTable: "__lunora_admin__:clearTable",
8
14
  createWorkflowInstance: "__lunora_admin__:createWorkflowInstance",
9
15
  deleteRows: "__lunora_admin__:deleteRows",
@@ -15,18 +21,23 @@ const ADMIN_FUNCTIONS = {
15
21
  getAuditLog: "__lunora_admin__:getAuditLog",
16
22
  getAuthMetrics: "__lunora_admin__:getAuthMetrics",
17
23
  getCapturedMail: "__lunora_admin__:getCapturedMail",
24
+ getFanoutMetrics: "__lunora_admin__:getFanoutMetrics",
18
25
  getFunctionStats: "__lunora_admin__:getFunctionStats",
26
+ getIssues: "__lunora_admin__:getIssues",
19
27
  listSubscriptions: "__lunora_admin__:listSubscriptions",
20
28
  listTableIndexes: "__lunora_admin__:listTableIndexes",
21
29
  getLogs: "__lunora_admin__:getLogs",
22
30
  getMetrics: "__lunora_admin__:getMetrics",
23
31
  getPitrBookmark: "__lunora_admin__:getPitrBookmark",
32
+ getQueueMessages: "__lunora_admin__:getQueueMessages",
24
33
  getRequestLog: "__lunora_admin__:getRequestLog",
25
34
  getSecurityAudit: "__lunora_admin__:getSecurityAudit",
26
35
  getSettings: "__lunora_admin__:getSettings",
27
36
  // eslint-disable-next-line no-secrets/no-secrets -- reserved admin RPC path constant, not a credential
28
37
  getWorkflowInstanceStatus: "__lunora_admin__:getWorkflowInstanceStatus",
29
38
  importShard: "__lunora_admin__:importShard",
39
+ listFlags: "__lunora_admin__:listFlags",
40
+ listQueues: "__lunora_admin__:listQueues",
30
41
  listTables: "__lunora_admin__:listTables",
31
42
  listWorkflows: "__lunora_admin__:listWorkflows",
32
43
  maskPolicies: "__lunora_admin__:maskPolicies",
@@ -38,10 +49,13 @@ const ADMIN_FUNCTIONS = {
38
49
  recordAuthEvent: "__lunora_admin__:recordAuthEvent",
39
50
  recordContainerEvent: "__lunora_admin__:recordContainerEvent",
40
51
  recordMail: "__lunora_admin__:recordMail",
52
+ recordQueueMessage: "__lunora_admin__:recordQueueMessage",
53
+ replayQueueMessage: "__lunora_admin__:replayQueueMessage",
41
54
  rlsPolicies: "__lunora_admin__:rlsPolicies",
42
55
  runAs: "__lunora_admin__:runAs",
43
56
  runMigration: "__lunora_admin__:runMigration",
44
57
  runSql: "__lunora_admin__:runSql",
58
+ sendQueueMessage: "__lunora_admin__:sendQueueMessage",
45
59
  sendTestMail: "__lunora_admin__:sendTestMail",
46
60
  storageOrphans: "__lunora_admin__:storageOrphans",
47
61
  storageReferences: "__lunora_admin__:storageReferences",
@@ -91,7 +105,6 @@ const expandDocumentRows = (columns, rows) => {
91
105
  };
92
106
  const escapeLike = (value) => value.replaceAll(/[\\%_]/g, (character) => `\\${character}`);
93
107
  const isInternalTable = (name) => name.startsWith("sqlite_") || name.startsWith("_cf_") || name.startsWith("__miniflare") || name.startsWith("__lunora") || name.includes("__fts_");
94
- const quoteIdentifier = (name) => `"${name.replaceAll('"', '""')}"`;
95
108
  const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
96
109
  const countRows = (sql, quotedTable) => {
97
110
  const row = sql.exec(`SELECT COUNT(*) AS c FROM ${quotedTable}`).one();
@@ -169,7 +182,7 @@ const buildOrderBy = (orderBy, physicalColumns) => {
169
182
  const readTablePage = (sql, options) => {
170
183
  const { table } = options;
171
184
  if (isInternalTable(table) || !tableExists(sql, table)) {
172
- throw Object.assign(new Error(`unknown table: ${table}`), { code: "UNKNOWN_TABLE", name: "LunoraError", status: 404 });
185
+ throw new LunoraError("UNKNOWN_TABLE", `unknown table: ${table}`, { status: 404 });
173
186
  }
174
187
  const limit = clamp(Math.trunc(options.limit ?? DEFAULT_PAGE_SIZE), 1, MAX_PAGE_SIZE);
175
188
  const offset = Math.max(0, Math.trunc(options.offset ?? 0));
@@ -195,14 +208,17 @@ const readTablePage = (sql, options) => {
195
208
  const orderSql = order === void 0 ? "" : ` ORDER BY ${order.sql}`;
196
209
  const whereParams = predicate?.parameters ?? [];
197
210
  const orderParams = order?.params ?? [];
198
- const total = predicate === void 0 ? countRows(sql, quoted) : Number(sql.exec(`SELECT COUNT(*) AS c FROM ${quoted}${whereSql}`, ...whereParams).one().c);
211
+ let total;
212
+ if (!options.skipCount) {
213
+ total = predicate === void 0 ? countRows(sql, quoted) : Number(sql.exec(`SELECT COUNT(*) AS c FROM ${quoted}${whereSql}`, ...whereParams).one().c);
214
+ }
199
215
  const rawRows = sql.exec(`SELECT * FROM ${quoted}${whereSql}${orderSql} LIMIT ? OFFSET ?`, ...whereParams, ...orderParams, limit, offset).toArray();
200
216
  return withReferences({ ...expandDocumentRows(columns, rawRows), total });
201
217
  };
202
218
  const selectMatchingIds = (sql, options) => {
203
219
  const { table } = options;
204
220
  if (isInternalTable(table) || !tableExists(sql, table)) {
205
- throw Object.assign(new Error(`unknown table: ${table}`), { code: "UNKNOWN_TABLE", name: "LunoraError", status: 404 });
221
+ throw new LunoraError("UNKNOWN_TABLE", `unknown table: ${table}`, { status: 404 });
206
222
  }
207
223
  const limit = clamp(Math.trunc(options.limit ?? MAX_PAGE_SIZE), 1, MAX_PAGE_SIZE);
208
224
  const quoted = quoteIdentifier(table);
@@ -233,16 +249,16 @@ const knownDisplayColumns = (sql, quotedTable, physicalColumns) => {
233
249
  const facetColumn = (sql, options) => {
234
250
  const { column, table } = options;
235
251
  if (isInternalTable(table) || !tableExists(sql, table)) {
236
- throw Object.assign(new Error(`unknown table: ${table}`), { code: "UNKNOWN_TABLE", name: "LunoraError", status: 404 });
252
+ throw new LunoraError("UNKNOWN_TABLE", `unknown table: ${table}`, { status: 404 });
237
253
  }
238
254
  const quoted = quoteIdentifier(table);
239
255
  const physicalColumns = sql.exec(`PRAGMA table_info(${quoted})`).toArray().map((info) => info.name);
240
256
  if (!knownDisplayColumns(sql, quoted, physicalColumns).has(column)) {
241
- throw Object.assign(new Error(`unknown column: ${column}`), { code: "UNKNOWN_COLUMN", name: "LunoraError", status: 404 });
257
+ throw new LunoraError("UNKNOWN_COLUMN", `unknown column: ${column}`, { status: 404 });
242
258
  }
243
259
  const resolved = resolveColumnExpression(column, physicalColumns);
244
260
  if (resolved === void 0) {
245
- throw Object.assign(new Error(`unknown column: ${column}`), { code: "UNKNOWN_COLUMN", name: "LunoraError", status: 404 });
261
+ throw new LunoraError("UNKNOWN_COLUMN", `unknown column: ${column}`, { status: 404 });
246
262
  }
247
263
  const limit = clamp(Math.trunc(options.limit ?? DEFAULT_FACET_LIMIT), 1, MAX_FACET_LIMIT);
248
264
  const needle = options.search?.trim() ?? "";
@@ -309,5 +325,43 @@ const summarizeSubscriptions = (attachments) => {
309
325
  const totalSubscriptions = connections.reduce((sum, connection) => sum + connection.subscriptions.length, 0);
310
326
  return { connections, totalConnections: connections.length, totalSubscriptions };
311
327
  };
328
+ const DEFAULT_FANOUT_TOPIC_LIMIT = 20;
329
+ const createFanoutCounters = () => {
330
+ return { maxMs: 0, passes: 0, peakSocketsIterated: 0, socketsDelivered: 0, socketsIterated: 0, totalMs: 0 };
331
+ };
332
+ const recordFanoutPass = (counters, iterated, delivered, ms) => {
333
+ return {
334
+ maxMs: Math.max(counters.maxMs, ms),
335
+ passes: counters.passes + 1,
336
+ peakSocketsIterated: Math.max(counters.peakSocketsIterated, iterated),
337
+ socketsDelivered: counters.socketsDelivered + delivered,
338
+ socketsIterated: counters.socketsIterated + iterated,
339
+ totalMs: counters.totalMs + ms
340
+ };
341
+ };
342
+ const summarizeFanoutTopics = (attachments, limit = DEFAULT_FANOUT_TOPIC_LIMIT) => {
343
+ const shapeCounts = /* @__PURE__ */ new Map();
344
+ const whisperCounts = /* @__PURE__ */ new Map();
345
+ for (const attachment of attachments) {
346
+ for (const shape of Object.values(attachment.shapes ?? {})) {
347
+ const key = shape.name ?? "(unknown shape)";
348
+ shapeCounts.set(key, (shapeCounts.get(key) ?? 0) + 1);
349
+ }
350
+ for (const topic of attachment.whispers ?? []) {
351
+ whisperCounts.set(topic, (whisperCounts.get(topic) ?? 0) + 1);
352
+ }
353
+ }
354
+ const topics = [
355
+ ...[...shapeCounts].map(([topic, subscribers]) => {
356
+ return { kind: "shape", subscribers, topic };
357
+ }),
358
+ ...[...whisperCounts].map(([topic, subscribers]) => {
359
+ return { kind: "whisper", subscribers, topic };
360
+ })
361
+ ];
362
+ topics.sort((a, b) => b.subscribers - a.subscribers || a.topic.localeCompare(b.topic));
363
+ const peakSubscribers = topics[0]?.subscribers ?? 0;
364
+ return { peakSubscribers, topics: topics.slice(0, limit), totalConnections: attachments.length };
365
+ };
312
366
 
313
- export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, MAX_PAGE_SIZE, RELATION_FUNCTION_PREFIX, facetColumn, findStorageReferences, listTables, readTablePage, selectMatchingIds, summarizeSubscriptions };
367
+ export { ADMIN_FUNCTIONS, ADMIN_FUNCTION_PREFIX, DEFAULT_FANOUT_TOPIC_LIMIT, FLAGS_FUNCTION_PREFIX, MAX_PAGE_SIZE, RELATION_FUNCTION_PREFIX, createFanoutCounters, facetColumn, findStorageReferences, listTables, readTablePage, recordFanoutPass, selectMatchingIds, summarizeFanoutTopics, summarizeSubscriptions };
@@ -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) => {
@@ -26,9 +26,13 @@ const appendCdcChange = (sql$1, ts, table, id, op, doc) => {
26
26
  const readCdcChanges = (sql$1, options = {}) => {
27
27
  const sinceSeq = options.sinceSeq ?? 0;
28
28
  const limit = Math.max(1, Math.min(options.limit ?? 1e3, 1e4));
29
+ const tableFilter = options.tables && options.tables.size > 0 ? sql` AND ${sql.identifier("table")} IN (${sql.join(
30
+ [...options.tables].map((table) => sql`${table}`),
31
+ sql`, `
32
+ )})` : sql``;
29
33
  const rows = runDrizzle(
30
34
  sql$1,
31
- sql`SELECT seq, ts, ${sql.identifier("table")}, id, op, doc FROM ${sql.identifier(CDC_LOG_TABLE)} WHERE seq > ${sinceSeq} ORDER BY seq ASC LIMIT ${limit}`
35
+ sql`SELECT seq, ts, ${sql.identifier("table")}, id, op, doc FROM ${sql.identifier(CDC_LOG_TABLE)} WHERE seq > ${sinceSeq}${tableFilter} ORDER BY seq ASC LIMIT ${limit}`
32
36
  ).toArray();
33
37
  const changes = rows.map((row) => {
34
38
  const base = { id: row.id, op: row.op, seq: row.seq, table: row.table, ts: row.ts };
@@ -91,7 +95,7 @@ const applyCdcChange = async (writer, change) => {
91
95
  fields[key] = value;
92
96
  }
93
97
  }
94
- await writer.replace(change.id, fields);
98
+ await writer.replace(change.id, fields, void 0, { allowExplicitId: true });
95
99
  }
96
100
  };
97
101
  const applyCdcChanges = async (writer, changes) => {
@@ -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;
@@ -176,7 +178,9 @@ const runDataMigration = async (options) => {
176
178
  if (next !== void 0) {
177
179
  changed += 1;
178
180
  if (!dryRun) {
179
- await writer.replace(String(document["_id"]), { ...next, _creationTime: document["_creationTime"], _id: document["_id"] });
181
+ await writer.replace(String(document["_id"]), { ...next, _creationTime: document["_creationTime"], _id: document["_id"] }, void 0, {
182
+ allowExplicitId: true
183
+ });
180
184
  }
181
185
  }
182
186
  if (!dryRun) {
@@ -229,7 +233,11 @@ const runDataMigration = async (options) => {
229
233
  throw error;
230
234
  }
231
235
  if (!dryRun && !isDone) {
232
- releaseClaim(sql, migration.id);
236
+ try {
237
+ releaseClaim(sql, migration.id);
238
+ } catch (error) {
239
+ console.warn(`data migration "${migration.id}": releaseClaim failed`, error);
240
+ }
233
241
  }
234
242
  return { changed, cursor: isDone ? null : cursor, direction, dryRun, id: migration.id, processed, status: isDone ? "completed" : "in_progress" };
235
243
  };
@@ -1,4 +1,5 @@
1
- import { distinctValues } from './applyOnDelete-CMif2RKw.mjs';
1
+ import { LunoraError } from '@lunora/errors';
2
+ import { distinctValues } from './applyOnDelete-BXSq3S70.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) => {
@@ -156,5 +158,54 @@ const resolveRelationPredicates = async (where, options) => {
156
158
  schema: options.schema
157
159
  });
158
160
  };
161
+ const firstShardedHit = (branches, schema, tableName) => {
162
+ for (const branch of branches) {
163
+ const hit = findShardedRelationTarget(branch, schema, tableName);
164
+ if (hit) {
165
+ return hit;
166
+ }
167
+ }
168
+ return void 0;
169
+ };
170
+ const inspectKey = (key, value, schema, tableName) => {
171
+ if (key === "AND" || key === "OR") {
172
+ return firstShardedHit(branchesOf(value), schema, tableName);
173
+ }
174
+ if (key === "NOT") {
175
+ return firstShardedHit([value ?? {}], schema, tableName);
176
+ }
177
+ const relation = schema.tables[tableName]?.relationMap?.[key];
178
+ if (!relation || !isRelationPredicate(value)) {
179
+ return void 0;
180
+ }
181
+ if (schema.tables[relation.table]?.shardMode?.kind === "shardBy") {
182
+ return { relation: key, target: relation.table };
183
+ }
184
+ return firstShardedHit(Object.values(value), schema, relation.table);
185
+ };
186
+ const findShardedRelationTarget = (where, schema, tableName) => {
187
+ for (const key of Object.keys(where)) {
188
+ const hit = inspectKey(key, where[key], schema, tableName);
189
+ if (hit) {
190
+ return hit;
191
+ }
192
+ }
193
+ return void 0;
194
+ };
195
+ const assertShapeShardable = (effectiveWhere, schema, table) => {
196
+ if (!effectiveWhere) {
197
+ return;
198
+ }
199
+ const offending = findShardedRelationTarget(effectiveWhere, schema, table);
200
+ if (!offending) {
201
+ return;
202
+ }
203
+ throw Object.assign(
204
+ new Error(
205
+ `shape on "${table}" joins the sharded table "${offending.target}" via relation "${offending.relation}" — a live shape cannot replicate rows that live in another shard's Durable Object. Fix it by (a) denormalizing the joined columns into "${table}", or (b) moving "${offending.target}" to .global() so it is served through the latency-tiered D1 shape tier.`
206
+ ),
207
+ { code: "SHAPE_CROSS_SHARD_JOIN", name: "LunoraError", status: 400 }
208
+ );
209
+ };
159
210
 
160
- export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates };
211
+ export { DEFAULT_MAX_RELATION_KEYS, assertFlatPredicate, assertShapeShardable, containsRelationPredicate, isRelationPredicate, resolveRelationPredicates };
@@ -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) => Object.assign(new Error(message), { code, name: "LunoraError", status: 400 });
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 === "") {
@@ -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 };