@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.
@@ -2872,6 +2872,12 @@ function parseDocumentIdKey(key) {
2872
2872
  const internalId = key.substring(colonIndex + 1);
2873
2873
  if (!table || !internalId)
2874
2874
  return null;
2875
+ if (table.startsWith("#")) {
2876
+ const tableNumber = Number.parseInt(table.slice(1), 10);
2877
+ if (Number.isInteger(tableNumber) && tableNumber > 0) {
2878
+ return { table, internalId, tableNumber };
2879
+ }
2880
+ }
2875
2881
  return { table, internalId };
2876
2882
  }
2877
2883
  var Order;
@@ -10655,7 +10661,6 @@ class KernelContext5 {
10655
10661
  }
10656
10662
  recordTableRead(tableName) {
10657
10663
  if (this.mutationTransaction) {
10658
- this.mutationTransaction.recordTableScan(stringToHex5(tableName), []);
10659
10664
  return;
10660
10665
  }
10661
10666
  this.readLog.addTableScan(tableName);
@@ -10668,8 +10673,6 @@ class KernelContext5 {
10668
10673
  }
10669
10674
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
10670
10675
  if (this.mutationTransaction) {
10671
- const indexId = indexKeyspaceId5(tableName, indexDescriptor);
10672
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
10673
10676
  return;
10674
10677
  }
10675
10678
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -10821,11 +10824,12 @@ class BlobStoreGateway5 {
10821
10824
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
10822
10825
  return;
10823
10826
  }
10824
- await storage2.delete(docId.internalId);
10827
+ const canonicalDocId = latest.value.id;
10828
+ await storage2.delete(canonicalDocId.internalId);
10825
10829
  const timestamp22 = this.docStore.allocateTimestamp();
10826
- const entry = { ts: timestamp22, id: docId, value: null, prev_ts: latest.ts };
10830
+ const entry = { ts: timestamp22, id: canonicalDocId, value: null, prev_ts: latest.ts };
10827
10831
  await this.docStore.applyWrites([entry], new Set, "Error");
10828
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
10832
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
10829
10833
  }
10830
10834
  requireStorage() {
10831
10835
  if (!this.storage) {
@@ -11026,16 +11030,17 @@ class SchedulerGateway5 {
11026
11030
  if (!latest) {
11027
11031
  throw new Error(`Scheduled job with id ${id} not found.`);
11028
11032
  }
11033
+ const canonicalDocId = latest.value.id;
11029
11034
  const newValue = {
11030
11035
  ...latest.value.value,
11031
11036
  state: state ?? { kind: "canceled" }
11032
11037
  };
11033
- const resolvedDocument = { id: docId, value: newValue };
11038
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
11034
11039
  const timestamp22 = this.docStore.allocateTimestamp();
11035
- const entry = { ts: timestamp22, id: docId, value: resolvedDocument, prev_ts: latest.ts };
11040
+ const entry = { ts: timestamp22, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
11036
11041
  await this.docStore.applyWrites([entry], new Set, "Error");
11037
- const tableName = await resolveTableName5(docId, this.context.tableRegistry);
11038
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
11042
+ const tableName = await resolveTableName5(canonicalDocId, this.context.tableRegistry);
11043
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
11039
11044
  }
11040
11045
  }
11041
11046
  async function runAsServerCall5(fn, functionPath) {
@@ -11238,13 +11243,14 @@ class DatabaseSyscalls5 {
11238
11243
  if (!latest) {
11239
11244
  throw new Error(`Document with id ${id} not found.`);
11240
11245
  }
11246
+ const canonicalDocId = latest.value.id;
11241
11247
  const timestamp22 = this.docStore.allocateTimestamp();
11242
- const entry = { ts: timestamp22, id: docId, value: null, prev_ts: latest.ts };
11248
+ const entry = { ts: timestamp22, id: canonicalDocId, value: null, prev_ts: latest.ts };
11243
11249
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
11244
- const indexUpdates = generateIndexUpdates5(fullTableName, docId, null, latest.value.value, indexes);
11250
+ const indexUpdates = generateIndexUpdates5(fullTableName, canonicalDocId, null, latest.value.value, indexes);
11245
11251
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp22, update })));
11246
11252
  await this.docStore.applyWrites([entry], indexEntries, "Error");
11247
- this.context.recordLocalWrite(id, fullTableName, null, docId);
11253
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
11248
11254
  return {};
11249
11255
  }
11250
11256
  async handleShallowMerge(args) {
@@ -11270,6 +11276,7 @@ class DatabaseSyscalls5 {
11270
11276
  if (!latest) {
11271
11277
  throw new Error(`Document with id ${id} not found.`);
11272
11278
  }
11279
+ const canonicalDocId = latest.value.id;
11273
11280
  const existingValue = latest.value.value;
11274
11281
  const newValue = { ...existingValue };
11275
11282
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -11296,14 +11303,14 @@ class DatabaseSyscalls5 {
11296
11303
  }
11297
11304
  }
11298
11305
  await this.schemaService.validate(bareTableName, newValue);
11299
- const resolvedDocument = { id: docId, value: newValue };
11306
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
11300
11307
  const timestamp22 = this.docStore.allocateTimestamp();
11301
- const entry = { ts: timestamp22, id: docId, value: resolvedDocument, prev_ts: latest.ts };
11308
+ const entry = { ts: timestamp22, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
11302
11309
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
11303
- const indexUpdates = generateIndexUpdates5(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
11310
+ const indexUpdates = generateIndexUpdates5(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
11304
11311
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp22, update })));
11305
11312
  await this.docStore.applyWrites([entry], indexEntries, "Error");
11306
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
11313
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
11307
11314
  return {};
11308
11315
  }
11309
11316
  async handleReplace(args) {
@@ -11325,17 +11332,18 @@ class DatabaseSyscalls5 {
11325
11332
  if (!latest) {
11326
11333
  throw new Error(`Document with id ${id} not found.`);
11327
11334
  }
11335
+ const canonicalDocId = latest.value.id;
11328
11336
  const { _id, _creationTime } = latest.value.value;
11329
11337
  const newValue = { ...replaceValue, _id, _creationTime };
11330
11338
  await this.schemaService.validate(bareTableName, newValue);
11331
- const resolvedDocument = { id: docId, value: newValue };
11339
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
11332
11340
  const timestamp22 = this.docStore.allocateTimestamp();
11333
- const entry = { ts: timestamp22, id: docId, value: resolvedDocument, prev_ts: latest.ts };
11341
+ const entry = { ts: timestamp22, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
11334
11342
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
11335
- const indexUpdates = generateIndexUpdates5(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
11343
+ const indexUpdates = generateIndexUpdates5(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
11336
11344
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp22, update })));
11337
11345
  await this.docStore.applyWrites([entry], indexEntries, "Error");
11338
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
11346
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
11339
11347
  return {};
11340
11348
  }
11341
11349
  }
@@ -20920,7 +20928,6 @@ class KernelContext {
20920
20928
  }
