@concavejs/cli 0.0.1-alpha.8 → 0.0.1-alpha.9

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.
@@ -24,6 +24,12 @@ function parseDocumentIdKey(key) {
24
24
  const internalId = key.substring(colonIndex + 1);
25
25
  if (!table || !internalId)
26
26
  return null;
27
+ if (table.startsWith("#")) {
28
+ const tableNumber = Number.parseInt(table.slice(1), 10);
29
+ if (Number.isInteger(tableNumber) && tableNumber > 0) {
30
+ return { table, internalId, tableNumber };
31
+ }
32
+ }
27
33
  return { table, internalId };
28
34
  }
29
35
  var Order;
@@ -9103,7 +9109,6 @@ class KernelContext {
9103
9109
  }
9104
9110
  recordTableRead(tableName) {
9105
9111
  if (this.mutationTransaction) {
9106
- this.mutationTransaction.recordTableScan(stringToHex(tableName), []);
9107
9112
  return;
9108
9113
  }
9109
9114
  this.readLog.addTableScan(tableName);
@@ -9116,8 +9121,6 @@ class KernelContext {
9116
9121
  }
9117
9122
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
9118
9123
  if (this.mutationTransaction) {
9119
- const indexId = indexKeyspaceId(tableName, indexDescriptor);
9120
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
9121
9124
  return;
9122
9125
  }
9123
9126
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -9273,11 +9276,12 @@ class BlobStoreGateway {
9273
9276
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
9274
9277
  return;
9275
9278
  }
9276
- await storage2.delete(docId.internalId);
9279
+ const canonicalDocId = latest.value.id;
9280
+ await storage2.delete(canonicalDocId.internalId);
9277
9281
  const timestamp2 = this.docStore.allocateTimestamp();
9278
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
9282
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
9279
9283
  await this.docStore.applyWrites([entry], new Set, "Error");
9280
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
9284
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
9281
9285
  }
