@topgunbuild/core 0.10.1 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -36,7 +36,9 @@ __export(index_exports, {
36
36
  BatchMessageSchema: () => BatchMessageSchema,
37
37
  BuiltInProcessors: () => BuiltInProcessors,
38
38
  BuiltInResolvers: () => BuiltInResolvers,
39
+ COST_WEIGHTS: () => COST_WEIGHTS,
39
40
  CRDTDebugger: () => CRDTDebugger,
41
+ CRDTInvariants: () => CRDTInvariants,
40
42
  ClientOpMessageSchema: () => ClientOpMessageSchema,
41
43
  ClientOpSchema: () => ClientOpSchema,
42
44
  ClusterSearchReqMessageSchema: () => ClusterSearchReqMessageSchema,
@@ -78,6 +80,7 @@ __export(index_exports, {
78
80
  DEFAULT_RESOLVER_RATE_LIMITS: () => DEFAULT_RESOLVER_RATE_LIMITS,
79
81
  DEFAULT_STOP_WORDS: () => DEFAULT_STOP_WORDS,
80
82
  DEFAULT_WRITE_CONCERN_TIMEOUT: () => DEFAULT_WRITE_CONCERN_TIMEOUT,
83
+ DeltaRecordSchema: () => DeltaRecordSchema,
81
84
  ENGLISH_STOPWORDS: () => ENGLISH_STOPWORDS,
82
85
  EntryProcessBatchRequestSchema: () => EntryProcessBatchRequestSchema,
83
86
  EntryProcessBatchResponseSchema: () => EntryProcessBatchResponseSchema,
@@ -97,12 +100,20 @@ __export(index_exports, {
97
100
  GcPrunePayloadSchema: () => GcPrunePayloadSchema,
98
101
  HLC: () => HLC,
99
102
  HashIndex: () => HashIndex,
103
+ HttpQueryRequestSchema: () => HttpQueryRequestSchema,
104
+ HttpQueryResultSchema: () => HttpQueryResultSchema,
105
+ HttpSearchRequestSchema: () => HttpSearchRequestSchema,
106
+ HttpSearchResultSchema: () => HttpSearchResultSchema,
107
+ HttpSyncErrorSchema: () => HttpSyncErrorSchema,
108
+ HttpSyncRequestSchema: () => HttpSyncRequestSchema,
109
+ HttpSyncResponseSchema: () => HttpSyncResponseSchema,
100
110
  HybridQueryDeltaPayloadSchema: () => HybridQueryDeltaPayloadSchema,
101
111
  HybridQueryRespPayloadSchema: () => HybridQueryRespPayloadSchema,
102
112
  IndexRegistry: () => IndexRegistry,
103
113
  IndexedLWWMap: () => IndexedLWWMap,
104
114
  IndexedORMap: () => IndexedORMap,
105
115
  IntersectionResultSet: () => IntersectionResultSet,
116
+ InvariantChecker: () => InvariantChecker,
106
117
  InvertedIndex: () => InvertedIndex,
107
118
  JournalEventDataSchema: () => JournalEventDataSchema,
108
119
  JournalEventMessageSchema: () => JournalEventMessageSchema,
@@ -123,6 +134,7 @@ __export(index_exports, {
123
134
  LockReleasedPayloadSchema: () => LockReleasedPayloadSchema,
124
135
  LockRequestSchema: () => LockRequestSchema,
125
136
  LowercaseFilter: () => LowercaseFilter,
137
+ MapDeltaSchema: () => MapDeltaSchema,
126
138
  MaxLengthFilter: () => MaxLengthFilter,
127
139
  MergeRejectedMessageSchema: () => MergeRejectedMessageSchema,
128
140
  MerkleReqBucketMessageSchema: () => MerkleReqBucketMessageSchema,
@@ -167,10 +179,12 @@ __export(index_exports, {
167
179
  QueryUpdateMessageSchema: () => QueryUpdateMessageSchema,
168
180
  QueryUpdatePayloadSchema: () => QueryUpdatePayloadSchema,
169
181
  RESOLVER_FORBIDDEN_PATTERNS: () => RESOLVER_FORBIDDEN_PATTERNS,
182
+ RealClock: () => RealClock,
170
183
  ReciprocalRankFusion: () => ReciprocalRankFusion,
171
184
  RegisterResolverRequestSchema: () => RegisterResolverRequestSchema,
172
185
  RegisterResolverResponseSchema: () => RegisterResolverResponseSchema,
173
186
  Ringbuffer: () => Ringbuffer,
187
+ ScenarioRunner: () => ScenarioRunner,
174
188
  SearchCursor: () => SearchCursor,
175
189
  SearchDebugger: () => SearchDebugger,
176
190
  SearchMessageSchema: () => SearchMessageSchema,
@@ -185,6 +199,7 @@ __export(index_exports, {
185
199
  SearchUpdateMessageSchema: () => SearchUpdateMessageSchema,
186
200
  SearchUpdatePayloadSchema: () => SearchUpdatePayloadSchema,
187
201
  SearchUpdateTypeSchema: () => SearchUpdateTypeSchema,
202
+ SeededRNG: () => SeededRNG,
188
203
  ServerBatchEventMessageSchema: () => ServerBatchEventMessageSchema,
189
204
  ServerEventMessageSchema: () => ServerEventMessageSchema,
190
205
  ServerEventPayloadSchema: () => ServerEventPayloadSchema,
@@ -196,6 +211,7 @@ __export(index_exports, {
196
211
  StandingQueryRegistry: () => StandingQueryRegistry,
197
212
  StopWordFilter: () => StopWordFilter,
198
213
  SyncInitMessageSchema: () => SyncInitMessageSchema,
214
+ SyncMapEntrySchema: () => SyncMapEntrySchema,
199
215
  SyncResetRequiredPayloadSchema: () => SyncResetRequiredPayloadSchema,
200
216
  SyncRespBucketsMessageSchema: () => SyncRespBucketsMessageSchema,
201
217
  SyncRespLeafMessageSchema: () => SyncRespLeafMessageSchema,
@@ -211,11 +227,14 @@ __export(index_exports, {
211
227
  UniqueFilter: () => UniqueFilter,
212
228
  UnregisterResolverRequestSchema: () => UnregisterResolverRequestSchema,
213
229
  UnregisterResolverResponseSchema: () => UnregisterResolverResponseSchema,
230
+ VirtualClock: () => VirtualClock,
231
+ VirtualNetwork: () => VirtualNetwork,
214
232
  WRITE_CONCERN_ORDER: () => WRITE_CONCERN_ORDER,
215
233
  WhitespaceTokenizer: () => WhitespaceTokenizer,
216
234
  WordBoundaryTokenizer: () => WordBoundaryTokenizer,
217
235
  WriteConcern: () => WriteConcern,
218
236
  WriteConcernSchema: () => WriteConcernSchema,
237
+ calculateTotalCost: () => calculateTotalCost,
219
238
  combineHashes: () => combineHashes,
220
239
  compareHLCTimestamps: () => compareHLCTimestamps,
221
240
  compareTimestamps: () => compareTimestamps,
@@ -269,6 +288,7 @@ var HLC = class {
269
288
  this.nodeId = nodeId;
270
289
  this.strictMode = options.strictMode ?? false;
271
290
  this.maxDriftMs = options.maxDriftMs ?? 6e4;
291
+ this.clockSource = options.clockSource ?? { now: () => Date.now() };
272
292
  this.lastMillis = 0;
273
293
  this.lastCounter = 0;
274
294
  }
@@ -281,12 +301,19 @@ var HLC = class {
281
301
  get getMaxDriftMs() {
282
302
  return this.maxDriftMs;
283
303
  }
304
+ /**
305
+ * Returns the clock source used by this HLC instance.
306
+ * Useful for LWWMap/ORMap to access the same clock for TTL checks.
307
+ */
308
+ getClockSource() {
309
+ return this.clockSource;
310
+ }
284
311
  /**
285
312
  * Generates a new unique timestamp for a local event.
286
313
  * Ensures monotonicity: always greater than any previously generated or received timestamp.
287
314
  */
288
315
  now() {
289
- const systemTime = Date.now();
316
+ const systemTime = this.clockSource.now();
290
317
  if (systemTime > this.lastMillis) {
291
318
  this.lastMillis = systemTime;
292
319
  this.lastCounter = 0;
@@ -304,7 +331,7 @@ var HLC = class {
304
331
  * Must be called whenever a message/event is received from another node.
305
332
  */
306
333
  update(remote) {
307
- const systemTime = Date.now();
334
+ const systemTime = this.clockSource.now();
308
335
  const drift = remote.millis - systemTime;
309
336
  if (drift > this.maxDriftMs) {
310
337
  if (this.strictMode) {
@@ -588,7 +615,7 @@ var LWWMap = class {
588
615
  return void 0;
589
616
  }
590
617
  if (record.ttlMs) {
591
- const now = Date.now();
618
+ const now = this.hlc.getClockSource().now();
592
619
  if (record.timestamp.millis + record.ttlMs < now) {
593
620
  return void 0;
594
621
  }
@@ -665,7 +692,7 @@ var LWWMap = class {
665
692
  */
666
693
  entries() {
667
694
  const iterator = this.data.entries();
668
- const now = Date.now();
695
+ const clockSource = this.hlc.getClockSource();
669
696
  return {
670
697
  [Symbol.iterator]() {
671
698
  return this;
@@ -675,7 +702,7 @@ var LWWMap = class {
675
702
  while (!result.done) {
676
703
  const [key, record] = result.value;
677
704
  if (record.value !== null) {
678
- if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {
705
+ if (record.ttlMs && record.timestamp.millis + record.ttlMs < clockSource.now()) {
679
706
  result = iterator.next();
680
707
  continue;
681
708
  }
@@ -1012,7 +1039,7 @@ var ORMap = class {
1012
1039
  const keyMap = this.items.get(key);
1013
1040
  if (!keyMap) return [];
1014
1041
  const values = [];
1015
- const now = Date.now();
1042
+ const now = this.hlc.getClockSource().now();
1016
1043
  for (const [tag, record] of keyMap.entries()) {
1017
1044
  if (!this.tombstones.has(tag)) {
1018
1045
  if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {
@@ -1032,7 +1059,7 @@ var ORMap = class {
1032
1059
  const keyMap = this.items.get(key);
1033
1060
  if (!keyMap) return [];
1034
1061
  const records = [];
1035
- const now = Date.now();
1062
+ const now = this.hlc.getClockSource().now();
1036
1063
  for (const [tag, record] of keyMap.entries()) {
1037
1064
  if (!this.tombstones.has(tag)) {
1038
1065
  if (record.ttlMs && record.timestamp.millis + record.ttlMs < now) {
@@ -3134,9 +3161,86 @@ var SyncResetRequiredPayloadSchema = import_zod9.z.object({
3134
3161
  reason: import_zod9.z.string()
3135
3162
  });
3136
3163
 
3137
- // src/schemas/index.ts
3164
+ // src/schemas/http-sync-schemas.ts
3138
3165
  var import_zod10 = require("zod");
3139
- var MessageSchema = import_zod10.z.discriminatedUnion("type", [
3166
+ var SyncMapEntrySchema = import_zod10.z.object({
3167
+ mapName: import_zod10.z.string(),
3168
+ lastSyncTimestamp: TimestampSchema
3169
+ });
3170
+ var HttpQueryRequestSchema = import_zod10.z.object({
3171
+ queryId: import_zod10.z.string(),
3172
+ mapName: import_zod10.z.string(),
3173
+ filter: import_zod10.z.any(),
3174
+ limit: import_zod10.z.number().optional(),
3175
+ offset: import_zod10.z.number().optional()
3176
+ });
3177
+ var HttpSearchRequestSchema = import_zod10.z.object({
3178
+ searchId: import_zod10.z.string(),
3179
+ mapName: import_zod10.z.string(),
3180
+ query: import_zod10.z.string(),
3181
+ options: import_zod10.z.any().optional()
3182
+ });
3183
+ var HttpSyncRequestSchema = import_zod10.z.object({
3184
+ // Client identification
3185
+ clientId: import_zod10.z.string(),
3186
+ // Client's current HLC for causality tracking
3187
+ clientHlc: TimestampSchema,
3188
+ // Batch of operations to push (optional)
3189
+ operations: import_zod10.z.array(ClientOpSchema).optional(),
3190
+ // Maps the client wants deltas for, with their last known sync HLC timestamp
3191
+ syncMaps: import_zod10.z.array(SyncMapEntrySchema).optional(),
3192
+ // One-shot queries to execute (optional)
3193
+ queries: import_zod10.z.array(HttpQueryRequestSchema).optional(),
3194
+ // One-shot search requests (optional)
3195
+ searches: import_zod10.z.array(HttpSearchRequestSchema).optional()
3196
+ });
3197
+ var DeltaRecordSchema = import_zod10.z.object({
3198
+ key: import_zod10.z.string(),
3199
+ record: LWWRecordSchema,
3200
+ eventType: import_zod10.z.enum(["PUT", "REMOVE"])
3201
+ });
3202
+ var MapDeltaSchema = import_zod10.z.object({
3203
+ mapName: import_zod10.z.string(),
3204
+ records: import_zod10.z.array(DeltaRecordSchema),
3205
+ serverSyncTimestamp: TimestampSchema
3206
+ });
3207
+ var HttpQueryResultSchema = import_zod10.z.object({
3208
+ queryId: import_zod10.z.string(),
3209
+ results: import_zod10.z.array(import_zod10.z.any()),
3210
+ hasMore: import_zod10.z.boolean().optional(),
3211
+ nextCursor: import_zod10.z.string().optional()
3212
+ });
3213
+ var HttpSearchResultSchema = import_zod10.z.object({
3214
+ searchId: import_zod10.z.string(),
3215
+ results: import_zod10.z.array(import_zod10.z.any()),
3216
+ totalCount: import_zod10.z.number().optional()
3217
+ });
3218
+ var HttpSyncErrorSchema = import_zod10.z.object({
3219
+ code: import_zod10.z.number(),
3220
+ message: import_zod10.z.string(),
3221
+ context: import_zod10.z.string().optional()
3222
+ });
3223
+ var HttpSyncResponseSchema = import_zod10.z.object({
3224
+ // Server's current HLC
3225
+ serverHlc: TimestampSchema,
3226
+ // Acknowledgment of received operations
3227
+ ack: import_zod10.z.object({
3228
+ lastId: import_zod10.z.string(),
3229
+ results: import_zod10.z.array(OpResultSchema).optional()
3230
+ }).optional(),
3231
+ // Delta records for requested maps (new/changed since lastSyncTimestamp)
3232
+ deltas: import_zod10.z.array(MapDeltaSchema).optional(),
3233
+ // Query results
3234
+ queryResults: import_zod10.z.array(HttpQueryResultSchema).optional(),
3235
+ // Search results
3236
+ searchResults: import_zod10.z.array(HttpSearchResultSchema).optional(),
3237
+ // Errors for individual operations
3238
+ errors: import_zod10.z.array(HttpSyncErrorSchema).optional()
3239
+ });
3240
+
3241
+ // src/schemas/index.ts
3242
+ var import_zod11 = require("zod");
3243
+ var MessageSchema = import_zod11.z.discriminatedUnion("type", [
3140
3244
  AuthMessageSchema,
3141
3245
  QuerySubMessageSchema,
3142
3246
  QueryUnsubMessageSchema,
@@ -4149,6 +4253,18 @@ function createPredicateMatcher(getAttribute) {
4149
4253
  }
4150
4254
 
4151
4255
  // src/query/QueryTypes.ts
4256
+ var COST_WEIGHTS = {
4257
+ CPU: 1,
4258
+ NETWORK: 10,
4259
+ // Network is expensive (latency, bandwidth)
4260
+ IO: 5,
4261
+ // Disk I/O is moderately expensive
4262
+ ROWS: 1e-3
4263
+ // Row count factor
4264
+ };
4265
+ function calculateTotalCost(cost) {
4266
+ return cost.rows * COST_WEIGHTS.ROWS + cost.cpu * COST_WEIGHTS.CPU + cost.network * COST_WEIGHTS.NETWORK + cost.io * COST_WEIGHTS.IO;
4267
+ }
4152
4268
  function isSimpleQuery(query) {
4153
4269
  return [
4154
4270
  "eq",
@@ -6470,13 +6586,22 @@ var QueryOptimizer = class {
6470
6586
  * Optimize a query and return an execution plan.
6471
6587
  *
6472
6588
  * Optimization order (by cost):
6473
- * 1. StandingQueryIndex (cost: 10) - pre-computed results
6474
- * 2. Other indexes via optimizeNode
6589
+ * 1. Point lookup (cost: 1) - direct primary key access
6590
+ * 2. StandingQueryIndex (cost: 10) - pre-computed results
6591
+ * 3. Other indexes via optimizeNode
6475
6592
  *
6476
6593
  * @param query - Query to optimize
6477
6594
  * @returns Query execution plan
6478
6595
  */
6479
6596
  optimize(query) {
6597
+ const pointLookupStep = this.tryPointLookup(query);
6598
+ if (pointLookupStep) {
6599
+ return {
6600
+ root: pointLookupStep,
6601
+ estimatedCost: this.estimateCost(pointLookupStep),
6602
+ usesIndexes: this.usesIndexes(pointLookupStep)
6603
+ };
6604
+ }
6480
6605
  if (this.standingQueryRegistry) {
6481
6606
  const standingIndex = this.standingQueryRegistry.getIndex(query);
6482
6607
  if (standingIndex) {
@@ -6500,16 +6625,68 @@ var QueryOptimizer = class {
6500
6625
  };
6501
6626
  }
6502
6627
  /**
6503
- * Optimize a query with sort/limit/offset options.
6628
+ * Optimize a query with sort/limit/offset options and index hints.
6629
+ *
6630
+ * Hint precedence: disableOptimization > useIndex > forceIndexScan.
6504
6631
  *
6505
6632
  * @param query - Query to optimize
6506
- * @param options - Query options (sort, limit, offset)
6633
+ * @param options - Query options (sort, limit, cursor, hints)
6507
6634
  * @returns Query execution plan with options
6508
6635
  */
6509
6636
  optimizeWithOptions(query, options) {
6637
+ if (options.disableOptimization) {
6638
+ return {
6639
+ root: { type: "full-scan", predicate: query },
6640
+ estimatedCost: Number.MAX_SAFE_INTEGER,
6641
+ usesIndexes: false
6642
+ };
6643
+ }
6644
+ if (options.useIndex) {
6645
+ const indexes = this.indexRegistry.getIndexes(options.useIndex);
6646
+ if (indexes.length === 0) {
6647
+ throw new Error(
6648
+ `Index hint: no index found for attribute "${options.useIndex}"`
6649
+ );
6650
+ }
6651
+ let best = indexes[0];
6652
+ for (let i = 1; i < indexes.length; i++) {
6653
+ if (indexes[i].getRetrievalCost() < best.getRetrievalCost()) {
6654
+ best = indexes[i];
6655
+ }
6656
+ }
6657
+ const step = {
6658
+ type: "index-scan",
6659
+ index: best,
6660
+ query: this.buildHintedIndexQuery(query, options.useIndex)
6661
+ };
6662
+ return this.applyPlanOptions(
6663
+ {
6664
+ root: step,
6665
+ estimatedCost: best.getRetrievalCost(),
6666
+ usesIndexes: true,
6667
+ hint: options.useIndex
6668
+ },
6669
+ options
6670
+ );
6671
+ }
6510
6672
  const basePlan = this.optimize(query);
6673
+ if (options.forceIndexScan && !basePlan.usesIndexes) {
6674
+ throw new Error(
6675
+ "No suitable index found and forceIndexScan is enabled"
6676
+ );
6677
+ }
6678
+ return this.applyPlanOptions(basePlan, options);
6679
+ }
6680
+ /**
6681
+ * Apply sort/limit/cursor options to a query plan.
6682
+ *
6683
+ * @param plan - Base query plan
6684
+ * @param options - Query options with sort/limit/cursor
6685
+ * @returns Plan with options applied
6686
+ */
6687
+ applyPlanOptions(plan, options) {
6511
6688
  if (!options.sort && options.limit === void 0 && options.cursor === void 0) {
6512
- return basePlan;
6689
+ return plan;
6513
6690
  }
6514
6691
  let indexedSort = false;
6515
6692
  let sortField;
@@ -6526,14 +6703,73 @@ var QueryOptimizer = class {
6526
6703
  }
6527
6704
  }
6528
6705
  return {
6529
- ...basePlan,
6706
+ ...plan,
6530
6707
  indexedSort,
6531
6708
  sort: sortField && sortDirection ? { field: sortField, direction: sortDirection } : void 0,
6532
6709
  limit: options.limit,
6533
6710
  cursor: options.cursor
6534
- // replaces offset
6535
6711
  };
6536
6712
  }
6713
+ /**
6714
+ * Extract the relevant index query for a hinted attribute from the query tree.
6715
+ * If the query directly references the attribute, build an index query from it.
6716
+ * For compound (logical) queries, extract the matching child predicate.
6717
+ * Falls back to { type: 'has' } when no matching predicate is found,
6718
+ * retrieving all entries from the index for post-filtering.
6719
+ * FTS query nodes also fall back to { type: 'has' } since full-text search
6720
+ * queries are not compatible with regular index lookups.
6721
+ *
6722
+ * @param query - Original query tree
6723
+ * @param attributeName - Hinted attribute name
6724
+ * @returns Index query for the hinted attribute
6725
+ */
6726
+ buildHintedIndexQuery(query, attributeName) {
6727
+ if (isSimpleQuery(query) && query.attribute === attributeName) {
6728
+ return this.buildIndexQuery(query);
6729
+ }
6730
+ if (isFTSQuery(query)) {
6731
+ return { type: "has" };
6732
+ }
6733
+ if (isLogicalQuery(query) && query.children) {
6734
+ for (const child of query.children) {
6735
+ if (isSimpleQuery(child) && child.attribute === attributeName) {
6736
+ return this.buildIndexQuery(child);
6737
+ }
6738
+ }
6739
+ }
6740
+ return { type: "has" };
6741
+ }
6742
+ /**
6743
+ * Try to optimize query as a point lookup.
6744
+ * Returns a point lookup step if query is an equality or IN query on primary key.
6745
+ *
6746
+ * @param query - Query to check
6747
+ * @returns Point lookup step or null
6748
+ */
6749
+ tryPointLookup(query) {
6750
+ if (!isSimpleQuery(query)) {
6751
+ return null;
6752
+ }
6753
+ const primaryKeyFields = ["_key", "key", "id"];
6754
+ if (!primaryKeyFields.includes(query.attribute)) {
6755
+ return null;
6756
+ }
6757
+ if (query.type === "eq") {
6758
+ return {
6759
+ type: "point-lookup",
6760
+ key: query.value,
6761
+ cost: 1
6762
+ };
6763
+ }
6764
+ if (query.type === "in" && query.values) {
6765
+ return {
6766
+ type: "multi-point-lookup",
6767
+ keys: query.values,
6768
+ cost: query.values.length
6769
+ };
6770
+ }
6771
+ return null;
6772
+ }
6537
6773
  /**
6538
6774
  * Optimize a single query node.
6539
6775
  */
@@ -6922,6 +7158,9 @@ var QueryOptimizer = class {
6922
7158
  */
6923
7159
  estimateCost(step) {
6924
7160
  switch (step.type) {
7161
+ case "point-lookup":
7162
+ case "multi-point-lookup":
7163
+ return step.cost;
6925
7164
  case "index-scan":
6926
7165
  return step.index.getRetrievalCost();
6927
7166
  case "full-scan":
@@ -6956,11 +7195,89 @@ var QueryOptimizer = class {
6956
7195
  return Number.MAX_SAFE_INTEGER;
6957
7196
  }
6958
7197
  }
7198
+ /**
7199
+ * Estimate distributed cost including network overhead.
7200
+ *
7201
+ * Network cost is assigned based on step type:
7202
+ * - full-scan: broadcast to all nodes (highest cost)
7203
+ * - index-scan: 0 if local partition, 5 if remote
7204
+ * - point-lookup: 0 if local key, 5 if remote
7205
+ * - intersection/union: aggregating results from multiple sources
7206
+ *
7207
+ * @param step - Plan step to estimate
7208
+ * @param context - Distributed query context (optional)
7209
+ * @returns Distributed cost breakdown
7210
+ */
7211
+ estimateDistributedCost(step, context) {
7212
+ const baseCost = this.estimateCost(step);
7213
+ if (!context?.isDistributed || context.nodeCount <= 1) {
7214
+ return {
7215
+ rows: baseCost,
7216
+ cpu: baseCost,
7217
+ network: 0,
7218
+ io: 0
7219
+ };
7220
+ }
7221
+ let networkCost = 0;
7222
+ switch (step.type) {
7223
+ case "full-scan":
7224
+ networkCost = context.nodeCount * 10;
7225
+ break;
7226
+ case "index-scan":
7227
+ networkCost = 5;
7228
+ break;
7229
+ case "point-lookup":
7230
+ networkCost = 5;
7231
+ break;
7232
+ case "multi-point-lookup":
7233
+ networkCost = Math.min(step.keys.length, context.nodeCount) * 5;
7234
+ break;
7235
+ case "intersection":
7236
+ case "union":
7237
+ networkCost = step.steps.length * 5;
7238
+ break;
7239
+ case "filter":
7240
+ return this.estimateDistributedCost(step.source, context);
7241
+ case "not":
7242
+ networkCost = context.nodeCount * 5;
7243
+ break;
7244
+ case "fts-scan":
7245
+ networkCost = Math.ceil(context.nodeCount / 2) * 5;
7246
+ break;
7247
+ case "fusion":
7248
+ networkCost = step.steps.reduce(
7249
+ (sum, s) => sum + this.estimateDistributedCost(s, context).network,
7250
+ 0
7251
+ );
7252
+ break;
7253
+ }
7254
+ return {
7255
+ rows: baseCost,
7256
+ cpu: baseCost,
7257
+ network: networkCost,
7258
+ io: context.usesStorage ? baseCost * 0.5 : 0
7259
+ };
7260
+ }
7261
+ /**
7262
+ * Get total distributed cost for a plan step.
7263
+ * Convenience method combining estimateDistributedCost and calculateTotalCost.
7264
+ *
7265
+ * @param step - Plan step to estimate
7266
+ * @param context - Distributed query context (optional)
7267
+ * @returns Weighted total cost
7268
+ */
7269
+ getTotalDistributedCost(step, context) {
7270
+ const distributedCost = this.estimateDistributedCost(step, context);
7271
+ return calculateTotalCost(distributedCost);
7272
+ }
6959
7273
  /**
6960
7274
  * Check if a plan step uses any indexes.
6961
7275
  */
6962
7276
  usesIndexes(step) {
6963
7277
  switch (step.type) {
7278
+ case "point-lookup":
7279
+ case "multi-point-lookup":
7280
+ return true;
6964
7281
  case "index-scan":
6965
7282
  return true;
6966
7283
  case "full-scan":
@@ -9141,6 +9458,24 @@ var IndexedLWWMap = class extends LWWMap {
9141
9458
  */
9142
9459
  executePlan(step) {
9143
9460
  switch (step.type) {
9461
+ case "point-lookup": {
9462
+ const key = step.key;
9463
+ const result = /* @__PURE__ */ new Set();
9464
+ if (this.get(key) !== void 0) {
9465
+ result.add(key);
9466
+ }
9467
+ return new SetResultSet(result, 1);
9468
+ }
9469
+ case "multi-point-lookup": {
9470
+ const result = /* @__PURE__ */ new Set();
9471
+ for (const key of step.keys) {
9472
+ const k = key;
9473
+ if (this.get(k) !== void 0) {
9474
+ result.add(k);
9475
+ }
9476
+ }
9477
+ return new SetResultSet(result, step.keys.length);
9478
+ }
9144
9479
  case "index-scan":
9145
9480
  return step.index.retrieve(step.query);
9146
9481
  case "full-scan": {
@@ -12199,6 +12534,504 @@ function getSearchDebugger() {
12199
12534
  function resetSearchDebugger() {
12200
12535
  globalSearchDebugger = null;
12201
12536
  }
12537
+
12538
+ // src/testing/VirtualClock.ts
12539
+ var RealClock = {
12540
+ now: () => Date.now()
12541
+ };
12542
+ var VirtualClock = class {
12543
+ /**
12544
+ * @param initialTime Starting timestamp in milliseconds (default: 0)
12545
+ */
12546
+ constructor(initialTime = 0) {
12547
+ if (!Number.isFinite(initialTime) || initialTime < 0) {
12548
+ throw new Error("Initial time must be a non-negative finite number");
12549
+ }
12550
+ this.currentTime = initialTime;
12551
+ }
12552
+ /**
12553
+ * Returns the current virtual time.
12554
+ * Time remains frozen until advance() or set() is called.
12555
+ */
12556
+ now() {
12557
+ return this.currentTime;
12558
+ }
12559
+ /**
12560
+ * Advances time forward by the specified milliseconds.
12561
+ * @param ms Milliseconds to advance (must be non-negative)
12562
+ */
12563
+ advance(ms) {
12564
+ if (!Number.isFinite(ms) || ms < 0) {
12565
+ throw new Error("Advance amount must be a non-negative finite number");
12566
+ }
12567
+ this.currentTime += ms;
12568
+ }
12569
+ /**
12570
+ * Sets the clock to a specific time.
12571
+ * Allows moving time forward or backward (useful for testing).
12572
+ * @param time Absolute timestamp in milliseconds
12573
+ */
12574
+ set(time) {
12575
+ if (!Number.isFinite(time) || time < 0) {
12576
+ throw new Error("Time must be a non-negative finite number");
12577
+ }
12578
+ this.currentTime = time;
12579
+ }
12580
+ /**
12581
+ * Resets the clock to zero.
12582
+ */
12583
+ reset() {
12584
+ this.currentTime = 0;
12585
+ }
12586
+ };
12587
+
12588
+ // src/testing/SeededRNG.ts
12589
+ var SeededRNG = class {
12590
+ /**
12591
+ * @param seed Integer seed value. Same seed = same sequence.
12592
+ */
12593
+ constructor(seed) {
12594
+ if (!Number.isInteger(seed)) {
12595
+ throw new Error("Seed must be an integer");
12596
+ }
12597
+ this.state = seed >>> 0;
12598
+ this.originalSeed = this.state;
12599
+ }
12600
+ /**
12601
+ * Returns the original seed used to construct this RNG.
12602
+ */
12603
+ getSeed() {
12604
+ return this.originalSeed;
12605
+ }
12606
+ /**
12607
+ * Generates the next random number in [0, 1).
12608
+ * Uses mulberry32 algorithm for deterministic, high-quality randomness.
12609
+ */
12610
+ random() {
12611
+ let t = this.state += 1831565813;
12612
+ t = Math.imul(t ^ t >>> 15, t | 1);
12613
+ t ^= t + Math.imul(t ^ t >>> 7, t | 61);
12614
+ this.state = t;
12615
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
12616
+ }
12617
+ /**
12618
+ * Generates a random integer in [min, max] (inclusive).
12619
+ * @param min Minimum value (inclusive)
12620
+ * @param max Maximum value (inclusive)
12621
+ */
12622
+ randomInt(min, max) {
12623
+ if (!Number.isInteger(min) || !Number.isInteger(max)) {
12624
+ throw new Error("Min and max must be integers");
12625
+ }
12626
+ if (min > max) {
12627
+ throw new Error("Min must be less than or equal to max");
12628
+ }
12629
+ const range = max - min + 1;
12630
+ return Math.floor(this.random() * range) + min;
12631
+ }
12632
+ /**
12633
+ * Generates a random boolean value.
12634
+ * @param probability Probability of returning true (default: 0.5)
12635
+ */
12636
+ randomBool(probability = 0.5) {
12637
+ if (probability < 0 || probability > 1) {
12638
+ throw new Error("Probability must be between 0 and 1");
12639
+ }
12640
+ return this.random() < probability;
12641
+ }
12642
+ /**
12643
+ * Shuffles an array in place using Fisher-Yates algorithm.
12644
+ * Returns the shuffled array.
12645
+ * @param array Array to shuffle
12646
+ */
12647
+ shuffle(array) {
12648
+ for (let i = array.length - 1; i > 0; i--) {
12649
+ const j = this.randomInt(0, i);
12650
+ [array[i], array[j]] = [array[j], array[i]];
12651
+ }
12652
+ return array;
12653
+ }
12654
+ /**
12655
+ * Picks a random element from an array.
12656
+ * @param array Array to pick from
12657
+ * @returns Random element, or undefined if array is empty
12658
+ */
12659
+ pick(array) {
12660
+ if (array.length === 0) return void 0;
12661
+ return array[this.randomInt(0, array.length - 1)];
12662
+ }
12663
+ /**
12664
+ * Resets the RNG to its original seed.
12665
+ * Useful for reproducing a sequence from the start.
12666
+ */
12667
+ reset() {
12668
+ this.state = this.originalSeed;
12669
+ }
12670
+ };
12671
+
12672
+ // src/testing/VirtualNetwork.ts
12673
+ var VirtualNetwork = class {
12674
+ constructor(rng, clock) {
12675
+ this.pendingMessages = [];
12676
+ this.rng = rng;
12677
+ this.clock = clock;
12678
+ this.config = {
12679
+ latencyMs: { min: 0, max: 0 },
12680
+ packetLossRate: 0,
12681
+ partitions: []
12682
+ };
12683
+ }
12684
+ /**
12685
+ * Updates network configuration.
12686
+ * Partially updates existing config with provided values.
12687
+ */
12688
+ configure(config) {
12689
+ if (config.latencyMs !== void 0) {
12690
+ const { min, max } = config.latencyMs;
12691
+ if (min < 0 || max < 0 || min > max) {
12692
+ throw new Error("Invalid latency range");
12693
+ }
12694
+ this.config.latencyMs = config.latencyMs;
12695
+ }
12696
+ if (config.packetLossRate !== void 0) {
12697
+ if (config.packetLossRate < 0 || config.packetLossRate > 1) {
12698
+ throw new Error("Packet loss rate must be between 0 and 1");
12699
+ }
12700
+ this.config.packetLossRate = config.packetLossRate;
12701
+ }
12702
+ if (config.partitions !== void 0) {
12703
+ this.config.partitions = config.partitions;
12704
+ }
12705
+ }
12706
+ /**
12707
+ * Sends a message through the network.
12708
+ * Subject to packet loss, latency, and partition rules.
12709
+ */
12710
+ send(from, to, payload) {
12711
+ if (this.rng.random() < this.config.packetLossRate) {
12712
+ return;
12713
+ }
12714
+ if (this.isPartitioned(from, to)) {
12715
+ return;
12716
+ }
12717
+ const latency = this.rng.randomInt(
12718
+ this.config.latencyMs.min,
12719
+ this.config.latencyMs.max
12720
+ );
12721
+ const scheduledTime = this.clock.now() + latency;
12722
+ this.pendingMessages.push({
12723
+ from,
12724
+ to,
12725
+ payload,
12726
+ scheduledTime
12727
+ });
12728
+ }
12729
+ /**
12730
+ * Creates a network partition between two groups.
12731
+ * Nodes in groupA cannot communicate with nodes in groupB.
12732
+ */
12733
+ partition(groupA, groupB) {
12734
+ this.config.partitions.push(groupA, groupB);
12735
+ }
12736
+ /**
12737
+ * Removes all network partitions.
12738
+ */
12739
+ heal() {
12740
+ this.config.partitions = [];
12741
+ }
12742
+ /**
12743
+ * Delivers all messages scheduled at or before the current time.
12744
+ * @returns Array of delivered messages
12745
+ */
12746
+ tick() {
12747
+ const currentTime = this.clock.now();
12748
+ const delivered = [];
12749
+ const remaining = [];
12750
+ for (const msg of this.pendingMessages) {
12751
+ if (msg.scheduledTime <= currentTime) {
12752
+ delivered.push(msg);
12753
+ } else {
12754
+ remaining.push(msg);
12755
+ }
12756
+ }
12757
+ this.pendingMessages = remaining;
12758
+ return delivered;
12759
+ }
12760
+ /**
12761
+ * Returns the number of messages currently in flight.
12762
+ */
12763
+ getPendingCount() {
12764
+ return this.pendingMessages.length;
12765
+ }
12766
+ /**
12767
+ * Clears all pending messages.
12768
+ */
12769
+ clear() {
12770
+ this.pendingMessages = [];
12771
+ }
12772
+ /**
12773
+ * Checks if two nodes are partitioned from each other.
12774
+ */
12775
+ isPartitioned(from, to) {
12776
+ for (let i = 0; i < this.config.partitions.length; i += 2) {
12777
+ const groupA = this.config.partitions[i];
12778
+ const groupB = this.config.partitions[i + 1];
12779
+ if (groupA.includes(from) && groupB.includes(to) || groupB.includes(from) && groupA.includes(to)) {
12780
+ return true;
12781
+ }
12782
+ }
12783
+ return false;
12784
+ }
12785
+ /**
12786
+ * Returns all pending messages (useful for debugging).
12787
+ */
12788
+ getPendingMessages() {
12789
+ return [...this.pendingMessages];
12790
+ }
12791
+ };
12792
+
12793
+ // src/testing/InvariantChecker.ts
12794
+ var InvariantChecker = class {
12795
+ constructor() {
12796
+ this.invariants = /* @__PURE__ */ new Map();
12797
+ }
12798
+ /**
12799
+ * Adds an invariant to be checked.
12800
+ * @param name Unique name for this invariant
12801
+ * @param check Function that returns true if invariant holds
12802
+ */
12803
+ addInvariant(name, check) {
12804
+ if (this.invariants.has(name)) {
12805
+ throw new Error(`Invariant '${name}' already exists`);
12806
+ }
12807
+ this.invariants.set(name, check);
12808
+ }
12809
+ /**
12810
+ * Removes an invariant by name.
12811
+ */
12812
+ removeInvariant(name) {
12813
+ return this.invariants.delete(name);
12814
+ }
12815
+ /**
12816
+ * Verifies all invariants against the provided state.
12817
+ * @returns Result with pass/fail status and list of failed invariants
12818
+ */
12819
+ verify(state) {
12820
+ const failures = [];
12821
+ for (const [name, check] of this.invariants.entries()) {
12822
+ try {
12823
+ if (!check(state)) {
12824
+ failures.push(name);
12825
+ }
12826
+ } catch (error) {
12827
+ failures.push(`${name} (exception: ${error instanceof Error ? error.message : String(error)})`);
12828
+ }
12829
+ }
12830
+ return {
12831
+ passed: failures.length === 0,
12832
+ failures
12833
+ };
12834
+ }
12835
+ /**
12836
+ * Returns the number of registered invariants.
12837
+ */
12838
+ get count() {
12839
+ return this.invariants.size;
12840
+ }
12841
+ /**
12842
+ * Clears all invariants.
12843
+ */
12844
+ clear() {
12845
+ this.invariants.clear();
12846
+ }
12847
+ };
12848
+ var CRDTInvariants = {
12849
+ /**
12850
+ * Verifies LWW-Map convergence: all maps contain the same values for same keys.
12851
+ */
12852
+ lwwConvergence: (maps) => {
12853
+ if (maps.length < 2) return true;
12854
+ const reference = maps[0];
12855
+ const refKeys = new Set(reference.allKeys());
12856
+ for (let i = 1; i < maps.length; i++) {
12857
+ const other = maps[i];
12858
+ const otherKeys = new Set(other.allKeys());
12859
+ if (refKeys.size !== otherKeys.size) return false;
12860
+ for (const key of refKeys) {
12861
+ if (!otherKeys.has(key)) return false;
12862
+ }
12863
+ for (const key of refKeys) {
12864
+ const refRecord = reference.getRecord(key);
12865
+ const otherRecord = other.getRecord(key);
12866
+ if (!refRecord || !otherRecord) {
12867
+ if (refRecord !== otherRecord) return false;
12868
+ continue;
12869
+ }
12870
+ if (refRecord.value !== otherRecord.value) return false;
12871
+ if (HLC.compare(refRecord.timestamp, otherRecord.timestamp) !== 0) {
12872
+ return false;
12873
+ }
12874
+ }
12875
+ }
12876
+ return true;
12877
+ },
12878
+ /**
12879
+ * Verifies OR-Map convergence: all maps contain the same values for same keys.
12880
+ */
12881
+ orMapConvergence: (maps) => {
12882
+ if (maps.length < 2) return true;
12883
+ const reference = maps[0];
12884
+ const refKeys = reference.allKeys();
12885
+ for (let i = 1; i < maps.length; i++) {
12886
+ const other = maps[i];
12887
+ const otherKeys = new Set(other.allKeys());
12888
+ if (refKeys.length !== otherKeys.size) return false;
12889
+ for (const key of refKeys) {
12890
+ if (!otherKeys.has(key)) return false;
12891
+ }
12892
+ for (const key of refKeys) {
12893
+ const refRecords = reference.getRecords(key);
12894
+ const otherRecords = other.getRecords(key);
12895
+ if (refRecords.length !== otherRecords.length) return false;
12896
+ const refSorted = [...refRecords].sort((a, b) => a.tag.localeCompare(b.tag));
12897
+ const otherSorted = [...otherRecords].sort((a, b) => a.tag.localeCompare(b.tag));
12898
+ for (let j = 0; j < refSorted.length; j++) {
12899
+ if (refSorted[j].tag !== otherSorted[j].tag) return false;
12900
+ if (refSorted[j].value !== otherSorted[j].value) return false;
12901
+ if (HLC.compare(refSorted[j].timestamp, otherSorted[j].timestamp) !== 0) {
12902
+ return false;
12903
+ }
12904
+ }
12905
+ }
12906
+ const refTombstones = new Set(reference.getTombstones());
12907
+ const otherTombstones = new Set(other.getTombstones());
12908
+ if (refTombstones.size !== otherTombstones.size) return false;
12909
+ for (const tag of refTombstones) {
12910
+ if (!otherTombstones.has(tag)) return false;
12911
+ }
12912
+ }
12913
+ return true;
12914
+ },
12915
+ /**
12916
+ * Verifies HLC monotonicity: timestamps are strictly increasing.
12917
+ */
12918
+ hlcMonotonicity: (timestamps) => {
12919
+ for (let i = 1; i < timestamps.length; i++) {
12920
+ if (HLC.compare(timestamps[i - 1], timestamps[i]) >= 0) {
12921
+ return false;
12922
+ }
12923
+ }
12924
+ return true;
12925
+ },
12926
+ /**
12927
+ * Verifies Merkle tree consistency: trees with same data have same root hash.
12928
+ */
12929
+ merkleConsistency: (trees) => {
12930
+ if (trees.length < 2) return true;
12931
+ const referenceHash = trees[0].getRootHash();
12932
+ for (let i = 1; i < trees.length; i++) {
12933
+ if (trees[i].getRootHash() !== referenceHash) {
12934
+ return false;
12935
+ }
12936
+ }
12937
+ return true;
12938
+ }
12939
+ };
12940
+
12941
+ // src/testing/ScenarioRunner.ts
12942
+ var ScenarioRunner = class {
12943
+ constructor(config) {
12944
+ if (!config.nodes || config.nodes.length === 0) {
12945
+ throw new Error("Scenario must have at least one node");
12946
+ }
12947
+ if (config.duration <= 0) {
12948
+ throw new Error("Duration must be positive");
12949
+ }
12950
+ this.seed = config.seed ?? Math.floor(Math.random() * 2147483647);
12951
+ this.config = {
12952
+ ...config,
12953
+ seed: this.seed,
12954
+ tickInterval: config.tickInterval ?? 1
12955
+ };
12956
+ this.clock = new VirtualClock(0);
12957
+ this.rng = new SeededRNG(this.seed);
12958
+ this.network = new VirtualNetwork(this.rng, this.clock);
12959
+ }
12960
+ /**
12961
+ * Returns the seed used for this scenario.
12962
+ */
12963
+ getSeed() {
12964
+ return this.seed;
12965
+ }
12966
+ /**
12967
+ * Returns the virtual clock instance.
12968
+ */
12969
+ getClock() {
12970
+ return this.clock;
12971
+ }
12972
+ /**
12973
+ * Returns the seeded RNG instance.
12974
+ */
12975
+ getRNG() {
12976
+ return this.rng;
12977
+ }
12978
+ /**
12979
+ * Returns the virtual network instance.
12980
+ */
12981
+ getNetwork() {
12982
+ return this.network;
12983
+ }
12984
+ /**
12985
+ * Returns the list of nodes in this scenario.
12986
+ */
12987
+ getNodes() {
12988
+ return [...this.config.nodes];
12989
+ }
12990
+ /**
12991
+ * Executes the simulation scenario.
12992
+ *
12993
+ * @param setup Called once before simulation starts. Initialize state here.
12994
+ * @param step Called on each tick. Perform operations and message delivery.
12995
+ * @param invariants Checker for verifying correctness throughout execution.
12996
+ * @returns Result with pass/fail status and captured state
12997
+ */
12998
+ run(setup, step, invariants) {
12999
+ const finalStates = /* @__PURE__ */ new Map();
13000
+ const invariantFailures = [];
13001
+ setup(this);
13002
+ let tickCount = 0;
13003
+ const tickInterval = this.config.tickInterval;
13004
+ const endTime = this.config.duration;
13005
+ while (this.clock.now() < endTime) {
13006
+ this.clock.advance(tickInterval);
13007
+ tickCount++;
13008
+ step(this, tickCount);
13009
+ const delivered = this.network.tick();
13010
+ if (delivered.length > 0) {
13011
+ finalStates.set(`_tick_${tickCount}_delivered`, delivered.length);
13012
+ }
13013
+ }
13014
+ const result = invariants.verify(null);
13015
+ if (!result.passed) {
13016
+ invariantFailures.push(...result.failures);
13017
+ }
13018
+ return {
13019
+ seed: this.seed,
13020
+ passed: invariantFailures.length === 0,
13021
+ ticks: tickCount,
13022
+ invariantFailures,
13023
+ finalStates
13024
+ };
13025
+ }
13026
+ /**
13027
+ * Stores state for a node (useful for capturing final state).
13028
+ */
13029
+ setState(nodeId, state) {
13030
+ if (!this.config.nodes.includes(nodeId)) {
13031
+ throw new Error(`Unknown node: ${nodeId}`);
13032
+ }
13033
+ }
13034
+ };
12202
13035
  // Annotate the CommonJS export names for ESM import in node:
12203
13036
  0 && (module.exports = {
12204
13037
  AuthFailMessageSchema,
@@ -12207,7 +13040,9 @@ function resetSearchDebugger() {
12207
13040
  BatchMessageSchema,
12208
13041
  BuiltInProcessors,
12209
13042
  BuiltInResolvers,
13043
+ COST_WEIGHTS,
12210
13044
  CRDTDebugger,
13045
+ CRDTInvariants,
12211
13046
  ClientOpMessageSchema,
12212
13047
  ClientOpSchema,
12213
13048
  ClusterSearchReqMessageSchema,
@@ -12249,6 +13084,7 @@ function resetSearchDebugger() {
12249
13084
  DEFAULT_RESOLVER_RATE_LIMITS,
12250
13085
  DEFAULT_STOP_WORDS,
12251
13086
  DEFAULT_WRITE_CONCERN_TIMEOUT,
13087
+ DeltaRecordSchema,
12252
13088
  ENGLISH_STOPWORDS,
12253
13089
  EntryProcessBatchRequestSchema,
12254
13090
  EntryProcessBatchResponseSchema,
@@ -12268,12 +13104,20 @@ function resetSearchDebugger() {
12268
13104
  GcPrunePayloadSchema,
12269
13105
  HLC,
12270
13106
  HashIndex,
13107
+ HttpQueryRequestSchema,
13108
+ HttpQueryResultSchema,
13109
+ HttpSearchRequestSchema,
13110
+ HttpSearchResultSchema,
13111
+ HttpSyncErrorSchema,
13112
+ HttpSyncRequestSchema,
13113
+ HttpSyncResponseSchema,
12271
13114
  HybridQueryDeltaPayloadSchema,
12272
13115
  HybridQueryRespPayloadSchema,
12273
13116
  IndexRegistry,
12274
13117
  IndexedLWWMap,
12275
13118
  IndexedORMap,
12276
13119
  IntersectionResultSet,
13120
+ InvariantChecker,
12277
13121
  InvertedIndex,
12278
13122
  JournalEventDataSchema,
12279
13123
  JournalEventMessageSchema,
@@ -12294,6 +13138,7 @@ function resetSearchDebugger() {
12294
13138
  LockReleasedPayloadSchema,
12295
13139
  LockRequestSchema,
12296
13140
  LowercaseFilter,
13141
+ MapDeltaSchema,
12297
13142
  MaxLengthFilter,
12298
13143
  MergeRejectedMessageSchema,
12299
13144
  MerkleReqBucketMessageSchema,
@@ -12338,10 +13183,12 @@ function resetSearchDebugger() {
12338
13183
  QueryUpdateMessageSchema,
12339
13184
  QueryUpdatePayloadSchema,
12340
13185
  RESOLVER_FORBIDDEN_PATTERNS,
13186
+ RealClock,
12341
13187
  ReciprocalRankFusion,
12342
13188
  RegisterResolverRequestSchema,
12343
13189
  RegisterResolverResponseSchema,
12344
13190
  Ringbuffer,
13191
+ ScenarioRunner,
12345
13192
  SearchCursor,
12346
13193
  SearchDebugger,
12347
13194
  SearchMessageSchema,
@@ -12356,6 +13203,7 @@ function resetSearchDebugger() {
12356
13203
  SearchUpdateMessageSchema,
12357
13204
  SearchUpdatePayloadSchema,
12358
13205
  SearchUpdateTypeSchema,
13206
+ SeededRNG,
12359
13207
  ServerBatchEventMessageSchema,
12360
13208
  ServerEventMessageSchema,
12361
13209
  ServerEventPayloadSchema,
@@ -12367,6 +13215,7 @@ function resetSearchDebugger() {
12367
13215
  StandingQueryRegistry,
12368
13216
  StopWordFilter,
12369
13217
  SyncInitMessageSchema,
13218
+ SyncMapEntrySchema,
12370
13219
  SyncResetRequiredPayloadSchema,
12371
13220
  SyncRespBucketsMessageSchema,
12372
13221
  SyncRespLeafMessageSchema,
@@ -12382,11 +13231,14 @@ function resetSearchDebugger() {
12382
13231
  UniqueFilter,
12383
13232
  UnregisterResolverRequestSchema,
12384
13233
  UnregisterResolverResponseSchema,
13234
+ VirtualClock,
13235
+ VirtualNetwork,
12385
13236
  WRITE_CONCERN_ORDER,
12386
13237
  WhitespaceTokenizer,
12387
13238
  WordBoundaryTokenizer,
12388
13239
  WriteConcern,
12389
13240
  WriteConcernSchema,
13241
+ calculateTotalCost,
12390
13242
  combineHashes,
12391
13243
  compareHLCTimestamps,
12392
13244
  compareTimestamps,