20921
20929
  recordTableRead(tableName) {
20922
20930
  if (this.mutationTransaction) {
20923
- this.mutationTransaction.recordTableScan(stringToHex(tableName), []);
20924
20931
  return;
20925
20932
  }
20926
20933
  this.readLog.addTableScan(tableName);
@@ -20933,8 +20940,6 @@ class KernelContext {
20933
20940
  }
20934
20941
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
20935
20942
  if (this.mutationTransaction) {
20936
- const indexId = indexKeyspaceId(tableName, indexDescriptor);
20937
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
20938
20943
  return;
20939
20944
  }
20940
20945
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -21090,11 +21095,12 @@ class BlobStoreGateway {
21090
21095
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
21091
21096
  return;
21092
21097
  }
21093
- await storage2.delete(docId.internalId);
21098
+ const canonicalDocId = latest.value.id;
21099
+ await storage2.delete(canonicalDocId.internalId);
21094
21100
  const timestamp = this.docStore.allocateTimestamp();
21095
- const entry = { ts: timestamp, id: docId, value: null, prev_ts: latest.ts };
21101
+ const entry = { ts: timestamp, id: canonicalDocId, value: null, prev_ts: latest.ts };
21096
21102
  await this.docStore.applyWrites([entry], new Set, "Error");
21097
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
21103
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
21098
21104
  }
21099
21105
  requireStorage() {
21100
21106
  if (!this.storage) {
@@ -21297,16 +21303,17 @@ class SchedulerGateway {
21297
21303
  if (!latest) {
21298
21304
  throw new Error(`Scheduled job with id ${id} not found.`);
21299
21305
  }
21306
+ const canonicalDocId = latest.value.id;
21300
21307
  const newValue = {
21301
21308
  ...latest.value.value,
21302
21309
  state: state ?? { kind: "canceled" }
21303
21310
  };
21304
- const resolvedDocument = { id: docId, value: newValue };
21311
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
21305
21312
  const timestamp = this.docStore.allocateTimestamp();
21306
- const entry = { ts: timestamp, id: docId, value: resolvedDocument, prev_ts: latest.ts };
21313
+ const entry = { ts: timestamp, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
21307
21314
  await this.docStore.applyWrites([entry], new Set, "Error");
21308
- const tableName = await resolveTableName(docId, this.context.tableRegistry);
21309
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
21315
+ const tableName = await resolveTableName(canonicalDocId, this.context.tableRegistry);
21316
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
21310
21317
  }
21311
21318
  }
21312
21319
 
@@ -21508,13 +21515,14 @@ class DatabaseSyscalls {
21508
21515
  if (!latest) {
21509
21516
  throw new Error(`Document with id ${id} not found.`);
21510
21517
  }
21518
+ const canonicalDocId = latest.value.id;
21511
21519
  const timestamp = this.docStore.allocateTimestamp();
21512
- const entry = { ts: timestamp, id: docId, value: null, prev_ts: latest.ts };
21520
+ const entry = { ts: timestamp, id: canonicalDocId, value: null, prev_ts: latest.ts };
21513
21521
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
21514
- const indexUpdates = generateIndexUpdates(fullTableName, docId, null, latest.value.value, indexes);
21522
+ const indexUpdates = generateIndexUpdates(fullTableName, canonicalDocId, null, latest.value.value, indexes);
21515
21523
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp, update })));
21516
21524
  await this.docStore.applyWrites([entry], indexEntries, "Error");
21517
- this.context.recordLocalWrite(id, fullTableName, null, docId);
21525
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
21518
21526
  return {};
21519
21527
  }
21520
21528
  async handleShallowMerge(args) {
@@ -21540,6 +21548,7 @@ class DatabaseSyscalls {
21540
21548
  if (!latest) {
21541
21549
  throw new Error(`Document with id ${id} not found.`);
21542
21550
  }
21551
+ const canonicalDocId = latest.value.id;
21543
21552
  const existingValue = latest.value.value;
21544
21553
  const newValue = { ...existingValue };
21545
21554
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -21566,14 +21575,14 @@ class DatabaseSyscalls {
21566
21575
  }
21567
21576
  }
21568
21577
  await this.schemaService.validate(bareTableName, newValue);
21569
- const resolvedDocument = { id: docId, value: newValue };
21578
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
21570
21579
  const timestamp = this.docStore.allocateTimestamp();
21571
- const entry = { ts: timestamp, id: docId, value: resolvedDocument, prev_ts: latest.ts };
21580
+ const entry = { ts: timestamp, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
21572
21581
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
21573
- const indexUpdates = generateIndexUpdates(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
21582
+ const indexUpdates = generateIndexUpdates(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
21574
21583
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp, update })));
21575
21584
  await this.docStore.applyWrites([entry], indexEntries, "Error");
21576
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
21585
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
21577
21586
  return {};
21578
21587
  }
21579
21588
  async handleReplace(args) {
@@ -21595,17 +21604,18 @@ class DatabaseSyscalls {
21595
21604
  if (!latest) {
21596
21605
  throw new Error(`Document with id ${id} not found.`);
21597
21606
  }
21607
+ const canonicalDocId = latest.value.id;
21598
21608
  const { _id, _creationTime } = latest.value.value;
21599
21609
  const newValue = { ...replaceValue, _id, _creationTime };
21600
21610
  await this.schemaService.validate(bareTableName, newValue);
21601
- const resolvedDocument = { id: docId, value: newValue };
21611
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
21602
21612
  const timestamp = this.docStore.allocateTimestamp();
21603
- const entry = { ts: timestamp, id: docId, value: resolvedDocument, prev_ts: latest.ts };
21613
+ const entry = { ts: timestamp, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
21604
21614
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
21605
- const indexUpdates = generateIndexUpdates(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
21615
+ const indexUpdates = generateIndexUpdates(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
21606
21616
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp, update })));
21607
21617
  await this.docStore.applyWrites([entry], indexEntries, "Error");
21608
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
21618
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
21609
21619
  return {};
21610
21620
  }
21611
21621
  }
@@ -22290,6 +22300,7 @@ class SyncProtocolHandler {
22290
22300
  rateLimitWindowMs;
22291
22301
  operationTimeoutMs;
22292
22302
  maxActiveQueriesPerSession;
22303
+ lastObservedWriteTimestamp = 0n;
22293
22304
  constructor(instanceName, udfExecutor, options) {
22294
22305
  this.udfExecutor = udfExecutor;
22295
22306
  this.instanceName = instanceName;
@@ -22313,6 +22324,22 @@ class SyncProtocolHandler {
22313
22324
  onPing: (session) => this.sendPing(session)
22314
22325
  });
22315
22326
  }
22327
+ resolveWriteTimestamp(commitTimestamp, snapshotTimestamp) {
22328
+ const wallClock = BigInt(Date.now());
22329
+ const monotonicFloor = this.lastObservedWriteTimestamp + 1n;
22330
+ let resolved = wallClock;
22331
+ if (commitTimestamp !== undefined && commitTimestamp > resolved) {
22332
+ resolved = commitTimestamp;
22333
+ }
22334
+ if (snapshotTimestamp !== undefined && snapshotTimestamp > resolved) {
22335
+ resolved = snapshotTimestamp;
22336
+ }
22337
+ if (monotonicFloor > resolved) {
22338
+ resolved = monotonicFloor;
22339
+ }
22340
+ this.lastObservedWriteTimestamp = resolved;
22341
+ return resolved;
22342
+ }
22316
22343
  createSession(sessionId, websocket) {
22317
22344
  const session = new SyncSession(websocket);
22318
22345
  this.sessions.set(sessionId, session);
@@ -22395,11 +22422,11 @@ class SyncProtocolHandler {
22395
22422
  return assertNever(message2);
22396
22423
  }
22397
22424
  }