9282
9286
  requireStorage() {
9283
9287
  if (!this.storage) {
@@ -9480,16 +9484,17 @@ class SchedulerGateway {
9480
9484
  if (!latest) {
9481
9485
  throw new Error(`Scheduled job with id ${id} not found.`);
9482
9486
  }
9487
+ const canonicalDocId = latest.value.id;
9483
9488
  const newValue = {
9484
9489
  ...latest.value.value,
9485
9490
  state: state ?? { kind: "canceled" }
9486
9491
  };
9487
- const resolvedDocument = { id: docId, value: newValue };
9492
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
9488
9493
  const timestamp2 = this.docStore.allocateTimestamp();
9489
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
9494
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
9490
9495
  await this.docStore.applyWrites([entry], new Set, "Error");
9491
- const tableName = await resolveTableName(docId, this.context.tableRegistry);
9492
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
9496
+ const tableName = await resolveTableName(canonicalDocId, this.context.tableRegistry);
9497
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
9493
9498
  }
9494
9499
  }
9495
9500
  init_context_storage();
@@ -9701,13 +9706,14 @@ class DatabaseSyscalls {
9701
9706
  if (!latest) {
9702
9707
  throw new Error(`Document with id ${id} not found.`);
9703
9708
  }
9709
+ const canonicalDocId = latest.value.id;
9704
9710
  const timestamp2 = this.docStore.allocateTimestamp();
9705
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
9711
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
9706
9712
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
9707
- const indexUpdates = generateIndexUpdates(fullTableName, docId, null, latest.value.value, indexes);
9713
+ const indexUpdates = generateIndexUpdates(fullTableName, canonicalDocId, null, latest.value.value, indexes);
9708
9714
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
9709
9715
  await this.docStore.applyWrites([entry], indexEntries, "Error");
9710
- this.context.recordLocalWrite(id, fullTableName, null, docId);
9716
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
9711
9717
  return {};
9712
9718
  }
9713
9719
  async handleShallowMerge(args) {
@@ -9733,6 +9739,7 @@ class DatabaseSyscalls {
9733
9739
  if (!latest) {
9734
9740
  throw new Error(`Document with id ${id} not found.`);
9735
9741
  }
9742
+ const canonicalDocId = latest.value.id;
9736
9743
  const existingValue = latest.value.value;
9737
9744
  const newValue = { ...existingValue };
9738
9745
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -9759,14 +9766,14 @@ class DatabaseSyscalls {
9759
9766
  }
9760
9767
  }
9761
9768
  await this.schemaService.validate(bareTableName, newValue);
9762
- const resolvedDocument = { id: docId, value: newValue };
9769
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
9763
9770
  const timestamp2 = this.docStore.allocateTimestamp();
9764
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
9771
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
9765
9772
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
9766
- const indexUpdates = generateIndexUpdates(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
9773
+ const indexUpdates = generateIndexUpdates(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
9767
9774
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
9768
9775
  await this.docStore.applyWrites([entry], indexEntries, "Error");
9769
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
9776
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
9770
9777
  return {};
9771
9778
  }
9772
9779
  async handleReplace(args) {
@@ -9788,17 +9795,18 @@ class DatabaseSyscalls {
9788
9795
  if (!latest) {
9789
9796
  throw new Error(`Document with id ${id} not found.`);
9790
9797
  }
9798
+ const canonicalDocId = latest.value.id;
9791
9799
  const { _id, _creationTime } = latest.value.value;
9792
9800
  const newValue = { ...replaceValue, _id, _creationTime };
9793
9801
  await this.schemaService.validate(bareTableName, newValue);
9794
- const resolvedDocument = { id: docId, value: newValue };
9802
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
9795
9803
  const timestamp2 = this.docStore.allocateTimestamp();
9796
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
9804
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
9797
9805
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
9798
- const indexUpdates = generateIndexUpdates(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
9806
+ const indexUpdates = generateIndexUpdates(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
9799
9807
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
9800
9808
  await this.docStore.applyWrites([entry], indexEntries, "Error");
9801
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
9809
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
9802
9810
  return {};
9803
9811
  }
9804
9812
  }
@@ -18124,7 +18132,6 @@ class KernelContext2 {
18124
18132
  }
18125
18133
  recordTableRead(tableName) {
18126
18134
  if (this.mutationTransaction) {
18127
- this.mutationTransaction.recordTableScan(stringToHex2(tableName), []);
18128
18135
  return;
18129
18136
  }
18130
18137
  this.readLog.addTableScan(tableName);
@@ -18137,8 +18144,6 @@ class KernelContext2 {
18137
18144
  }
18138
18145
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
18139
18146
  if (this.mutationTransaction) {
18140
- const indexId = indexKeyspaceId2(tableName, indexDescriptor);
18141
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
18142
18147
  return;
18143
18148
  }
18144
18149
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -18294,11 +18299,12 @@ class BlobStoreGateway2 {
18294
18299
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
18295
18300
  return;
18296
18301
  }
18297
- await storage2.delete(docId.internalId);
18302
+ const canonicalDocId = latest.value.id;
18303
+ await storage2.delete(canonicalDocId.internalId);
18298
18304
  const timestamp = this.docStore.allocateTimestamp();
18299
- const entry = { ts: timestamp, id: docId, value: null, prev_ts: latest.ts };
18305
+ const entry = { ts: timestamp, id: canonicalDocId, value: null, prev_ts: latest.ts };
18300
18306
  await this.docStore.applyWrites([entry], new Set, "Error");
18301
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
18307
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
18302
18308
  }
18303
18309
  requireStorage() {
18304
18310
  if (!this.storage) {
@@ -18501,16 +18507,17 @@ class SchedulerGateway2 {
18501
18507
  if (!latest) {
18502
18508
  throw new Error(`Scheduled job with id ${id} not found.`);
18503
18509
  }
18510
+ const canonicalDocId = latest.value.id;
18504
18511
  const newValue = {
18505
18512
  ...latest.value.value,
18506
18513
  state: state ?? { kind: "canceled" }
18507
18514
  };
18508
- const resolvedDocument = { id: docId, value: newValue };
18515
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
18509
18516
  const timestamp = this.docStore.allocateTimestamp();
18510
- const entry = { ts: timestamp, id: docId, value: resolvedDocument, prev_ts: latest.ts };
18517
+ const entry = { ts: timestamp, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
18511
18518
  await this.docStore.applyWrites([entry], new Set, "Error");
18512
- const tableName = await resolveTableName2(docId, this.context.tableRegistry);
18513
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
18519
+ const tableName = await resolveTableName2(canonicalDocId, this.context.tableRegistry);
18520
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
18514
18521
  }
18515
18522
  }
18516
18523
 
@@ -18712,13 +18719,14 @@ class DatabaseSyscalls2 {
18712
18719
  if (!latest) {
18713
18720
  throw new Error(`Document with id ${id} not found.`);
18714
18721
  }
18722
+ const canonicalDocId = latest.value.id;
18715
18723
  const timestamp = this.docStore.allocateTimestamp();
18716
- const entry = { ts: timestamp, id: docId, value: null, prev_ts: latest.ts };
18724
+ const entry = { ts: timestamp, id: canonicalDocId, value: null, prev_ts: latest.ts };
18717
18725
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
18718
- const indexUpdates = generateIndexUpdates2(fullTableName, docId, null, latest.value.value, indexes);
18726
+ const indexUpdates = generateIndexUpdates2(fullTableName, canonicalDocId, null, latest.value.value, indexes);
18719
18727
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp, update })));
18720
18728
  await this.docStore.applyWrites([entry], indexEntries, "Error");
18721
- this.context.recordLocalWrite(id, fullTableName, null, docId);
18729
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
18722
18730
  return {};
18723
18731
  }
18724
18732
  async handleShallowMerge(args) {
@@ -18744,6 +18752,7 @@ class DatabaseSyscalls2 {
18744
18752
  if (!latest) {
18745
18753
  throw new Error(`Document with id ${id} not found.`);
18746
18754
  }
18755
+ const canonicalDocId = latest.value.id;
18747
18756
  const existingValue = latest.value.value;
18748
18757
  const newValue = { ...existingValue };
18749
18758
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -18770,14 +18779,14 @@ class DatabaseSyscalls2 {
18770
18779
  }
18771
18780
  }
18772
18781
  await this.schemaService.validate(bareTableName, newValue);
18773
- const resolvedDocument = { id: docId, value: newValue };
18782
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
18774
18783
  const timestamp = this.docStore.allocateTimestamp();
18775
- const entry = { ts: timestamp, id: docId, value: resolvedDocument, prev_ts: latest.ts };
18784
+ const entry = { ts: timestamp, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
18776
18785
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
18777
- const indexUpdates = generateIndexUpdates2(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
18786
+ const indexUpdates = generateIndexUpdates2(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
18778
18787
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp, update })));
18779
18788
  await this.docStore.applyWrites([entry], indexEntries, "Error");
18780
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
18789
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
18781
18790
  return {};
18782
18791
  }
18783
18792
  async handleReplace(args) {
@@ -18799,17 +18808,18 @@ class DatabaseSyscalls2 {
18799
18808
  if (!latest) {
18800
18809
  throw new Error(`Document with id ${id} not found.`);
18801
18810
  }
18811
+ const canonicalDocId = latest.value.id;
18802
18812
  const { _id, _creationTime } = latest.value.value;
18803
18813
  const newValue = { ...replaceValue, _id, _creationTime };
18804
18814
  await this.schemaService.validate(bareTableName, newValue);
18805
- const resolvedDocument = { id: docId, value: newValue };
18815
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
18806
18816
  const timestamp = this.docStore.allocateTimestamp();
18807
- const entry = { ts: timestamp, id: docId, value: resolvedDocument, prev_ts: latest.ts };
18817
+ const entry = { ts: timestamp, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
18808
18818
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
18809
- const indexUpdates = generateIndexUpdates2(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
18819
+ const indexUpdates = generateIndexUpdates2(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
18810
18820
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp, update })));
18811
18821
  await this.docStore.applyWrites([entry], indexEntries, "Error");
18812
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
18822
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
18813
18823
  return {};
18814
18824
  }
18815
18825
  }
@@ -19494,6 +19504,7 @@ class SyncProtocolHandler {
19494
19504
  rateLimitWindowMs;
19495
19505
  operationTimeoutMs;
19496
19506
  maxActiveQueriesPerSession;
19507
+ lastObservedWriteTimestamp = 0n;
19497
19508
  constructor(instanceName, udfExecutor, options) {
19498
19509
  this.udfExecutor = udfExecutor;
19499
19510
  this.instanceName = instanceName;
@@ -19517,6 +19528,22 @@ class SyncProtocolHandler {
19517
19528
  onPing: (session) => this.sendPing(session)
19518
19529
  });
19519
19530
  }
19531
+ resolveWriteTimestamp(commitTimestamp, snapshotTimestamp) {
19532
+ const wallClock = BigInt(Date.now());
19533
+ const monotonicFloor = this.lastObservedWriteTimestamp + 1n;
19534
+ let resolved = wallClock;
19535
+ if (commitTimestamp !== undefined && commitTimestamp > resolved) {
19536
+ resolved = commitTimestamp;
19537
+ }
19538
+ if (snapshotTimestamp !== undefined && snapshotTimestamp > resolved) {
19539
+ resolved = snapshotTimestamp;
19540
+ }
19541
+ if (monotonicFloor > resolved) {
19542
+ resolved = monotonicFloor;
19543
+ }
19544
+ this.lastObservedWriteTimestamp = resolved;
19545
+ return resolved;
19546
+ }
19520
19547
  createSession(sessionId, websocket) {
19521
19548
  const session = new SyncSession(websocket);
19522
19549
  this.sessions.set(sessionId, session);
@@ -19599,11 +19626,11 @@ class SyncProtocolHandler {
19599
19626
  return assertNever(message2);
19600
19627
  }
19601
19628
  }
19602
- async notifyWrites(writtenRanges, writtenTables, commitTimestamp) {
19629
+ async notifyWrites(writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp) {
19603
19630
  const ranges = writtenRanges ? writtenRanges.map(deserializeKeyRange2) : convertTablesToRanges(writtenTables);
19604
19631
  this.logRanges("/notify", ranges, { writtenTables });
19605
19632
  if (ranges.length > 0) {
19606
- const ts = commitTimestamp ?? BigInt(Date.now());
19633
+ const ts = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
19607
19634
  this.subscriptionManager.recordWrites(ranges, ts);
19608
19635
  await this.broadcastUpdates(ranges);
19609
19636
  }
@@ -19701,8 +19728,8 @@ class SyncProtocolHandler {
19701
19728
  if (message2.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
19702
19729
  throw new Error("Only admin or system auth can execute component functions");
19703
19730
  }
19704
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeMutation(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
19705
- const now = commitTimestamp ?? BigInt(Date.now());
19731
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeMutation(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
19732
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
19706
19733
  const successResponse = {
19707
19734
  type: "MutationResponse",
19708
19735
  requestId: message2.requestId,
@@ -19747,8 +19774,8 @@ class SyncProtocolHandler {
19747
19774
  if (message2.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
19748
19775
  throw new Error("Only admin or system auth can mutate component functions");
19749
19776
  }
19750
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeAction(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
19751
- const now = commitTimestamp ?? BigInt(Date.now());
19777
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeAction(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
19778
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
19752
19779
  const successResponse = {
19753
19780
  type: "ActionResponse",
19754
19781
  requestId: message2.requestId,
@@ -20104,7 +20131,8 @@ function createSyncUdfExecutor(adapter) {
20104
20131
  writtenRanges: result.writtenRanges,
20105
20132
  writtenTables: writtenTablesFromRanges(result.writtenRanges),
20106
20133
  logLines: result.logLines,
20107
- commitTimestamp: result.commitTimestamp
20134
+ commitTimestamp: result.commitTimestamp,
20135
+ snapshotTimestamp: result.snapshotTimestamp
20108
20136
  };
20109
20137
  },
20110
20138
  executeAction: async (path, args, auth, componentPath) => {
@@ -20122,7 +20150,8 @@ function createSyncUdfExecutor(adapter) {
20122
20150
  writtenRanges: result.writtenRanges,
20123
20151
  writtenTables: writtenTablesFromRanges(result.writtenRanges),
20124
20152
  logLines: result.logLines,
20125
- commitTimestamp: result.commitTimestamp
20153
+ commitTimestamp: result.commitTimestamp,
20154
+ snapshotTimestamp: result.snapshotTimestamp
20126
20155
  };
20127
20156
  }
20128
20157
  };
@@ -23636,7 +23665,7 @@ function rangeExpressionsToIndexBounds(expressions, indexFields) {
23636
23665
  }
23637
23666
  return { start, end };
23638
23667
  }
23639
- async function executeIndexQuery(docstore, tableName, indexName, indexFields, expressions, order, limit, cursor, snapshotTimestamp) {
23668
+ async function executeIndexQuery(docstore, tableName, indexName, indexFields, expressions, order, limit, cursor, snapshotTimestamp, onDocumentRead) {
23640
23669
  const tableId = stringToHex3(tableName);
23641
23670
  const indexId = stringToHex3(`${tableName}:${indexName}`);
23642
23671
  const indexOrder = order === "asc" ? Order.Asc : Order.Desc;
@@ -23662,6 +23691,7 @@ async function executeIndexQuery(docstore, tableName, indexName, indexFields, ex
23662
23691
  try {
23663
23692
  const generator = docstore.index_scan(indexId, tableId, readTimestamp, interval, indexOrder);
23664
23693
  for await (const [indexKey, document] of generator) {
23694
+ onDocumentRead?.(document);
23665
23695
  const doc = document.value.value;
23666
23696
  if (skipping) {
23667
23697
  if (resumeIndexKey) {
@@ -24091,6 +24121,9 @@ class UncommittedWrites {
24091
24121
  }
24092
24122
  }
24093
24123
  }
24124
+ // ../core/dist/query/query-runtime.js
24125
+ init_interface();
24126
+
24094
24127
  // ../core/dist/query/planner.js
24095
24128
  init_values3();
24096
24129
  init_interface4();
@@ -24460,13 +24493,27 @@ class QueryRuntime {
24460
24493
  return paginateByCursor(sortedResults, cursor, limit);
24461
24494
  }
24462
24495
  async handleIndexRange(plan, cursor, limit) {
24463
- if (!this.docStore.hasTransaction()) {
24464
- const { start, end } = rangeExpressionsToIndexBounds(plan.expressions, plan.indexFields);
24496
+ const { start, end } = rangeExpressionsToIndexBounds(plan.expressions, plan.indexFields);
24497
+ const mutationTransaction = this.docStore.getTransaction();
24498
+ if (!mutationTransaction) {
24465
24499
  this.context.recordIndexRange(plan.fullTableName, plan.indexDescriptor, start, end);
24466
24500
  }
24501
+ const observedDocuments = mutationTransaction ? new Map : null;
24467
24502
  let paginationResult;
24468
24503
  try {
24469
- const indexResult = await executeIndexQuery(this.docStore.getDocStore(), plan.fullTableName, plan.indexDescriptor, plan.indexFields, plan.expressions, plan.order, limit, cursor, this.context.snapshotTimestamp);
24504
+ const indexResult = await executeIndexQuery(this.docStore.getDocStore(), plan.fullTableName, plan.indexDescriptor, plan.indexFields, plan.expressions, plan.order, limit, cursor, this.context.snapshotTimestamp, (latestDoc) => {
24505
+ if (!observedDocuments) {
24506
+ return;
24507
+ }
24508
+ observedDocuments.set(documentIdKey(latestDoc.value.id), latestDoc);
24509
+ });
24510
+ if (mutationTransaction && observedDocuments) {
24511
+ const observed = Array.from(observedDocuments.values());
24512
+ mutationTransaction.recordIndexRangeScan(indexKeyspaceId3(plan.fullTableName, plan.indexDescriptor), start, end, observed);
24513
+ for (const doc of observed) {
24514
+ mutationTransaction.recordDocumentRead(doc.value.id, doc);
24515
+ }
24516
+ }
24470
24517
  const uncommittedWrites = UncommittedWrites.fromContext(this.docStore.getTransaction(), this.context.getLocalWrites());
24471
24518
  if (uncommittedWrites) {
24472
24519
  const tableId = stringToHex3(plan.fullTableName);
@@ -24499,7 +24546,10 @@ class QueryRuntime {
24499
24546
  return paginationResult;
24500
24547
  }
24501
24548
  async handleSearch(plan, _cursor, limit) {
24502
- this.context.recordTableRead(plan.fullTableName);
24549
+ const mutationTransaction = this.docStore.getTransaction();
24550
+ if (!mutationTransaction) {
24551
+ this.context.recordTableRead(plan.fullTableName);
24552
+ }
24503
24553
  const limitOperator = plan.query.operators?.find((operator) => ("limit" in operator));
24504
24554
  const operatorLimit = limitOperator?.limit;
24505
24555
  const combinedLimit = typeof limit === "number" && limit > 0 ? operatorLimit && operatorLimit > 0 ? Math.min(limit, operatorLimit) : limit : operatorLimit && operatorLimit > 0 ? operatorLimit : undefined;
@@ -24508,7 +24558,13 @@ class QueryRuntime {
24508
24558
  throw new Error("DocStore does not support full-text search");
24509
24559
  }
24510
24560
  const searchResults = await rawDocStore.search(plan.indexIdHex, plan.searchTerm, plan.filterMap, { limit: combinedLimit });
24511
- const documents = searchResults.filter(({ doc }) => doc.ts <= this.context.snapshotTimestamp).map(({ doc, score }) => ({
24561
+ const visibleResults = searchResults.filter(({ doc }) => doc.ts <= this.context.snapshotTimestamp);
24562
+ if (mutationTransaction) {
24563
+ for (const { doc } of visibleResults) {
24564
+ mutationTransaction.recordDocumentRead(doc.value.id, doc);
24565
+ }
24566
+ }
24567
+ const documents = visibleResults.map(({ doc, score }) => ({
24512
24568
  ...doc.value.value,
24513
24569
  _score: score
24514
24570
  }));
@@ -24695,6 +24751,7 @@ class AccessLog3 {
24695
24751
  return this.ranges.getRanges().map(serializeKeyRange3);
24696
24752
  }
24697
24753
  }
24754
+
24698
24755
  // ../core/dist/tables/memory-table-registry.js
24699
24756
  init_interface4();
24700
24757
 
@@ -24832,7 +24889,6 @@ class KernelContext3 {
24832
24889
  }
24833
24890
  recordTableRead(tableName) {
24834
24891
  if (this.mutationTransaction) {
24835
- this.mutationTransaction.recordTableScan(stringToHex3(tableName), []);
24836
24892
  return;
24837
24893
  }
24838
24894
  this.readLog.addTableScan(tableName);
@@ -24845,8 +24901,6 @@ class KernelContext3 {
24845
24901
  }
24846
24902
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
24847
24903
  if (this.mutationTransaction) {
24848
- const indexId = indexKeyspaceId3(tableName, indexDescriptor);
24849
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
24850
24904
  return;
24851
24905
  }
24852
24906
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -25005,11 +25059,12 @@ class BlobStoreGateway3 {
25005
25059
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
25006
25060
  return;
25007
25061
  }
25008
- await storage2.delete(docId.internalId);
25062
+ const canonicalDocId = latest.value.id;
25063
+ await storage2.delete(canonicalDocId.internalId);
25009
25064
  const timestamp2 = this.docStore.allocateTimestamp();
25010
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
25065
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
25011
25066
  await this.docStore.applyWrites([entry], new Set, "Error");
25012
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
25067
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
25013
25068
  }
25014
25069
  requireStorage() {
25015
25070
  if (!this.storage) {
@@ -25216,16 +25271,17 @@ class SchedulerGateway3 {
25216
25271
  if (!latest) {
25217
25272
  throw new Error(`Scheduled job with id ${id} not found.`);
25218
25273
  }
25274
+ const canonicalDocId = latest.value.id;
25219
25275
  const newValue = {
25220
25276
  ...latest.value.value,
25221
25277
  state: state ?? { kind: "canceled" }
25222
25278
  };
25223
- const resolvedDocument = { id: docId, value: newValue };
25279
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
25224
25280
  const timestamp2 = this.docStore.allocateTimestamp();
25225
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
25281
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
25226
25282
  await this.docStore.applyWrites([entry], new Set, "Error");
25227
- const tableName = await resolveTableName3(docId, this.context.tableRegistry);
25228
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
25283
+ const tableName = await resolveTableName3(canonicalDocId, this.context.tableRegistry);
25284
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
25229
25285
  }
25230
25286
  }
25231
25287
 
@@ -25449,13 +25505,14 @@ class DatabaseSyscalls3 {
25449
25505
  if (!latest) {
25450
25506
  throw new Error(`Document with id ${id} not found.`);
25451
25507
  }
25508
+ const canonicalDocId = latest.value.id;
25452
25509
  const timestamp2 = this.docStore.allocateTimestamp();
25453
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
25510
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
25454
25511
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
25455
- const indexUpdates = generateIndexUpdates3(fullTableName, docId, null, latest.value.value, indexes);
25512
+ const indexUpdates = generateIndexUpdates3(fullTableName, canonicalDocId, null, latest.value.value, indexes);
25456
25513
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
25457
25514
  await this.docStore.applyWrites([entry], indexEntries, "Error");
25458
- this.context.recordLocalWrite(id, fullTableName, null, docId);
25515
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
25459
25516
  return {};
25460
25517
  }
25461
25518
  async handleShallowMerge(args) {
@@ -25481,6 +25538,7 @@ class DatabaseSyscalls3 {
25481
25538
  if (!latest) {
25482
25539
  throw new Error(`Document with id ${id} not found.`);
25483
25540
  }
25541
+ const canonicalDocId = latest.value.id;
25484
25542
  const existingValue = latest.value.value;
25485
25543
  const newValue = { ...existingValue };
25486
25544
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -25507,14 +25565,14 @@ class DatabaseSyscalls3 {
25507
25565
  }
25508
25566
  }
25509
25567
  await this.schemaService.validate(bareTableName, newValue);
25510
- const resolvedDocument = { id: docId, value: newValue };
25568
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
25511
25569
  const timestamp2 = this.docStore.allocateTimestamp();
25512
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
25570
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
25513
25571
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
25514
- const indexUpdates = generateIndexUpdates3(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
25572
+ const indexUpdates = generateIndexUpdates3(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
25515
25573
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
25516
25574
  await this.docStore.applyWrites([entry], indexEntries, "Error");
25517
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
25575
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
25518
25576
  return {};
25519
25577
  }
25520
25578
  async handleReplace(args) {
@@ -25536,17 +25594,18 @@ class DatabaseSyscalls3 {
25536
25594
  if (!latest) {
25537
25595
  throw new Error(`Document with id ${id} not found.`);
25538
25596
  }
25597
+ const canonicalDocId = latest.value.id;
25539
25598
  const { _id, _creationTime } = latest.value.value;
25540
25599
  const newValue = { ...replaceValue, _id, _creationTime };
25541
25600
  await this.schemaService.validate(bareTableName, newValue);
25542
- const resolvedDocument = { id: docId, value: newValue };
25601
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
25543
25602
  const timestamp2 = this.docStore.allocateTimestamp();
25544
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
25603
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
25545
25604
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
25546
- const indexUpdates = generateIndexUpdates3(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
25605
+ const indexUpdates = generateIndexUpdates3(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
25547
25606
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
25548
25607
  await this.docStore.applyWrites([entry], indexEntries, "Error");
25549
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
25608
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
25550
25609
  return {};
25551
25610
  }
25552
25611
  }
@@ -25941,7 +26000,7 @@ async function validateReadSetForCommit(docstore, readChecks, writtenDocKeys) {
25941
26000
  await validateTableScanRead(docstore, readEntry.tableId, readEntry.documentIds, writtenDocKeys);
25942
26001
  continue;
25943
26002
  }
25944
- await validateIndexRangeRead(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.documentIds, writtenDocKeys);
26003
+ await validateIndexRangeRead(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.readTimestamp, readEntry.documentIds, writtenDocKeys);
25945
26004
  }
25946
26005
  }
25947
26006
  async function validateDocumentRead(docstore, key, readVersion, writtenDocKeys) {
@@ -25985,11 +26044,12 @@ async function validateTableScanRead(docstore, tableId, readDocumentIds, written
25985
26044
  }
25986
26045
  }
25987
26046
  }
25988
- async function validateIndexRangeRead(docstore, indexId, startKey, endKey, readDocumentIds, writtenDocKeys) {
26047
+ async function validateIndexRangeRead(docstore, indexId, startKey, endKey, readTimestamp, readDocumentIds, writtenDocKeys) {
25989
26048
  const { table } = decodeIndexId3(indexId);
25990
26049
  const interval = { start: startKey, end: endKey };
26050
+ const validationReadTimestamp = resolveValidationReadTimestamp(docstore, readTimestamp);
25991
26051
  const currentDocIds = new Set;
25992
- for await (const [, doc] of docstore.index_scan(indexId, table, BigInt(Date.now()), interval, Order.Asc)) {
26052
+ for await (const [, doc] of docstore.index_scan(indexId, table, validationReadTimestamp, interval, Order.Asc)) {
25993
26053
  currentDocIds.add(documentIdKey(doc.value.id));
25994
26054
  }
25995
26055
  for (const docId of currentDocIds) {
@@ -26003,6 +26063,13 @@ async function validateIndexRangeRead(docstore, indexId, startKey, endKey, readD
26003
26063
  }
26004
26064
  }
26005
26065
  }
26066
+ function resolveValidationReadTimestamp(docstore, minimumTimestamp) {
26067
+ const maybeDocStore = docstore;
26068
+ const oracleTimestamp = maybeDocStore.timestampOracle?.getCurrentTimestamp?.();
26069
+ const wallClockTimestamp = BigInt(Date.now());
26070
+ const latestKnownTimestamp = oracleTimestamp !== undefined && oracleTimestamp > wallClockTimestamp ? oracleTimestamp : wallClockTimestamp;
26071
+ return latestKnownTimestamp > minimumTimestamp ? latestKnownTimestamp : minimumTimestamp;
26072
+ }
26006
26073
 
26007
26074
  // ../core/dist/transactor/occ-transaction.js
26008
26075
  class OccMutationTransaction {
@@ -26573,7 +26640,7 @@ function runUdfMutation(docstore, fn, auth, storage2, requestId, udfExecutor, co
26573
26640
  const savepoint = parentTransaction.createSavepoint();
26574
26641
  const existingIdGenerator = idGeneratorContext3.getStore();
26575
26642
  const idGenerator = existingIdGenerator ?? createDeterministicIdGenerator(seed);
26576
- const nestedResult = transactionContext3.run(parentTransaction, () => idGeneratorContext3.run(idGenerator, () => runUdfAndGetLogs(docstore, fn, ops, auth, "mutation", storage2, seed, parentTransaction, udfExecutor, componentPath)));
26643
+ const nestedResult = Promise.resolve(transactionContext3.run(parentTransaction, () => idGeneratorContext3.run(idGenerator, () => runUdfAndGetLogs(docstore, fn, ops, auth, "mutation", storage2, seed, parentTransaction, udfExecutor, componentPath))));
26577
26644
  return nestedResult.catch((error) => {
26578
26645
  parentTransaction.restoreSavepoint(savepoint);
26579
26646
  throw error;
@@ -26719,10 +26786,15 @@ class InlineUdfExecutor {
26719
26786
  async executeHttp(request, auth, requestId) {
26720
26787
  const url = new URL(request.url);
26721
26788
  const runHttpUdf = async () => {
26722
- const httpModule = await this.loadModule("http");
26789
+ let httpModule;
26790
+ try {
26791
+ httpModule = await this.loadModule("http");
26792
+ } catch {
26793
+ return new Response("Not found", { status: 404 });
26794
+ }
26723
26795
  const router = httpModule?.default;
26724
26796
  if (!router?.isRouter || typeof router.lookup !== "function") {
26725
- throw new Error("convex/http.ts must export a default httpRouter()");
26797
+ return new Response("Not found", { status: 404 });
26726
26798
  }
26727
26799
  const match = router.lookup(url.pathname, request.method);
26728
26800
  if (!match) {
@@ -27157,6 +27229,9 @@ class HttpHandler {
27157
27229
  if (url.pathname === "/health") {
27158
27230
  return apply(Response.json({ status: "ok", runtime: this.runtimeName }));
27159
27231
  }
27232
+ if (!isReservedApiPath(url.pathname)) {
27233
+ return forwardHttpRequest(request, "HTTP action");
27234
+ }
27160
27235
  return apply(Response.json({ error: "Not found" }, { status: 404 }));
27161
27236
  }
27162
27237
  }
@@ -31330,6 +31405,12 @@ function parseDocumentIdKey2(key) {
31330
31405
  const internalId = key.substring(colonIndex + 1);
31331
31406
  if (!table || !internalId)
31332
31407
  return null;
31408
+ if (table.startsWith("#")) {
31409
+ const tableNumber = Number.parseInt(table.slice(1), 10);
31410
+ if (Number.isInteger(tableNumber) && tableNumber > 0) {
31411
+ return { table, internalId, tableNumber };
31412
+ }
31413
+ }
31333
31414
  return { table, internalId };
31334
31415
  }
31335
31416
  var Order4;
@@ -31842,7 +31923,7 @@ async function validateReadSetForCommit2(docstore, readChecks, writtenDocKeys) {
31842
31923
  await validateTableScanRead2(docstore, readEntry.tableId, readEntry.documentIds, writtenDocKeys);
31843
31924
  continue;
31844
31925
  }
31845
- await validateIndexRangeRead2(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.documentIds, writtenDocKeys);
31926
+ await validateIndexRangeRead2(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.readTimestamp, readEntry.documentIds, writtenDocKeys);
31846
31927
  }
31847
31928
  }
31848
31929
  async function validateDocumentRead2(docstore, key, readVersion, writtenDocKeys) {
@@ -31886,11 +31967,12 @@ async function validateTableScanRead2(docstore, tableId, readDocumentIds, writte
31886
31967
  }
31887
31968
  }
31888
31969
  }
31889
- async function validateIndexRangeRead2(docstore, indexId, startKey, endKey, readDocumentIds, writtenDocKeys) {
31970
+ async function validateIndexRangeRead2(docstore, indexId, startKey, endKey, readTimestamp, readDocumentIds, writtenDocKeys) {
31890
31971
  const { table } = decodeIndexId4(indexId);
31891
31972
  const interval = { start: startKey, end: endKey };
31973
+ const validationReadTimestamp = resolveValidationReadTimestamp2(docstore, readTimestamp);
31892
31974
  const currentDocIds = new Set;
31893
- for await (const [, doc] of docstore.index_scan(indexId, table, BigInt(Date.now()), interval, Order4.Asc)) {
31975
+ for await (const [, doc] of docstore.index_scan(indexId, table, validationReadTimestamp, interval, Order4.Asc)) {
31894
31976
  currentDocIds.add(documentIdKey3(doc.value.id));
31895
31977
  }
31896
31978
  for (const docId of currentDocIds) {
@@ -31904,6 +31986,13 @@ async function validateIndexRangeRead2(docstore, indexId, startKey, endKey, read
31904
31986
  }
31905
31987
  }
31906
31988
  }
31989
+ function resolveValidationReadTimestamp2(docstore, minimumTimestamp) {
31990
+ const maybeDocStore = docstore;
31991
+ const oracleTimestamp = maybeDocStore.timestampOracle?.getCurrentTimestamp?.();
31992
+ const wallClockTimestamp = BigInt(Date.now());
31993
+ const latestKnownTimestamp = oracleTimestamp !== undefined && oracleTimestamp > wallClockTimestamp ? oracleTimestamp : wallClockTimestamp;
31994
+ return latestKnownTimestamp > minimumTimestamp ? latestKnownTimestamp : minimumTimestamp;
31995
+ }
31907
31996
 
31908
31997
  class OccMutationTransaction2 {
31909
31998
  docstore;
@@ -32508,7 +32597,6 @@ class KernelContext4 {
32508
32597
  }
32509
32598
  recordTableRead(tableName) {
32510
32599
  if (this.mutationTransaction) {
32511
- this.mutationTransaction.recordTableScan(stringToHex4(tableName), []);
32512
32600
  return;
32513
32601
  }
32514
32602
  this.readLog.addTableScan(tableName);
@@ -32521,8 +32609,6 @@ class KernelContext4 {
32521
32609
  }
32522
32610
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
32523
32611
  if (this.mutationTransaction) {
32524
- const indexId = indexKeyspaceId4(tableName, indexDescriptor);
32525
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
32526
32612
  return;
32527
32613
  }
32528
32614
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -32678,11 +32764,12 @@ class BlobStoreGateway4 {
32678
32764
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
32679
32765
  return;
32680
32766
  }
32681
- await storage2.delete(docId.internalId);
32767
+ const canonicalDocId = latest.value.id;
32768
+ await storage2.delete(canonicalDocId.internalId);
32682
32769
  const timestamp2 = this.docStore.allocateTimestamp();
32683
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
32770
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
32684
32771
  await this.docStore.applyWrites([entry], new Set, "Error");
32685
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
32772
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
32686
32773
  }
32687
32774
  requireStorage() {
32688
32775
  if (!this.storage) {
@@ -32885,16 +32972,17 @@ class SchedulerGateway4 {
32885
32972
  if (!latest) {
32886
32973
  throw new Error(`Scheduled job with id ${id} not found.`);
32887
32974
  }
32975
+ const canonicalDocId = latest.value.id;
32888
32976
  const newValue = {
32889
32977
  ...latest.value.value,
32890
32978
  state: state ?? { kind: "canceled" }
32891
32979
  };
32892
- const resolvedDocument = { id: docId, value: newValue };
32980
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
32893
32981
  const timestamp2 = this.docStore.allocateTimestamp();
32894
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
32982
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
32895
32983
  await this.docStore.applyWrites([entry], new Set, "Error");
32896
- const tableName = await resolveTableName4(docId, this.context.tableRegistry);
32897
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
32984
+ const tableName = await resolveTableName4(canonicalDocId, this.context.tableRegistry);
32985
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
32898
32986
  }
32899
32987
  }
32900
32988
  init_context_storage4();
@@ -33106,13 +33194,14 @@ class DatabaseSyscalls4 {
33106
33194
  if (!latest) {
33107
33195
  throw new Error(`Document with id ${id} not found.`);
33108
33196
  }
33197
+ const canonicalDocId = latest.value.id;
33109
33198
  const timestamp2 = this.docStore.allocateTimestamp();
33110
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
33199
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
33111
33200
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
33112
- const indexUpdates = generateIndexUpdates4(fullTableName, docId, null, latest.value.value, indexes);
33201
+ const indexUpdates = generateIndexUpdates4(fullTableName, canonicalDocId, null, latest.value.value, indexes);
33113
33202
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
33114
33203
  await this.docStore.applyWrites([entry], indexEntries, "Error");
33115
- this.context.recordLocalWrite(id, fullTableName, null, docId);
33204
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
33116
33205
  return {};
33117
33206
  }
33118
33207
  async handleShallowMerge(args) {
@@ -33138,6 +33227,7 @@ class DatabaseSyscalls4 {
33138
33227
  if (!latest) {
33139
33228
  throw new Error(`Document with id ${id} not found.`);
33140
33229
  }
33230
+ const canonicalDocId = latest.value.id;
33141
33231
  const existingValue = latest.value.value;
33142
33232
  const newValue = { ...existingValue };
33143
33233
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -33164,14 +33254,14 @@ class DatabaseSyscalls4 {
33164
33254
  }
33165
33255
  }
33166
33256
  await this.schemaService.validate(bareTableName, newValue);
33167
- const resolvedDocument = { id: docId, value: newValue };
33257
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
33168
33258
  const timestamp2 = this.docStore.allocateTimestamp();
33169
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
33259
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
33170
33260
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
33171
- const indexUpdates = generateIndexUpdates4(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
33261
+ const indexUpdates = generateIndexUpdates4(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
33172
33262
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
33173
33263
  await this.docStore.applyWrites([entry], indexEntries, "Error");
33174
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
33264
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
33175
33265
  return {};
33176
33266
  }
33177
33267
  async handleReplace(args) {
@@ -33193,17 +33283,18 @@ class DatabaseSyscalls4 {
33193
33283
  if (!latest) {
33194
33284
  throw new Error(`Document with id ${id} not found.`);
33195
33285
  }
33286
+ const canonicalDocId = latest.value.id;
33196
33287
  const { _id, _creationTime } = latest.value.value;
33197
33288
  const newValue = { ...replaceValue, _id, _creationTime };
33198
33289
  await this.schemaService.validate(bareTableName, newValue);
33199
- const resolvedDocument = { id: docId, value: newValue };
33290
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
33200
33291
  const timestamp2 = this.docStore.allocateTimestamp();
33201
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
33292
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
33202
33293
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
33203
- const indexUpdates = generateIndexUpdates4(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
33294
+ const indexUpdates = generateIndexUpdates4(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
33204
33295
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
33205
33296
  await this.docStore.applyWrites([entry], indexEntries, "Error");
33206
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
33297
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
33207
33298
  return {};
33208
33299
  }
33209
33300
  }
@@ -38710,6 +38801,12 @@ function parseDocumentIdKey3(key) {
38710
38801
  const internalId = key.substring(colonIndex + 1);
38711
38802
  if (!table || !internalId)
38712
38803
  return null;
38804
+ if (table.startsWith("#")) {
38805
+ const tableNumber = Number.parseInt(table.slice(1), 10);
38806
+ if (Number.isInteger(tableNumber) && tableNumber > 0) {
38807
+ return { table, internalId, tableNumber };
38808
+ }
38809
+ }
38713
38810
  return { table, internalId };
38714
38811
  }
38715
38812
  var Order5;
@@ -39219,7 +39316,7 @@ async function validateReadSetForCommit3(docstore, readChecks, writtenDocKeys) {
39219
39316
  await validateTableScanRead3(docstore, readEntry.tableId, readEntry.documentIds, writtenDocKeys);
39220
39317
  continue;
39221
39318
  }
39222
- await validateIndexRangeRead3(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.documentIds, writtenDocKeys);
39319
+ await validateIndexRangeRead3(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.readTimestamp, readEntry.documentIds, writtenDocKeys);
39223
39320
  }
39224
39321
  }
39225
39322
  async function validateDocumentRead3(docstore, key, readVersion, writtenDocKeys) {
@@ -39263,11 +39360,12 @@ async function validateTableScanRead3(docstore, tableId, readDocumentIds, writte
39263
39360
  }
39264
39361
  }
39265
39362
  }
39266
- async function validateIndexRangeRead3(docstore, indexId, startKey, endKey, readDocumentIds, writtenDocKeys) {
39363
+ async function validateIndexRangeRead3(docstore, indexId, startKey, endKey, readTimestamp, readDocumentIds, writtenDocKeys) {
39267
39364
  const { table } = decodeIndexId5(indexId);
39268
39365
  const interval = { start: startKey, end: endKey };
39366
+ const validationReadTimestamp = resolveValidationReadTimestamp3(docstore, readTimestamp);
39269
39367
  const currentDocIds = new Set;
39270
- for await (const [, doc] of docstore.index_scan(indexId, table, BigInt(Date.now()), interval, Order5.Asc)) {
39368
+ for await (const [, doc] of docstore.index_scan(indexId, table, validationReadTimestamp, interval, Order5.Asc)) {
39271
39369
  currentDocIds.add(documentIdKey4(doc.value.id));
39272
39370
  }
39273
39371
  for (const docId of currentDocIds) {
@@ -39281,6 +39379,13 @@ async function validateIndexRangeRead3(docstore, indexId, startKey, endKey, read
39281
39379
  }
39282
39380
  }
39283
39381
  }
39382
+ function resolveValidationReadTimestamp3(docstore, minimumTimestamp) {
39383
+ const maybeDocStore = docstore;
39384
+ const oracleTimestamp = maybeDocStore.timestampOracle?.getCurrentTimestamp?.();
39385
+ const wallClockTimestamp = BigInt(Date.now());
39386
+ const latestKnownTimestamp = oracleTimestamp !== undefined && oracleTimestamp > wallClockTimestamp ? oracleTimestamp : wallClockTimestamp;
39387
+ return latestKnownTimestamp > minimumTimestamp ? latestKnownTimestamp : minimumTimestamp;
39388
+ }
39284
39389
 
39285
39390
  class OccMutationTransaction3 {
39286
39391
  docstore;
@@ -39885,7 +39990,6 @@ class KernelContext5 {
39885
39990
  }
39886
39991
  recordTableRead(tableName) {
39887
39992
  if (this.mutationTransaction) {
39888
- this.mutationTransaction.recordTableScan(stringToHex5(tableName), []);
39889
39993
  return;
39890
39994
  }
39891
39995
  this.readLog.addTableScan(tableName);
@@ -39898,8 +40002,6 @@ class KernelContext5 {
39898
40002
  }
39899
40003
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
39900
40004
  if (this.mutationTransaction) {
39901
- const indexId = indexKeyspaceId5(tableName, indexDescriptor);
39902
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
39903
40005
  return;
39904
40006
  }
39905
40007
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -40055,11 +40157,12 @@ class BlobStoreGateway5 {
40055
40157
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
40056
40158
  return;
40057
40159
  }
40058
- await storage2.delete(docId.internalId);
40160
+ const canonicalDocId = latest.value.id;
40161
+ await storage2.delete(canonicalDocId.internalId);
40059
40162
  const timestamp2 = this.docStore.allocateTimestamp();
40060
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
40163
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
40061
40164
  await this.docStore.applyWrites([entry], new Set, "Error");
40062
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
40165
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
40063
40166
  }
40064
40167
  requireStorage() {
40065
40168
  if (!this.storage) {
@@ -40262,16 +40365,17 @@ class SchedulerGateway5 {
40262
40365
  if (!latest) {
40263
40366
  throw new Error(`Scheduled job with id ${id} not found.`);
40264
40367
  }
40368
+ const canonicalDocId = latest.value.id;
40265
40369
  const newValue = {
40266
40370
  ...latest.value.value,
40267
40371
  state: state ?? { kind: "canceled" }
40268
40372
  };
40269
- const resolvedDocument = { id: docId, value: newValue };
40373
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
40270
40374
  const timestamp2 = this.docStore.allocateTimestamp();
40271
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
40375
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
40272
40376
  await this.docStore.applyWrites([entry], new Set, "Error");
40273
- const tableName = await resolveTableName5(docId, this.context.tableRegistry);
40274
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
40377
+ const tableName = await resolveTableName5(canonicalDocId, this.context.tableRegistry);
40378
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
40275
40379
  }
40276
40380
  }
40277
40381
  init_context_storage5();
@@ -40482,13 +40586,14 @@ class DatabaseSyscalls5 {
40482
40586
  if (!latest) {
40483
40587
  throw new Error(`Document with id ${id} not found.`);
40484
40588
  }
40589
+ const canonicalDocId = latest.value.id;
40485
40590
  const timestamp2 = this.docStore.allocateTimestamp();
40486
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
40591
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
40487
40592
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
40488
- const indexUpdates = generateIndexUpdates5(fullTableName, docId, null, latest.value.value, indexes);
40593
+ const indexUpdates = generateIndexUpdates5(fullTableName, canonicalDocId, null, latest.value.value, indexes);
40489
40594
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
40490
40595
  await this.docStore.applyWrites([entry], indexEntries, "Error");
40491
- this.context.recordLocalWrite(id, fullTableName, null, docId);
40596
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
40492
40597
  return {};
40493
40598
  }
40494
40599
  async handleShallowMerge(args) {
@@ -40514,6 +40619,7 @@ class DatabaseSyscalls5 {
40514
40619
  if (!latest) {
40515
40620
  throw new Error(`Document with id ${id} not found.`);
40516
40621
  }
40622
+ const canonicalDocId = latest.value.id;
40517
40623
  const existingValue = latest.value.value;
40518
40624
  const newValue = { ...existingValue };
40519
40625
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -40540,14 +40646,14 @@ class DatabaseSyscalls5 {
40540
40646
  }
40541
40647
  }
40542
40648
  await this.schemaService.validate(bareTableName, newValue);
40543
- const resolvedDocument = { id: docId, value: newValue };
40649
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
40544
40650
  const timestamp2 = this.docStore.allocateTimestamp();
40545
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
40651
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
40546
40652
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
40547
- const indexUpdates = generateIndexUpdates5(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
40653
+ const indexUpdates = generateIndexUpdates5(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
40548
40654
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
40549
40655
  await this.docStore.applyWrites([entry], indexEntries, "Error");
40550
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
40656
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
40551
40657
  return {};
40552
40658
  }
40553
40659
  async handleReplace(args) {
@@ -40569,17 +40675,18 @@ class DatabaseSyscalls5 {
40569
40675
  if (!latest) {
40570
40676
  throw new Error(`Document with id ${id} not found.`);
40571
40677
  }
40678
+ const canonicalDocId = latest.value.id;
40572
40679
  const { _id, _creationTime } = latest.value.value;
40573
40680
  const newValue = { ...replaceValue, _id, _creationTime };
40574
40681
  await this.schemaService.validate(bareTableName, newValue);
40575
- const resolvedDocument = { id: docId, value: newValue };
40682
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
40576
40683
  const timestamp2 = this.docStore.allocateTimestamp();
40577
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
40684
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
40578
40685
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
40579
- const indexUpdates = generateIndexUpdates5(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
40686
+ const indexUpdates = generateIndexUpdates5(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
40580
40687
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
40581
40688
  await this.docStore.applyWrites([entry], indexEntries, "Error");
40582
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
40689
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
40583
40690
  return {};
40584
40691
  }
40585
40692
  }
@@ -43681,6 +43788,7 @@ class SyncProtocolHandler2 {
43681
43788
  rateLimitWindowMs;
43682
43789
  operationTimeoutMs;
43683
43790
  maxActiveQueriesPerSession;
43791
+ lastObservedWriteTimestamp = 0n;
43684
43792
  constructor(instanceName, udfExecutor, options) {
43685
43793
  this.udfExecutor = udfExecutor;
43686
43794
  this.instanceName = instanceName;
@@ -43704,6 +43812,22 @@ class SyncProtocolHandler2 {
43704
43812
  onPing: (session) => this.sendPing(session)
43705
43813
  });
43706
43814
  }
43815
+ resolveWriteTimestamp(commitTimestamp, snapshotTimestamp) {
43816
+ const wallClock = BigInt(Date.now());
43817
+ const monotonicFloor = this.lastObservedWriteTimestamp + 1n;
43818
+ let resolved = wallClock;
43819
+ if (commitTimestamp !== undefined && commitTimestamp > resolved) {
43820
+ resolved = commitTimestamp;
43821
+ }
43822
+ if (snapshotTimestamp !== undefined && snapshotTimestamp > resolved) {
43823
+ resolved = snapshotTimestamp;
43824
+ }
43825
+ if (monotonicFloor > resolved) {
43826
+ resolved = monotonicFloor;
43827
+ }
43828
+ this.lastObservedWriteTimestamp = resolved;
43829
+ return resolved;
43830
+ }
43707
43831
  createSession(sessionId, websocket) {
43708
43832
  const session = new SyncSession2(websocket);
43709
43833
  this.sessions.set(sessionId, session);
@@ -43786,11 +43910,11 @@ class SyncProtocolHandler2 {
43786
43910
  return assertNever2(message22);
43787
43911
  }
43788
43912
  }
43789
- async notifyWrites(writtenRanges, writtenTables, commitTimestamp) {
43913
+ async notifyWrites(writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp) {
43790
43914
  const ranges = writtenRanges ? writtenRanges.map(deserializeKeyRange5) : convertTablesToRanges2(writtenTables);
43791
43915
  this.logRanges("/notify", ranges, { writtenTables });
43792
43916
  if (ranges.length > 0) {
43793
- const ts = commitTimestamp ?? BigInt(Date.now());
43917
+ const ts = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
43794
43918
  this.subscriptionManager.recordWrites(ranges, ts);
43795
43919
  await this.broadcastUpdates(ranges);
43796
43920
  }
@@ -43888,8 +44012,8 @@ class SyncProtocolHandler2 {
43888
44012
  if (message22.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
43889
44013
  throw new Error("Only admin or system auth can execute component functions");
43890
44014
  }
43891
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeMutation(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
43892
- const now = commitTimestamp ?? BigInt(Date.now());
44015
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeMutation(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
44016
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
43893
44017
  const successResponse = {
43894
44018
  type: "MutationResponse",
43895
44019
  requestId: message22.requestId,
@@ -43934,8 +44058,8 @@ class SyncProtocolHandler2 {
43934
44058
  if (message22.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
43935
44059
  throw new Error("Only admin or system auth can mutate component functions");
43936
44060
  }
43937
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeAction(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
43938
- const now = commitTimestamp ?? BigInt(Date.now());
44061
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeAction(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
44062
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
43939
44063
  const successResponse = {
43940
44064
  type: "ActionResponse",
43941
44065
  requestId: message22.requestId,