22398
- async notifyWrites(writtenRanges, writtenTables, commitTimestamp) {
22425
+ async notifyWrites(writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp) {
22399
22426
  const ranges = writtenRanges ? writtenRanges.map(deserializeKeyRange) : convertTablesToRanges(writtenTables);
22400
22427
  this.logRanges("/notify", ranges, { writtenTables });
22401
22428
  if (ranges.length > 0) {
22402
- const ts = commitTimestamp ?? BigInt(Date.now());
22429
+ const ts = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
22403
22430
  this.subscriptionManager.recordWrites(ranges, ts);
22404
22431
  await this.broadcastUpdates(ranges);
22405
22432
  }
@@ -22497,8 +22524,8 @@ class SyncProtocolHandler {
22497
22524
  if (message2.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
22498
22525
  throw new Error("Only admin or system auth can execute component functions");
22499
22526
  }
22500
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeMutation(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
22501
- const now = commitTimestamp ?? BigInt(Date.now());
22527
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeMutation(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
22528
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
22502
22529
  const successResponse = {
22503
22530
  type: "MutationResponse",
22504
22531
  requestId: message2.requestId,
@@ -22543,8 +22570,8 @@ class SyncProtocolHandler {
22543
22570
  if (message2.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
22544
22571
  throw new Error("Only admin or system auth can mutate component functions");
22545
22572
  }
22546
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeAction(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
22547
- const now = commitTimestamp ?? BigInt(Date.now());
22573
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeAction(message2.udfPath, message2.args[0] ?? {}, session.auth, message2.componentPath);
22574
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
22548
22575
  const successResponse = {
22549
22576
  type: "ActionResponse",
22550
22577
  requestId: message2.requestId,
@@ -22900,7 +22927,8 @@ function createSyncUdfExecutor(adapter) {
22900
22927
  writtenRanges: result.writtenRanges,
22901
22928
  writtenTables: writtenTablesFromRanges(result.writtenRanges),
22902
22929
  logLines: result.logLines,
22903
- commitTimestamp: result.commitTimestamp
22930
+ commitTimestamp: result.commitTimestamp,
22931
+ snapshotTimestamp: result.snapshotTimestamp
22904
22932
  };
22905
22933
  },
22906
22934
  executeAction: async (path, args, auth, componentPath) => {
@@ -22918,7 +22946,8 @@ function createSyncUdfExecutor(adapter) {
22918
22946
  writtenRanges: result.writtenRanges,
22919
22947
  writtenTables: writtenTablesFromRanges(result.writtenRanges),
22920
22948
  logLines: result.logLines,
22921
- commitTimestamp: result.commitTimestamp
22949
+ commitTimestamp: result.commitTimestamp,
22950
+ snapshotTimestamp: result.snapshotTimestamp
22922
22951
  };
22923
22952
  }
22924
22953
  };
@@ -26426,7 +26455,7 @@ function rangeExpressionsToIndexBounds(expressions, indexFields) {
26426
26455
  }
26427
26456
  return { start, end };
26428
26457
  }
26429
- async function executeIndexQuery(docstore, tableName, indexName, indexFields, expressions, order, limit, cursor, snapshotTimestamp) {
26458
+ async function executeIndexQuery(docstore, tableName, indexName, indexFields, expressions, order, limit, cursor, snapshotTimestamp, onDocumentRead) {
26430
26459
  const tableId = stringToHex2(tableName);
26431
26460
  const indexId = stringToHex2(`${tableName}:${indexName}`);
26432
26461
  const indexOrder = order === "asc" ? Order.Asc : Order.Desc;
@@ -26452,6 +26481,7 @@ async function executeIndexQuery(docstore, tableName, indexName, indexFields, ex
26452
26481
  try {
26453
26482
  const generator = docstore.index_scan(indexId, tableId, readTimestamp, interval, indexOrder);
26454
26483
  for await (const [indexKey, document] of generator) {
26484
+ onDocumentRead?.(document);
26455
26485
  const doc = document.value.value;
26456
26486
  if (skipping) {
26457
26487
  if (resumeIndexKey) {
@@ -26881,6 +26911,9 @@ class UncommittedWrites {
26881
26911
  }
26882
26912
  }
26883
26913
  }
26914
+ // ../core/dist/query/query-runtime.js
26915
+ init_interface();
26916
+
26884
26917
  // ../core/dist/query/planner.js
26885
26918
  init_values2();
26886
26919
  init_interface3();
@@ -27250,13 +27283,27 @@ class QueryRuntime {
27250
27283
  return paginateByCursor(sortedResults, cursor, limit);
27251
27284
  }
27252
27285
  async handleIndexRange(plan, cursor, limit) {
27253
- if (!this.docStore.hasTransaction()) {
27254
- const { start, end } = rangeExpressionsToIndexBounds(plan.expressions, plan.indexFields);
27286
+ const { start, end } = rangeExpressionsToIndexBounds(plan.expressions, plan.indexFields);
27287
+ const mutationTransaction = this.docStore.getTransaction();
27288
+ if (!mutationTransaction) {
27255
27289
  this.context.recordIndexRange(plan.fullTableName, plan.indexDescriptor, start, end);
27256
27290
  }
27291
+ const observedDocuments = mutationTransaction ? new Map : null;
27257
27292
  let paginationResult;
27258
27293
  try {
27259
- const indexResult = await executeIndexQuery(this.docStore.getDocStore(), plan.fullTableName, plan.indexDescriptor, plan.indexFields, plan.expressions, plan.order, limit, cursor, this.context.snapshotTimestamp);
27294
+ const indexResult = await executeIndexQuery(this.docStore.getDocStore(), plan.fullTableName, plan.indexDescriptor, plan.indexFields, plan.expressions, plan.order, limit, cursor, this.context.snapshotTimestamp, (latestDoc) => {
27295
+ if (!observedDocuments) {
27296
+ return;
27297
+ }
27298
+ observedDocuments.set(documentIdKey(latestDoc.value.id), latestDoc);
27299
+ });
27300
+ if (mutationTransaction && observedDocuments) {
27301
+ const observed = Array.from(observedDocuments.values());
27302
+ mutationTransaction.recordIndexRangeScan(indexKeyspaceId2(plan.fullTableName, plan.indexDescriptor), start, end, observed);
27303
+ for (const doc of observed) {
27304
+ mutationTransaction.recordDocumentRead(doc.value.id, doc);
27305
+ }
27306
+ }
27260
27307
  const uncommittedWrites = UncommittedWrites.fromContext(this.docStore.getTransaction(), this.context.getLocalWrites());
27261
27308
  if (uncommittedWrites) {
27262
27309
  const tableId = stringToHex2(plan.fullTableName);
@@ -27289,7 +27336,10 @@ class QueryRuntime {
27289
27336
  return paginationResult;
27290
27337
  }
27291
27338
  async handleSearch(plan, _cursor, limit) {
27292
- this.context.recordTableRead(plan.fullTableName);
27339
+ const mutationTransaction = this.docStore.getTransaction();
27340
+ if (!mutationTransaction) {
27341
+ this.context.recordTableRead(plan.fullTableName);
27342
+ }
27293
27343
  const limitOperator = plan.query.operators?.find((operator) => ("limit" in operator));
27294
27344
  const operatorLimit = limitOperator?.limit;
27295
27345
  const combinedLimit = typeof limit === "number" && limit > 0 ? operatorLimit && operatorLimit > 0 ? Math.min(limit, operatorLimit) : limit : operatorLimit && operatorLimit > 0 ? operatorLimit : undefined;
@@ -27298,7 +27348,13 @@ class QueryRuntime {
27298
27348
  throw new Error("DocStore does not support full-text search");
27299
27349
  }
27300
27350
  const searchResults = await rawDocStore.search(plan.indexIdHex, plan.searchTerm, plan.filterMap, { limit: combinedLimit });
27301
- const documents = searchResults.filter(({ doc }) => doc.ts <= this.context.snapshotTimestamp).map(({ doc, score }) => ({
27351
+ const visibleResults = searchResults.filter(({ doc }) => doc.ts <= this.context.snapshotTimestamp);
27352
+ if (mutationTransaction) {
27353
+ for (const { doc } of visibleResults) {
27354
+ mutationTransaction.recordDocumentRead(doc.value.id, doc);
27355
+ }
27356
+ }
27357
+ const documents = visibleResults.map(({ doc, score }) => ({
27302
27358
  ...doc.value.value,
27303
27359
  _score: score
27304
27360
  }));
@@ -27485,6 +27541,7 @@ class AccessLog2 {
27485
27541
  return this.ranges.getRanges().map(serializeKeyRange2);
27486
27542
  }
27487
27543
  }
27544
+
27488
27545
  // ../core/dist/tables/memory-table-registry.js
27489
27546
  init_interface3();
27490
27547
 
@@ -27622,7 +27679,6 @@ class KernelContext2 {
27622
27679
  }
27623
27680
  recordTableRead(tableName) {
27624
27681
  if (this.mutationTransaction) {
27625
- this.mutationTransaction.recordTableScan(stringToHex2(tableName), []);
27626
27682
  return;
27627
27683
  }
27628
27684
  this.readLog.addTableScan(tableName);
@@ -27635,8 +27691,6 @@ class KernelContext2 {
27635
27691
  }
27636
27692
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
27637
27693
  if (this.mutationTransaction) {
27638
- const indexId = indexKeyspaceId2(tableName, indexDescriptor);
27639
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
27640
27694
  return;
27641
27695
  }
27642
27696
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -27795,11 +27849,12 @@ class BlobStoreGateway2 {
27795
27849
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
27796
27850
  return;
27797
27851
  }
27798
- await storage2.delete(docId.internalId);
27852
+ const canonicalDocId = latest.value.id;
27853
+ await storage2.delete(canonicalDocId.internalId);
27799
27854
  const timestamp2 = this.docStore.allocateTimestamp();
27800
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
27855
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
27801
27856
  await this.docStore.applyWrites([entry], new Set, "Error");
27802
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
27857
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
27803
27858
  }
27804
27859
  requireStorage() {
27805
27860
  if (!this.storage) {
@@ -28006,16 +28061,17 @@ class SchedulerGateway2 {
28006
28061
  if (!latest) {
28007
28062
  throw new Error(`Scheduled job with id ${id} not found.`);
28008
28063
  }
28064
+ const canonicalDocId = latest.value.id;
28009
28065
  const newValue = {
28010
28066
  ...latest.value.value,
28011
28067
  state: state ?? { kind: "canceled" }
28012
28068
  };
28013
- const resolvedDocument = { id: docId, value: newValue };
28069
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
28014
28070
  const timestamp2 = this.docStore.allocateTimestamp();
28015
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
28071
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
28016
28072
  await this.docStore.applyWrites([entry], new Set, "Error");
28017
- const tableName = await resolveTableName2(docId, this.context.tableRegistry);
28018
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
28073
+ const tableName = await resolveTableName2(canonicalDocId, this.context.tableRegistry);
28074
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
28019
28075
  }
28020
28076
  }
28021
28077
 
@@ -28239,13 +28295,14 @@ class DatabaseSyscalls2 {
28239
28295
  if (!latest) {
28240
28296
  throw new Error(`Document with id ${id} not found.`);
28241
28297
  }
28298
+ const canonicalDocId = latest.value.id;
28242
28299
  const timestamp2 = this.docStore.allocateTimestamp();
28243
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
28300
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
28244
28301
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
28245
- const indexUpdates = generateIndexUpdates2(fullTableName, docId, null, latest.value.value, indexes);
28302
+ const indexUpdates = generateIndexUpdates2(fullTableName, canonicalDocId, null, latest.value.value, indexes);
28246
28303
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
28247
28304
  await this.docStore.applyWrites([entry], indexEntries, "Error");
28248
- this.context.recordLocalWrite(id, fullTableName, null, docId);
28305
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
28249
28306
  return {};
28250
28307
  }
28251
28308
  async handleShallowMerge(args) {
@@ -28271,6 +28328,7 @@ class DatabaseSyscalls2 {
28271
28328
  if (!latest) {
28272
28329
  throw new Error(`Document with id ${id} not found.`);
28273
28330
  }
28331
+ const canonicalDocId = latest.value.id;
28274
28332
  const existingValue = latest.value.value;
28275
28333
  const newValue = { ...existingValue };
28276
28334
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -28297,14 +28355,14 @@ class DatabaseSyscalls2 {
28297
28355
  }
28298
28356
  }
28299
28357
  await this.schemaService.validate(bareTableName, newValue);
28300
- const resolvedDocument = { id: docId, value: newValue };
28358
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
28301
28359
  const timestamp2 = this.docStore.allocateTimestamp();
28302
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
28360
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
28303
28361
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
28304
- const indexUpdates = generateIndexUpdates2(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
28362
+ const indexUpdates = generateIndexUpdates2(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
28305
28363
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
28306
28364
  await this.docStore.applyWrites([entry], indexEntries, "Error");
28307
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
28365
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
28308
28366
  return {};
28309
28367
  }
28310
28368
  async handleReplace(args) {
@@ -28326,17 +28384,18 @@ class DatabaseSyscalls2 {
28326
28384
  if (!latest) {
28327
28385
  throw new Error(`Document with id ${id} not found.`);
28328
28386
  }
28387
+ const canonicalDocId = latest.value.id;
28329
28388
  const { _id, _creationTime } = latest.value.value;
28330
28389
  const newValue = { ...replaceValue, _id, _creationTime };
28331
28390
  await this.schemaService.validate(bareTableName, newValue);
28332
- const resolvedDocument = { id: docId, value: newValue };
28391
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
28333
28392
  const timestamp2 = this.docStore.allocateTimestamp();
28334
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
28393
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
28335
28394
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
28336
- const indexUpdates = generateIndexUpdates2(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
28395
+ const indexUpdates = generateIndexUpdates2(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
28337
28396
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
28338
28397
  await this.docStore.applyWrites([entry], indexEntries, "Error");
28339
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
28398
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
28340
28399
  return {};
28341
28400
  }
28342
28401
  }
@@ -28731,7 +28790,7 @@ async function validateReadSetForCommit(docstore, readChecks, writtenDocKeys) {
28731
28790
  await validateTableScanRead(docstore, readEntry.tableId, readEntry.documentIds, writtenDocKeys);
28732
28791
  continue;
28733
28792
  }
28734
- await validateIndexRangeRead(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.documentIds, writtenDocKeys);
28793
+ await validateIndexRangeRead(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.readTimestamp, readEntry.documentIds, writtenDocKeys);
28735
28794
  }
28736
28795
  }
28737
28796
  async function validateDocumentRead(docstore, key, readVersion, writtenDocKeys) {
@@ -28775,11 +28834,12 @@ async function validateTableScanRead(docstore, tableId, readDocumentIds, written
28775
28834
  }
28776
28835
  }
28777
28836
  }
28778
- async function validateIndexRangeRead(docstore, indexId, startKey, endKey, readDocumentIds, writtenDocKeys) {
28837
+ async function validateIndexRangeRead(docstore, indexId, startKey, endKey, readTimestamp, readDocumentIds, writtenDocKeys) {
28779
28838
  const { table } = decodeIndexId2(indexId);
28780
28839
  const interval = { start: startKey, end: endKey };
28840
+ const validationReadTimestamp = resolveValidationReadTimestamp(docstore, readTimestamp);
28781
28841
  const currentDocIds = new Set;
28782
- for await (const [, doc] of docstore.index_scan(indexId, table, BigInt(Date.now()), interval, Order.Asc)) {
28842
+ for await (const [, doc] of docstore.index_scan(indexId, table, validationReadTimestamp, interval, Order.Asc)) {
28783
28843
  currentDocIds.add(documentIdKey(doc.value.id));
28784
28844
  }
28785
28845
  for (const docId of currentDocIds) {
@@ -28793,6 +28853,13 @@ async function validateIndexRangeRead(docstore, indexId, startKey, endKey, readD
28793
28853
  }
28794
28854
  }
28795
28855
  }
28856
+ function resolveValidationReadTimestamp(docstore, minimumTimestamp) {
28857
+ const maybeDocStore = docstore;
28858
+ const oracleTimestamp = maybeDocStore.timestampOracle?.getCurrentTimestamp?.();
28859
+ const wallClockTimestamp = BigInt(Date.now());
28860
+ const latestKnownTimestamp = oracleTimestamp !== undefined && oracleTimestamp > wallClockTimestamp ? oracleTimestamp : wallClockTimestamp;
28861
+ return latestKnownTimestamp > minimumTimestamp ? latestKnownTimestamp : minimumTimestamp;
28862
+ }
28796
28863
 
28797
28864
  // ../core/dist/transactor/occ-transaction.js
28798
28865
  class OccMutationTransaction {
@@ -29363,7 +29430,7 @@ function runUdfMutation(docstore, fn, auth, storage2, requestId, udfExecutor, co
29363
29430
  const savepoint = parentTransaction.createSavepoint();
29364
29431
  const existingIdGenerator = idGeneratorContext2.getStore();
29365
29432
  const idGenerator = existingIdGenerator ?? createDeterministicIdGenerator(seed);
29366
- const nestedResult = transactionContext2.run(parentTransaction, () => idGeneratorContext2.run(idGenerator, () => runUdfAndGetLogs(docstore, fn, ops, auth, "mutation", storage2, seed, parentTransaction, udfExecutor, componentPath)));
29433
+ const nestedResult = Promise.resolve(transactionContext2.run(parentTransaction, () => idGeneratorContext2.run(idGenerator, () => runUdfAndGetLogs(docstore, fn, ops, auth, "mutation", storage2, seed, parentTransaction, udfExecutor, componentPath))));
29367
29434
  return nestedResult.catch((error) => {
29368
29435
  parentTransaction.restoreSavepoint(savepoint);
29369
29436
  throw error;
@@ -29509,10 +29576,15 @@ class InlineUdfExecutor {
29509
29576
  async executeHttp(request, auth, requestId) {
29510
29577
  const url = new URL(request.url);
29511
29578
  const runHttpUdf = async () => {
29512
- const httpModule = await this.loadModule("http");
29579
+ let httpModule;
29580
+ try {
29581
+ httpModule = await this.loadModule("http");
29582
+ } catch {
29583
+ return new Response("Not found", { status: 404 });
29584
+ }
29513
29585
  const router = httpModule?.default;
29514
29586
  if (!router?.isRouter || typeof router.lookup !== "function") {
29515
- throw new Error("convex/http.ts must export a default httpRouter()");
29587
+ return new Response("Not found", { status: 404 });
29516
29588
  }
29517
29589
  const match = router.lookup(url.pathname, request.method);
29518
29590
  if (!match) {
@@ -29947,6 +30019,9 @@ class HttpHandler {
29947
30019
  if (url.pathname === "/health") {
29948
30020
  return apply(Response.json({ status: "ok", runtime: this.runtimeName }));
29949
30021
  }
30022
+ if (!isReservedApiPath(url.pathname)) {
30023
+ return forwardHttpRequest(request, "HTTP action");
30024
+ }
29950
30025
  return apply(Response.json({ error: "Not found" }, { status: 404 }));
29951
30026
  }
29952
30027
  }
@@ -34103,6 +34178,12 @@ function parseDocumentIdKey2(key) {
34103
34178
  const internalId = key.substring(colonIndex + 1);
34104
34179
  if (!table || !internalId)
34105
34180
  return null;
34181
+ if (table.startsWith("#")) {
34182
+ const tableNumber = Number.parseInt(table.slice(1), 10);
34183
+ if (Number.isInteger(tableNumber) && tableNumber > 0) {
34184
+ return { table, internalId, tableNumber };
34185
+ }
34186
+ }
34106
34187
  return { table, internalId };
34107
34188
  }
34108
34189
  var Order3;
@@ -34615,7 +34696,7 @@ async function validateReadSetForCommit2(docstore, readChecks, writtenDocKeys) {
34615
34696
  await validateTableScanRead2(docstore, readEntry.tableId, readEntry.documentIds, writtenDocKeys);
34616
34697
  continue;
34617
34698
  }
34618
- await validateIndexRangeRead2(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.documentIds, writtenDocKeys);
34699
+ await validateIndexRangeRead2(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.readTimestamp, readEntry.documentIds, writtenDocKeys);
34619
34700
  }
34620
34701
  }
34621
34702
  async function validateDocumentRead2(docstore, key, readVersion, writtenDocKeys) {
@@ -34659,11 +34740,12 @@ async function validateTableScanRead2(docstore, tableId, readDocumentIds, writte
34659
34740
  }
34660
34741
  }
34661
34742
  }
34662
- async function validateIndexRangeRead2(docstore, indexId, startKey, endKey, readDocumentIds, writtenDocKeys) {
34743
+ async function validateIndexRangeRead2(docstore, indexId, startKey, endKey, readTimestamp, readDocumentIds, writtenDocKeys) {
34663
34744
  const { table } = decodeIndexId3(indexId);
34664
34745
  const interval = { start: startKey, end: endKey };
34746
+ const validationReadTimestamp = resolveValidationReadTimestamp2(docstore, readTimestamp);
34665
34747
  const currentDocIds = new Set;
34666
- for await (const [, doc] of docstore.index_scan(indexId, table, BigInt(Date.now()), interval, Order3.Asc)) {
34748
+ for await (const [, doc] of docstore.index_scan(indexId, table, validationReadTimestamp, interval, Order3.Asc)) {
34667
34749
  currentDocIds.add(documentIdKey2(doc.value.id));
34668
34750
  }
34669
34751
  for (const docId of currentDocIds) {
@@ -34677,6 +34759,13 @@ async function validateIndexRangeRead2(docstore, indexId, startKey, endKey, read
34677
34759
  }
34678
34760
  }
34679
34761
  }
34762
+ function resolveValidationReadTimestamp2(docstore, minimumTimestamp) {
34763
+ const maybeDocStore = docstore;
34764
+ const oracleTimestamp = maybeDocStore.timestampOracle?.getCurrentTimestamp?.();
34765
+ const wallClockTimestamp = BigInt(Date.now());
34766
+ const latestKnownTimestamp = oracleTimestamp !== undefined && oracleTimestamp > wallClockTimestamp ? oracleTimestamp : wallClockTimestamp;
34767
+ return latestKnownTimestamp > minimumTimestamp ? latestKnownTimestamp : minimumTimestamp;
34768
+ }
34680
34769
 
34681
34770
  class OccMutationTransaction2 {
34682
34771
  docstore;
@@ -35281,7 +35370,6 @@ class KernelContext3 {
35281
35370
  }
35282
35371
  recordTableRead(tableName) {
35283
35372
  if (this.mutationTransaction) {
35284
- this.mutationTransaction.recordTableScan(stringToHex3(tableName), []);
35285
35373
  return;
35286
35374
  }
35287
35375
  this.readLog.addTableScan(tableName);
@@ -35294,8 +35382,6 @@ class KernelContext3 {
35294
35382
  }
35295
35383
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
35296
35384
  if (this.mutationTransaction) {
35297
- const indexId = indexKeyspaceId3(tableName, indexDescriptor);
35298
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
35299
35385
  return;
35300
35386
  }
35301
35387
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -35451,11 +35537,12 @@ class BlobStoreGateway3 {
35451
35537
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
35452
35538
  return;
35453
35539
  }
35454
- await storage2.delete(docId.internalId);
35540
+ const canonicalDocId = latest.value.id;
35541
+ await storage2.delete(canonicalDocId.internalId);
35455
35542
  const timestamp2 = this.docStore.allocateTimestamp();
35456
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
35543
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
35457
35544
  await this.docStore.applyWrites([entry], new Set, "Error");
35458
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
35545
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
35459
35546
  }
35460
35547
  requireStorage() {
35461
35548
  if (!this.storage) {
@@ -35658,16 +35745,17 @@ class SchedulerGateway3 {
35658
35745
  if (!latest) {
35659
35746
  throw new Error(`Scheduled job with id ${id} not found.`);
35660
35747
  }
35748
+ const canonicalDocId = latest.value.id;
35661
35749
  const newValue = {
35662
35750
  ...latest.value.value,
35663
35751
  state: state ?? { kind: "canceled" }
35664
35752
  };
35665
- const resolvedDocument = { id: docId, value: newValue };
35753
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
35666
35754
  const timestamp2 = this.docStore.allocateTimestamp();
35667
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
35755
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
35668
35756
  await this.docStore.applyWrites([entry], new Set, "Error");
35669
- const tableName = await resolveTableName3(docId, this.context.tableRegistry);
35670
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
35757
+ const tableName = await resolveTableName3(canonicalDocId, this.context.tableRegistry);
35758
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
35671
35759
  }
35672
35760
  }
35673
35761
  init_context_storage3();
@@ -35879,13 +35967,14 @@ class DatabaseSyscalls3 {
35879
35967
  if (!latest) {
35880
35968
  throw new Error(`Document with id ${id} not found.`);
35881
35969
  }
35970
+ const canonicalDocId = latest.value.id;
35882
35971
  const timestamp2 = this.docStore.allocateTimestamp();
35883
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
35972
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
35884
35973
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
35885
- const indexUpdates = generateIndexUpdates3(fullTableName, docId, null, latest.value.value, indexes);
35974
+ const indexUpdates = generateIndexUpdates3(fullTableName, canonicalDocId, null, latest.value.value, indexes);
35886
35975
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
35887
35976
  await this.docStore.applyWrites([entry], indexEntries, "Error");
35888
- this.context.recordLocalWrite(id, fullTableName, null, docId);
35977
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
35889
35978
  return {};
35890
35979
  }
35891
35980
  async handleShallowMerge(args) {
@@ -35911,6 +36000,7 @@ class DatabaseSyscalls3 {
35911
36000
  if (!latest) {
35912
36001
  throw new Error(`Document with id ${id} not found.`);
35913
36002
  }
36003
+ const canonicalDocId = latest.value.id;
35914
36004
  const existingValue = latest.value.value;
35915
36005
  const newValue = { ...existingValue };
35916
36006
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -35937,14 +36027,14 @@ class DatabaseSyscalls3 {
35937
36027
  }
35938
36028
  }
35939
36029
  await this.schemaService.validate(bareTableName, newValue);
35940
- const resolvedDocument = { id: docId, value: newValue };
36030
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
35941
36031
  const timestamp2 = this.docStore.allocateTimestamp();
35942
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
36032
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
35943
36033
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
35944
- const indexUpdates = generateIndexUpdates3(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
36034
+ const indexUpdates = generateIndexUpdates3(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
35945
36035
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
35946
36036
  await this.docStore.applyWrites([entry], indexEntries, "Error");
35947
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
36037
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
35948
36038
  return {};
35949
36039
  }
35950
36040
  async handleReplace(args) {
@@ -35966,17 +36056,18 @@ class DatabaseSyscalls3 {
35966
36056
  if (!latest) {
35967
36057
  throw new Error(`Document with id ${id} not found.`);
35968
36058
  }
36059
+ const canonicalDocId = latest.value.id;
35969
36060
  const { _id, _creationTime } = latest.value.value;
35970
36061
  const newValue = { ...replaceValue, _id, _creationTime };
35971
36062
  await this.schemaService.validate(bareTableName, newValue);
35972
- const resolvedDocument = { id: docId, value: newValue };
36063
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
35973
36064
  const timestamp2 = this.docStore.allocateTimestamp();
35974
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
36065
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
35975
36066
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
35976
- const indexUpdates = generateIndexUpdates3(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
36067
+ const indexUpdates = generateIndexUpdates3(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
35977
36068
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
35978
36069
  await this.docStore.applyWrites([entry], indexEntries, "Error");
35979
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
36070
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
35980
36071
  return {};
35981
36072
  }
35982
36073
  }
@@ -41483,6 +41574,12 @@ function parseDocumentIdKey3(key) {
41483
41574
  const internalId = key.substring(colonIndex + 1);
41484
41575
  if (!table || !internalId)
41485
41576
  return null;
41577
+ if (table.startsWith("#")) {
41578
+ const tableNumber = Number.parseInt(table.slice(1), 10);
41579
+ if (Number.isInteger(tableNumber) && tableNumber > 0) {
41580
+ return { table, internalId, tableNumber };
41581
+ }
41582
+ }
41486
41583
  return { table, internalId };
41487
41584
  }
41488
41585
  var Order4;
@@ -41992,7 +42089,7 @@ async function validateReadSetForCommit3(docstore, readChecks, writtenDocKeys) {
41992
42089
  await validateTableScanRead3(docstore, readEntry.tableId, readEntry.documentIds, writtenDocKeys);
41993
42090
  continue;
41994
42091
  }
41995
- await validateIndexRangeRead3(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.documentIds, writtenDocKeys);
42092
+ await validateIndexRangeRead3(docstore, readEntry.indexId, readEntry.startKey, readEntry.endKey, readEntry.readTimestamp, readEntry.documentIds, writtenDocKeys);
41996
42093
  }
41997
42094
  }
41998
42095
  async function validateDocumentRead3(docstore, key, readVersion, writtenDocKeys) {
@@ -42036,11 +42133,12 @@ async function validateTableScanRead3(docstore, tableId, readDocumentIds, writte
42036
42133
  }
42037
42134
  }
42038
42135
  }
42039
- async function validateIndexRangeRead3(docstore, indexId, startKey, endKey, readDocumentIds, writtenDocKeys) {
42136
+ async function validateIndexRangeRead3(docstore, indexId, startKey, endKey, readTimestamp, readDocumentIds, writtenDocKeys) {
42040
42137
  const { table } = decodeIndexId4(indexId);
42041
42138
  const interval = { start: startKey, end: endKey };
42139
+ const validationReadTimestamp = resolveValidationReadTimestamp3(docstore, readTimestamp);
42042
42140
  const currentDocIds = new Set;
42043
- for await (const [, doc] of docstore.index_scan(indexId, table, BigInt(Date.now()), interval, Order4.Asc)) {
42141
+ for await (const [, doc] of docstore.index_scan(indexId, table, validationReadTimestamp, interval, Order4.Asc)) {
42044
42142
  currentDocIds.add(documentIdKey3(doc.value.id));
42045
42143
  }
42046
42144
  for (const docId of currentDocIds) {
@@ -42054,6 +42152,13 @@ async function validateIndexRangeRead3(docstore, indexId, startKey, endKey, read
42054
42152
  }
42055
42153
  }
42056
42154
  }
42155
+ function resolveValidationReadTimestamp3(docstore, minimumTimestamp) {
42156
+ const maybeDocStore = docstore;
42157
+ const oracleTimestamp = maybeDocStore.timestampOracle?.getCurrentTimestamp?.();
42158
+ const wallClockTimestamp = BigInt(Date.now());
42159
+ const latestKnownTimestamp = oracleTimestamp !== undefined && oracleTimestamp > wallClockTimestamp ? oracleTimestamp : wallClockTimestamp;
42160
+ return latestKnownTimestamp > minimumTimestamp ? latestKnownTimestamp : minimumTimestamp;
42161
+ }
42057
42162
 
42058
42163
  class OccMutationTransaction3 {
42059
42164
  docstore;
@@ -42658,7 +42763,6 @@ class KernelContext4 {
42658
42763
  }
42659
42764
  recordTableRead(tableName) {
42660
42765
  if (this.mutationTransaction) {
42661
- this.mutationTransaction.recordTableScan(stringToHex4(tableName), []);
42662
42766
  return;
42663
42767
  }
42664
42768
  this.readLog.addTableScan(tableName);
@@ -42671,8 +42775,6 @@ class KernelContext4 {
42671
42775
  }
42672
42776
  recordIndexRange(tableName, indexDescriptor, startKey, endKey) {
42673
42777
  if (this.mutationTransaction) {
42674
- const indexId = indexKeyspaceId4(tableName, indexDescriptor);
42675
- this.mutationTransaction.recordIndexRangeScan(indexId, startKey, endKey, []);
42676
42778
  return;
42677
42779
  }
42678
42780
  this.readLog.addIndexRange(tableName, indexDescriptor, startKey, endKey);
@@ -42828,11 +42930,12 @@ class BlobStoreGateway4 {
42828
42930
  if (!latest || latest.ts > this.context.snapshotTimestamp) {
42829
42931
  return;
42830
42932
  }
42831
- await storage2.delete(docId.internalId);
42933
+ const canonicalDocId = latest.value.id;
42934
+ await storage2.delete(canonicalDocId.internalId);
42832
42935
  const timestamp2 = this.docStore.allocateTimestamp();
42833
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
42936
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
42834
42937
  await this.docStore.applyWrites([entry], new Set, "Error");
42835
- this.context.recordLocalWrite(storageId, "_storage", null, docId);
42938
+ this.context.recordLocalWrite(storageId, "_storage", null, canonicalDocId);
42836
42939
  }
42837
42940
  requireStorage() {
42838
42941
  if (!this.storage) {
@@ -43035,16 +43138,17 @@ class SchedulerGateway4 {
43035
43138
  if (!latest) {
43036
43139
  throw new Error(`Scheduled job with id ${id} not found.`);
43037
43140
  }
43141
+ const canonicalDocId = latest.value.id;
43038
43142
  const newValue = {
43039
43143
  ...latest.value.value,
43040
43144
  state: state ?? { kind: "canceled" }
43041
43145
  };
43042
- const resolvedDocument = { id: docId, value: newValue };
43146
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
43043
43147
  const timestamp2 = this.docStore.allocateTimestamp();
43044
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
43148
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
43045
43149
  await this.docStore.applyWrites([entry], new Set, "Error");
43046
- const tableName = await resolveTableName4(docId, this.context.tableRegistry);
43047
- this.context.recordLocalWrite(id, tableName, resolvedDocument.value, docId);
43150
+ const tableName = await resolveTableName4(canonicalDocId, this.context.tableRegistry);
43151
+ this.context.recordLocalWrite(id, tableName, resolvedDocument.value, canonicalDocId);
43048
43152
  }
43049
43153
  }
43050
43154
  init_context_storage4();
@@ -43255,13 +43359,14 @@ class DatabaseSyscalls4 {
43255
43359
  if (!latest) {
43256
43360
  throw new Error(`Document with id ${id} not found.`);
43257
43361
  }
43362
+ const canonicalDocId = latest.value.id;
43258
43363
  const timestamp2 = this.docStore.allocateTimestamp();
43259
- const entry = { ts: timestamp2, id: docId, value: null, prev_ts: latest.ts };
43364
+ const entry = { ts: timestamp2, id: canonicalDocId, value: null, prev_ts: latest.ts };
43260
43365
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
43261
- const indexUpdates = generateIndexUpdates4(fullTableName, docId, null, latest.value.value, indexes);
43366
+ const indexUpdates = generateIndexUpdates4(fullTableName, canonicalDocId, null, latest.value.value, indexes);
43262
43367
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
43263
43368
  await this.docStore.applyWrites([entry], indexEntries, "Error");
43264
- this.context.recordLocalWrite(id, fullTableName, null, docId);
43369
+ this.context.recordLocalWrite(id, fullTableName, null, canonicalDocId);
43265
43370
  return {};
43266
43371
  }
43267
43372
  async handleShallowMerge(args) {
@@ -43287,6 +43392,7 @@ class DatabaseSyscalls4 {
43287
43392
  if (!latest) {
43288
43393
  throw new Error(`Document with id ${id} not found.`);
43289
43394
  }
43395
+ const canonicalDocId = latest.value.id;
43290
43396
  const existingValue = latest.value.value;
43291
43397
  const newValue = { ...existingValue };
43292
43398
  if (typeof value === "object" && value !== null && "$undefined" in value) {
@@ -43313,14 +43419,14 @@ class DatabaseSyscalls4 {
43313
43419
  }
43314
43420
  }
43315
43421
  await this.schemaService.validate(bareTableName, newValue);
43316
- const resolvedDocument = { id: docId, value: newValue };
43422
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
43317
43423
  const timestamp2 = this.docStore.allocateTimestamp();
43318
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
43424
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
43319
43425
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
43320
- const indexUpdates = generateIndexUpdates4(fullTableName, docId, resolvedDocument.value, existingValue, indexes);
43426
+ const indexUpdates = generateIndexUpdates4(fullTableName, canonicalDocId, resolvedDocument.value, existingValue, indexes);
43321
43427
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
43322
43428
  await this.docStore.applyWrites([entry], indexEntries, "Error");
43323
- this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, docId);
43429
+ this.context.recordLocalWrite(id, fullTableName, resolvedDocument.value, canonicalDocId);
43324
43430
  return {};
43325
43431
  }
43326
43432
  async handleReplace(args) {
@@ -43342,17 +43448,18 @@ class DatabaseSyscalls4 {
43342
43448
  if (!latest) {
43343
43449
  throw new Error(`Document with id ${id} not found.`);
43344
43450
  }
43451
+ const canonicalDocId = latest.value.id;
43345
43452
  const { _id, _creationTime } = latest.value.value;
43346
43453
  const newValue = { ...replaceValue, _id, _creationTime };
43347
43454
  await this.schemaService.validate(bareTableName, newValue);
43348
- const resolvedDocument = { id: docId, value: newValue };
43455
+ const resolvedDocument = { id: canonicalDocId, value: newValue };
43349
43456
  const timestamp2 = this.docStore.allocateTimestamp();
43350
- const entry = { ts: timestamp2, id: docId, value: resolvedDocument, prev_ts: latest.ts };
43457
+ const entry = { ts: timestamp2, id: canonicalDocId, value: resolvedDocument, prev_ts: latest.ts };
43351
43458
  const indexes = await this.schemaService.getAllIndexesForTable(bareTableName);
43352
- const indexUpdates = generateIndexUpdates4(fullTableName, docId, resolvedDocument.value, latest.value.value, indexes);
43459
+ const indexUpdates = generateIndexUpdates4(fullTableName, canonicalDocId, resolvedDocument.value, latest.value.value, indexes);
43353
43460
  const indexEntries = new Set(indexUpdates.map((update) => ({ ts: timestamp2, update })));
43354
43461
  await this.docStore.applyWrites([entry], indexEntries, "Error");
43355
- this.context.recordLocalWrite(id, fullTableName, newValue, docId);
43462
+ this.context.recordLocalWrite(id, fullTableName, newValue, canonicalDocId);
43356
43463
  return {};
43357
43464
  }
43358
43465
  }
@@ -46454,6 +46561,7 @@ class SyncProtocolHandler2 {
46454
46561
  rateLimitWindowMs;
46455
46562
  operationTimeoutMs;
46456
46563
  maxActiveQueriesPerSession;
46564
+ lastObservedWriteTimestamp = 0n;
46457
46565
  constructor(instanceName, udfExecutor, options) {
46458
46566
  this.udfExecutor = udfExecutor;
46459
46567
  this.instanceName = instanceName;
@@ -46477,6 +46585,22 @@ class SyncProtocolHandler2 {
46477
46585
  onPing: (session) => this.sendPing(session)
46478
46586
  });
46479
46587
  }
46588
+ resolveWriteTimestamp(commitTimestamp, snapshotTimestamp) {
46589
+ const wallClock = BigInt(Date.now());
46590
+ const monotonicFloor = this.lastObservedWriteTimestamp + 1n;
46591
+ let resolved = wallClock;
46592
+ if (commitTimestamp !== undefined && commitTimestamp > resolved) {
46593
+ resolved = commitTimestamp;
46594
+ }
46595
+ if (snapshotTimestamp !== undefined && snapshotTimestamp > resolved) {
46596
+ resolved = snapshotTimestamp;
46597
+ }
46598
+ if (monotonicFloor > resolved) {
46599
+ resolved = monotonicFloor;
46600
+ }
46601
+ this.lastObservedWriteTimestamp = resolved;
46602
+ return resolved;
46603
+ }
46480
46604
  createSession(sessionId, websocket) {
46481
46605
  const session = new SyncSession2(websocket);
46482
46606
  this.sessions.set(sessionId, session);
@@ -46559,11 +46683,11 @@ class SyncProtocolHandler2 {
46559
46683
  return assertNever2(message22);
46560
46684
  }
46561
46685
  }
46562
- async notifyWrites(writtenRanges, writtenTables, commitTimestamp) {
46686
+ async notifyWrites(writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp) {
46563
46687
  const ranges = writtenRanges ? writtenRanges.map(deserializeKeyRange4) : convertTablesToRanges2(writtenTables);
46564
46688
  this.logRanges("/notify", ranges, { writtenTables });
46565
46689
  if (ranges.length > 0) {
46566
- const ts = commitTimestamp ?? BigInt(Date.now());
46690
+ const ts = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
46567
46691
  this.subscriptionManager.recordWrites(ranges, ts);
46568
46692
  await this.broadcastUpdates(ranges);
46569
46693
  }
@@ -46661,8 +46785,8 @@ class SyncProtocolHandler2 {
46661
46785
  if (message22.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
46662
46786
  throw new Error("Only admin or system auth can execute component functions");
46663
46787
  }
46664
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeMutation(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
46665
- const now = commitTimestamp ?? BigInt(Date.now());
46788
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeMutation(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
46789
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
46666
46790
  const successResponse = {
46667
46791
  type: "MutationResponse",
46668
46792
  requestId: message22.requestId,
@@ -46707,8 +46831,8 @@ class SyncProtocolHandler2 {
46707
46831
  if (message22.componentPath && session.auth.tokenType !== "Admin" && session.auth.tokenType !== "System") {
46708
46832
  throw new Error("Only admin or system auth can mutate component functions");
46709
46833
  }
46710
- const { result, writtenRanges, writtenTables, commitTimestamp, logLines } = await this.udfExecutor.executeAction(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
46711
- const now = commitTimestamp ?? BigInt(Date.now());
46834
+ const { result, writtenRanges, writtenTables, commitTimestamp, snapshotTimestamp, logLines } = await this.udfExecutor.executeAction(message22.udfPath, message22.args[0] ?? {}, session.auth, message22.componentPath);
46835
+ const now = this.resolveWriteTimestamp(commitTimestamp, snapshotTimestamp);
46712
46836
  const successResponse = {
46713
46837
  type: "ActionResponse",
46714
46838
  requestId: message22.requestId,