@powersync/service-module-mongodb 0.21.2 → 0.22.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.
Files changed (90) hide show
  1. package/CHANGELOG.md +51 -0
  2. package/benchmarks/env.ts +11 -0
  3. package/benchmarks/replication_branch_throughput.benchmark.ts +240 -0
  4. package/dist/api/MongoRouteAPIAdapter.d.ts +6 -0
  5. package/dist/api/MongoRouteAPIAdapter.js +21 -2
  6. package/dist/api/MongoRouteAPIAdapter.js.map +1 -1
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/module/MongoModule.d.ts +1 -1
  11. package/dist/module/MongoModule.js +1 -0
  12. package/dist/module/MongoModule.js.map +1 -1
  13. package/dist/replication/ChangeStream.d.ts +13 -3
  14. package/dist/replication/ChangeStream.js +130 -196
  15. package/dist/replication/ChangeStream.js.map +1 -1
  16. package/dist/replication/ChangeStreamReplicationJob.d.ts +4 -1
  17. package/dist/replication/ChangeStreamReplicationJob.js +19 -8
  18. package/dist/replication/ChangeStreamReplicationJob.js.map +1 -1
  19. package/dist/replication/ChangeStreamReplicator.d.ts +4 -0
  20. package/dist/replication/ChangeStreamReplicator.js +6 -0
  21. package/dist/replication/ChangeStreamReplicator.js.map +1 -1
  22. package/dist/replication/MongoReplicationQueryProvider.d.ts +85 -0
  23. package/dist/replication/MongoReplicationQueryProvider.js +23 -0
  24. package/dist/replication/MongoReplicationQueryProvider.js.map +1 -0
  25. package/dist/replication/MongoReplicationStream.d.ts +74 -0
  26. package/dist/replication/MongoReplicationStream.js +228 -0
  27. package/dist/replication/MongoReplicationStream.js.map +1 -0
  28. package/dist/replication/MongoReplicationStreamTypes.d.ts +157 -0
  29. package/dist/replication/MongoReplicationStreamTypes.js +19 -0
  30. package/dist/replication/MongoReplicationStreamTypes.js.map +1 -0
  31. package/dist/replication/MongoSnapshotQuery.d.ts +2 -0
  32. package/dist/replication/MongoSnapshotQuery.js +12 -2
  33. package/dist/replication/MongoSnapshotQuery.js.map +1 -1
  34. package/dist/replication/MongoSnapshotter.d.ts +7 -2
  35. package/dist/replication/MongoSnapshotter.js +90 -88
  36. package/dist/replication/MongoSnapshotter.js.map +1 -1
  37. package/dist/replication/RawChangeStream.d.ts +1 -1
  38. package/dist/replication/RawChangeStream.js +1 -1
  39. package/dist/replication/RawChangeStream.js.map +1 -1
  40. package/dist/replication/estimateFilteredSnapshotCount.d.ts +12 -0
  41. package/dist/replication/estimateFilteredSnapshotCount.js +79 -0
  42. package/dist/replication/estimateFilteredSnapshotCount.js.map +1 -0
  43. package/dist/replication/replication-index.d.ts +7 -0
  44. package/dist/replication/replication-index.js +7 -0
  45. package/dist/replication/replication-index.js.map +1 -1
  46. package/dist/test-utils/ChangeStreamTestContext.d.ts +131 -0
  47. package/dist/test-utils/ChangeStreamTestContext.js +390 -0
  48. package/dist/test-utils/ChangeStreamTestContext.js.map +1 -0
  49. package/dist/test-utils/test-utils-index.d.ts +1 -0
  50. package/dist/test-utils/test-utils-index.js +2 -0
  51. package/dist/test-utils/test-utils-index.js.map +1 -0
  52. package/package.json +11 -10
  53. package/src/api/MongoRouteAPIAdapter.ts +26 -2
  54. package/src/index.ts +1 -0
  55. package/src/module/MongoModule.ts +2 -1
  56. package/src/replication/ChangeStream.ts +143 -226
  57. package/src/replication/ChangeStreamReplicationJob.ts +21 -9
  58. package/src/replication/ChangeStreamReplicator.ts +9 -0
  59. package/src/replication/MongoReplicationQueryProvider.ts +106 -0
  60. package/src/replication/MongoReplicationStream.ts +314 -0
  61. package/src/replication/MongoReplicationStreamTypes.ts +169 -0
  62. package/src/replication/MongoSnapshotQuery.ts +19 -3
  63. package/src/replication/MongoSnapshotter.ts +101 -92
  64. package/src/replication/RawChangeStream.ts +2 -2
  65. package/src/replication/estimateFilteredSnapshotCount.ts +93 -0
  66. package/src/replication/replication-index.ts +7 -0
  67. package/src/test-utils/ChangeStreamTestContext.ts +520 -0
  68. package/src/test-utils/test-utils-index.ts +1 -0
  69. package/test/src/change_event_memory.test.ts +33 -0
  70. package/test/src/change_stream.test.ts +3 -3
  71. package/test/src/change_stream_abort.test.ts +110 -0
  72. package/test/src/change_stream_test_setup.ts +38 -0
  73. package/test/src/chunked_snapshot.test.ts +3 -3
  74. package/test/src/documentdb_mode.test.ts +3 -3
  75. package/test/src/filtering_example.test.ts +65 -0
  76. package/test/src/filtering_lifecycle.test.ts +101 -0
  77. package/test/src/query_provider_availability.test.ts +77 -0
  78. package/test/src/query_provider_diagnostics.test.ts +55 -0
  79. package/test/src/replication_stream.test.ts +688 -0
  80. package/test/src/resume.test.ts +10 -4
  81. package/test/src/resuming_snapshots.test.ts +3 -3
  82. package/test/src/slow_tests.test.ts +3 -3
  83. package/test/src/snapshot_count.test.ts +146 -0
  84. package/test/src/snapshot_count_integration.test.ts +70 -0
  85. package/test/src/snapshot_query_provider.test.ts +122 -0
  86. package/test/src/stream_progress.test.ts +334 -0
  87. package/test/tsconfig.json +2 -2
  88. package/tsconfig.tsbuildinfo +1 -1
  89. package/vitest.benchmark.config.ts +15 -0
  90. package/test/src/change_stream_utils.ts +0 -375
@@ -1 +1 @@
1
- {"version":3,"file":"ChangeStreamReplicationJob.js","sourceRoot":"","sources":["../../src/replication/ChangeStreamReplicationJob.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChangeStreamReplicationJob.js","sourceRoot":"","sources":["../../src/replication/ChangeStreamReplicationJob.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,16 @@
1
1
  import { replication, storage } from '@powersync/service-core';
2
2
  import { ChangeStreamReplicationJob } from './ChangeStreamReplicationJob.js';
3
3
  import { ConnectionManagerFactory } from './ConnectionManagerFactory.js';
4
+ import { MongoReplicationQueryProviderFactory } from './MongoReplicationQueryProvider.js';
4
5
  export interface ChangeStreamReplicatorOptions extends replication.AbstractReplicatorOptions {
5
6
  connectionFactory: ConnectionManagerFactory;
7
+ createReplicationQueryProvider?: MongoReplicationQueryProviderFactory;
6
8
  }
7
9
  export declare class ChangeStreamReplicator extends replication.AbstractReplicator<ChangeStreamReplicationJob> {
8
10
  private readonly connectionFactory;
11
+ private readonly createReplicationQueryProvider;
9
12
  constructor(options: ChangeStreamReplicatorOptions);
13
+ protected get defaultSchema(): string;
10
14
  createJob(options: replication.CreateJobOptions): ChangeStreamReplicationJob;
11
15
  cleanUp(syncRulesStorage: storage.SyncRulesBucketStorage): Promise<void>;
12
16
  stop(): Promise<void>;
@@ -3,9 +3,14 @@ import { MongoModule } from '../module/MongoModule.js';
3
3
  import { ChangeStreamReplicationJob } from './ChangeStreamReplicationJob.js';
4
4
  export class ChangeStreamReplicator extends replication.AbstractReplicator {
5
5
  connectionFactory;
6
+ createReplicationQueryProvider;
6
7
  constructor(options) {
7
8
  super(options);
8
9
  this.connectionFactory = options.connectionFactory;
10
+ this.createReplicationQueryProvider = options.createReplicationQueryProvider;
11
+ }
12
+ get defaultSchema() {
13
+ return this.connectionFactory.dbConnectionConfig.database;
9
14
  }
10
15
  createJob(options) {
11
16
  return new ChangeStreamReplicationJob({
@@ -13,6 +18,7 @@ export class ChangeStreamReplicator extends replication.AbstractReplicator {
13
18
  storage: options.storage,
14
19
  metrics: this.metrics,
15
20
  connectionFactory: this.connectionFactory,
21
+ createReplicationQueryProvider: this.createReplicationQueryProvider,
16
22
  lock: options.lock,
17
23
  rateLimiter: this.rateLimiter
18
24
  });
@@ -1 +1 @@
1
- {"version":3,"file":"ChangeStreamReplicator.js","sourceRoot":"","sources":["../../src/replication/ChangeStreamReplicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAW,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAO7E,MAAM,OAAO,sBAAuB,SAAQ,WAAW,CAAC,kBAA8C;IACnF,iBAAiB,CAA2B;IAE7D,YAAY,OAAsC;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;IACrD,CAAC;IAED,SAAS,CAAC,OAAqC;QAC7C,OAAO,IAAI,0BAA0B,CAAC;YACpC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC;YACzD,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,gBAAgD;QAC5D,4BAA4B;IAC9B,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,OAAO,MAAM,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IACrF,CAAC;CACF"}
1
+ {"version":3,"file":"ChangeStreamReplicator.js","sourceRoot":"","sources":["../../src/replication/ChangeStreamReplicator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAW,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AACvD,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAS7E,MAAM,OAAO,sBAAuB,SAAQ,WAAW,CAAC,kBAA8C;IACnF,iBAAiB,CAA2B;IAC5C,8BAA8B,CAAmD;IAElG,YAAY,OAAsC;QAChD,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,iBAAiB,GAAG,OAAO,CAAC,iBAAiB,CAAC;QACnD,IAAI,CAAC,8BAA8B,GAAG,OAAO,CAAC,8BAA8B,CAAC;IAC/E,CAAC;IAED,IAAc,aAAa;QACzB,OAAO,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,QAAQ,CAAC;IAC5D,CAAC;IAED,SAAS,CAAC,OAAqC;QAC7C,OAAO,IAAI,0BAA0B,CAAC;YACpC,EAAE,EAAE,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC;YACzD,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,iBAAiB,EAAE,IAAI,CAAC,iBAAiB;YACzC,8BAA8B,EAAE,IAAI,CAAC,8BAA8B;YACnE,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,gBAAgD;QAC5D,4BAA4B;IAC9B,CAAC;IAED,KAAK,CAAC,IAAI;QACR,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,MAAM,IAAI,CAAC,iBAAiB,CAAC,QAAQ,EAAE,CAAC;IAC1C,CAAC;IAED,KAAK,CAAC,cAAc;QAClB,OAAO,MAAM,WAAW,CAAC,cAAc,CAAC,IAAI,CAAC,iBAAiB,CAAC,kBAAkB,CAAC,CAAC;IACrF,CAAC;CACF"}
@@ -0,0 +1,85 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { SourceTable } from '@powersync/service-core';
3
+ import { HydratedSyncConfig } from '@powersync/service-sync-rules';
4
+ import { MongoManager } from './MongoManager.js';
5
+ import type { MongoReplicationStreamBatch, MongoReplicationStreamContext } from './MongoReplicationStreamTypes.js';
6
+ /**
7
+ * Sync config and source namespace information used to construct a provider for a replication attempt.
8
+ */
9
+ export interface MongoReplicationQueryProviderContext {
10
+ /**
11
+ * Hydrated sync config from which the provider can read its connection-specific options.
12
+ */
13
+ syncConfig: HydratedSyncConfig;
14
+ /**
15
+ * Identifies the source connection whose options and tables this provider handles.
16
+ */
17
+ connectionTag: string;
18
+ /**
19
+ * MongoDB database used to resolve table references without an explicit schema.
20
+ */
21
+ defaultSchema: string;
22
+ }
23
+ /**
24
+ * Adapts snapshot selection and the stream of source changes for one replication implementation.
25
+ * The MongoDB module owns cursor options, namespaces, BSON parsing, large-event reassembly and durable progress.
26
+ */
27
+ export interface MongoReplicationQueryProvider {
28
+ /**
29
+ * Validate source capabilities before either snapshot queries or streaming cursors are opened.
30
+ * Throw if required capabilities are unavailable. Both the stream and snapshotter may call this hook
31
+ * on the same provider, so validation must be safe to repeat.
32
+ */
33
+ validateSource?(options: {
34
+ connectionManager: MongoManager;
35
+ isDocumentDb: boolean;
36
+ }): Promise<void>;
37
+ /**
38
+ * Call context.open() with any additional stages/pre-image options. For filtering, pass its result
39
+ * to filterMongoReplicationStream({ batches, filter }) with a MongoReplicationFilter callback.
40
+ * The helper preserves checkpoints, DDL, batch boundaries, buffered-change flags and safe progress,
41
+ * counts excluded events, and closes the source iterator on failure or early exit.
42
+ * The default provider returns the opener's batches directly.
43
+ * Each invocation is independent and also serves snapshot barriers and resume validation; keep
44
+ * filter state local to that invocation. Snapshot selection must agree with streaming decisions.
45
+ */
46
+ openChangeStream(context: MongoReplicationStreamContext): AsyncIterableIterator<MongoReplicationStreamBatch>;
47
+ /**
48
+ * Returns an additional MongoDB find predicate for a physical source table.
49
+ * Return null to snapshot without an additional filter. Snapshot selection must agree with the
50
+ * provider's streaming rules so both paths replicate the same set of documents.
51
+ * Expressions can be supplied as { $expr: ... }. The snapshot query combines the filter with its
52
+ * _id continuation predicate and uses simple collation whenever a filter is supplied.
53
+ */
54
+ getSnapshotFilter(table: SourceTable): mongo.Filter<mongo.Document> | null;
55
+ }
56
+ /**
57
+ * Creates a provider shared by a replication attempt's change stream, snapshotter and source probes.
58
+ */
59
+ export type MongoReplicationQueryProviderFactory = (context: MongoReplicationQueryProviderContext) => MongoReplicationQueryProvider;
60
+ /**
61
+ * Uses the standard MongoDB reader and snapshot selection without additional filtering or event translation.
62
+ */
63
+ export declare const DEFAULT_MONGO_REPLICATION_QUERY_PROVIDER: MongoReplicationQueryProvider;
64
+ /**
65
+ * Places provider stages after namespace selection and before optional large-event splitting.
66
+ * This lets provider stages inspect complete events; the shared reader reassembles any resulting fragments.
67
+ */
68
+ export declare function buildMongoChangeStreamPipeline(options: {
69
+ /**
70
+ * Shared reader options, including resume position, stream scope and requested document images.
71
+ */
72
+ streamOptions: mongo.ChangeStreamOptions & mongo.Document;
73
+ /**
74
+ * Namespace predicate restricting the stream to the selected source collections and checkpoint events.
75
+ */
76
+ namespaceMatch: mongo.Document;
77
+ /**
78
+ * Additional aggregation stages supplied by the provider, in execution order.
79
+ */
80
+ pipelineStages: mongo.Document[];
81
+ /**
82
+ * Append MongoDB's large-event split stage. Disabled for DocumentDB by the shared reader.
83
+ */
84
+ includeSplitLargeEvent: boolean;
85
+ }): mongo.Document[];
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Uses the standard MongoDB reader and snapshot selection without additional filtering or event translation.
3
+ */
4
+ export const DEFAULT_MONGO_REPLICATION_QUERY_PROVIDER = {
5
+ getSnapshotFilter: () => null,
6
+ openChangeStream: ({ open }) => open({})
7
+ };
8
+ /**
9
+ * Places provider stages after namespace selection and before optional large-event splitting.
10
+ * This lets provider stages inspect complete events; the shared reader reassembles any resulting fragments.
11
+ */
12
+ export function buildMongoChangeStreamPipeline(options) {
13
+ const pipeline = [
14
+ { $changeStream: options.streamOptions },
15
+ { $match: options.namespaceMatch },
16
+ ...options.pipelineStages
17
+ ];
18
+ if (options.includeSplitLargeEvent) {
19
+ pipeline.push({ $changeStreamSplitLargeEvent: {} });
20
+ }
21
+ return pipeline;
22
+ }
23
+ //# sourceMappingURL=MongoReplicationQueryProvider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MongoReplicationQueryProvider.js","sourceRoot":"","sources":["../../src/replication/MongoReplicationQueryProvider.ts"],"names":[],"mappings":"AAgEA;;GAEG;AACH,MAAM,CAAC,MAAM,wCAAwC,GAAkC;IACrF,iBAAiB,EAAE,GAAG,EAAE,CAAC,IAAI;IAC7B,gBAAgB,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,8BAA8B,CAAC,OAiB9C;IACC,MAAM,QAAQ,GAAqB;QACjC,EAAE,aAAa,EAAE,OAAO,CAAC,aAAa,EAAE;QACxC,EAAE,MAAM,EAAE,OAAO,CAAC,cAAc,EAAE;QAClC,GAAG,OAAO,CAAC,cAAc;KAC1B,CAAC;IAEF,IAAI,OAAO,CAAC,sBAAsB,EAAE,CAAC;QACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,4BAA4B,EAAE,EAAE,EAAE,CAAC,CAAC;IACtD,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
@@ -0,0 +1,74 @@
1
+ import { mongo } from '@powersync/lib-service-mongodb';
2
+ import { MongoReplicationQueryProvider } from './MongoReplicationQueryProvider.js';
3
+ import { MongoReplicationFilterOptions, MongoReplicationParserOptions, MongoReplicationStreamBatch, MongoReplicationStreamBatchMetadata, MongoReplicationStreamChange, RawMongoReplicationStreamBatch } from './MongoReplicationStreamTypes.js';
4
+ import { ChangeStreamBatch, ProjectedChangeStreamDocument, RawChangeStreamOptions } from './RawChangeStream.js';
5
+ /**
6
+ * Wraps changes with a single-use iterator. Caches the token and metadata after successful exhaustion.
7
+ */
8
+ export declare function createMongoReplicationStreamBatch({ events, resolveResumeToken, resolveMetadata }: {
9
+ /**
10
+ * Complete changes, optionally produced by a lazy parsing or filtering generator.
11
+ */
12
+ events: Iterable<MongoReplicationStreamChange>;
13
+ /**
14
+ * Compute a safe resume token once after successful exhaustion, using the final parser state.
15
+ */
16
+ resolveResumeToken: () => mongo.ResumeToken | undefined;
17
+ /**
18
+ * Compute this batch's final statistics after exhaustion. Defaults to no filtering.
19
+ */
20
+ resolveMetadata?: () => MongoReplicationStreamBatchMetadata;
21
+ }): MongoReplicationStreamBatch;
22
+ /**
23
+ * Filter complete data changes while retaining source batch boundaries and recovery bookkeeping.
24
+ * Return MongoReplicationFilterResult.KEEP to forward a change, EXCLUDE to omit it, or DELETE for an exit.
25
+ * Synthetic deletes retain the source identity, resume token and transaction metadata.
26
+ * The callback runs synchronously and lazily; failures and early exits close the underlying stream.
27
+ */
28
+ export declare function filterMongoReplicationStream({ batches, filter }: MongoReplicationFilterOptions): AsyncGenerator<MongoReplicationStreamBatch>;
29
+ /**
30
+ * Shared opening path for ongoing replication, snapshot barriers and resume validation.
31
+ */
32
+ export declare function openMongoReplicationStream({ db, queryProvider, namespaceFilter, isDocumentDb, usePostImages, position, skipInitialTimestamp, options, onBatch }: {
33
+ db: mongo.Db;
34
+ queryProvider: MongoReplicationQueryProvider;
35
+ namespaceFilter: {
36
+ $match: mongo.Document;
37
+ multipleDatabases: boolean;
38
+ };
39
+ isDocumentDb: boolean;
40
+ usePostImages: boolean;
41
+ position: {
42
+ resumeAfter?: mongo.ResumeToken | null;
43
+ startAfter?: mongo.Timestamp | null;
44
+ } | null;
45
+ /**
46
+ * Legacy streaming positions exclude the initial timestamp; snapshot barrier probes must include it.
47
+ */
48
+ skipInitialTimestamp?: boolean;
49
+ options: RawChangeStreamOptions;
50
+ onBatch?: (batch: ChangeStreamBatch) => Disposable | void;
51
+ }): AsyncIterableIterator<MongoReplicationStreamBatch>;
52
+ /**
53
+ * Creates a stateful parser for one raw MongoDB stream. Parses BSON entries, joins split-event
54
+ * fragments across batches, normalizes namespaces and skips events covered by legacy timestamps.
55
+ * After processing a batch, callers can request safe progress. Check completion on natural EOF,
56
+ * not cancellation.
57
+ */
58
+ export declare function createMongoReplicationStreamParser({ defaultSchema, multipleDatabases, startAfter, signal, logger }: MongoReplicationParserOptions): {
59
+ parse(rawEvent: Buffer): ProjectedChangeStreamDocument | null;
60
+ /**
61
+ * Returns the given transport token if it is safe to persist, or undefined while a split event is unfinished.
62
+ */
63
+ getSafeResumeToken(resumeToken: mongo.ResumeToken): unknown;
64
+ assertComplete(): void;
65
+ };
66
+ /**
67
+ * Wrap raw batches in lazy event iterables. BSON parsing and split-event assembly happen
68
+ * as consumers request events, without building a parsed array. After exhaustion, each batch retains
69
+ * its own resume-token result even when later batches change the parser state.
70
+ * Consume each batch completely before requesting the next; returning early closes the source.
71
+ */
72
+ export declare function parseMongoReplicationStream({ batches, ...options }: MongoReplicationParserOptions & {
73
+ batches: AsyncIterable<RawMongoReplicationStreamBatch>;
74
+ }): AsyncGenerator<MongoReplicationStreamBatch>;
@@ -0,0 +1,228 @@
1
+ import { ReplicationAssertionError } from '@powersync/lib-services-framework';
2
+ import { buildMongoChangeStreamPipeline } from './MongoReplicationQueryProvider.js';
3
+ import { MongoReplicationFilterResult } from './MongoReplicationStreamTypes.js';
4
+ import { parseChangeDocument, rawChangeStream } from './RawChangeStream.js';
5
+ import { CHECKPOINTS_COLLECTION } from './replication-utils.js';
6
+ /**
7
+ * Wraps changes with a single-use iterator. Caches the token and metadata after successful exhaustion.
8
+ */
9
+ export function createMongoReplicationStreamBatch({ events, resolveResumeToken, resolveMetadata = () => ({ filteredCount: null }) }) {
10
+ let started = false;
11
+ let complete = false;
12
+ let resumeToken;
13
+ let metadata;
14
+ function assertComplete() {
15
+ // Progress is only safe to read after every event has been consumed and finalization succeeds.
16
+ if (!complete) {
17
+ throw new ReplicationAssertionError('Consume all batch events before requesting token or metadata');
18
+ }
19
+ }
20
+ return {
21
+ events: {
22
+ [Symbol.iterator]() {
23
+ // A second pass would repeat parsing/filtering against state that has already advanced.
24
+ if (started) {
25
+ throw new ReplicationAssertionError('Batch events can only be consumed once');
26
+ }
27
+ started = true;
28
+ return iterate();
29
+ }
30
+ },
31
+ getResumeToken() {
32
+ assertComplete();
33
+ return resumeToken;
34
+ },
35
+ get metadata() {
36
+ assertComplete();
37
+ return metadata;
38
+ }
39
+ };
40
+ function* iterate() {
41
+ // Delegate lazily; an error or early return skips the finalization below.
42
+ yield* events;
43
+ // Cache this batch's final results before later batches can change the parser or filter state.
44
+ resumeToken = resolveResumeToken();
45
+ metadata = Object.freeze({ ...resolveMetadata() });
46
+ complete = true;
47
+ }
48
+ }
49
+ /**
50
+ * Filter complete data changes while retaining source batch boundaries and recovery bookkeeping.
51
+ * Return MongoReplicationFilterResult.KEEP to forward a change, EXCLUDE to omit it, or DELETE for an exit.
52
+ * Synthetic deletes retain the source identity, resume token and transaction metadata.
53
+ * The callback runs synchronously and lazily; failures and early exits close the underlying stream.
54
+ */
55
+ export async function* filterMongoReplicationStream({ batches, filter }) {
56
+ for await (const sourceBatch of batches) {
57
+ let filteredCount = 0;
58
+ const batch = createMongoReplicationStreamBatch({
59
+ events: filterEvents(),
60
+ resolveResumeToken: () => sourceBatch.getResumeToken(),
61
+ resolveMetadata: () => ({ filteredCount: (sourceBatch.metadata.filteredCount ?? 0) + filteredCount })
62
+ });
63
+ yield batch;
64
+ // Assert that the consumer exhausted this batch before requesting the next one, even if every event
65
+ // was filtered out. The token value is unused; getResumeToken() throws if consumption is incomplete.
66
+ batch.getResumeToken();
67
+ function* filterEvents() {
68
+ for (const change of sourceBatch.events) {
69
+ const { event } = change;
70
+ if ((event.operationType != 'insert' &&
71
+ event.operationType != 'update' &&
72
+ event.operationType != 'replace' &&
73
+ event.operationType != 'delete') ||
74
+ event.ns.coll == CHECKPOINTS_COLLECTION) {
75
+ yield change;
76
+ continue;
77
+ }
78
+ const result = filter(event);
79
+ if (result == MongoReplicationFilterResult.EXCLUDE) {
80
+ filteredCount++;
81
+ }
82
+ else if (result == MongoReplicationFilterResult.DELETE) {
83
+ yield { ...change, event: { ...event, operationType: 'delete' } };
84
+ }
85
+ else {
86
+ yield change;
87
+ }
88
+ }
89
+ }
90
+ }
91
+ }
92
+ /**
93
+ * Shared opening path for ongoing replication, snapshot barriers and resume validation.
94
+ */
95
+ export function openMongoReplicationStream({ db, queryProvider, namespaceFilter, isDocumentDb, usePostImages, position, skipInitialTimestamp = false, options, onBatch }) {
96
+ const parsing = {
97
+ defaultSchema: db.databaseName,
98
+ multipleDatabases: namespaceFilter.multipleDatabases,
99
+ startAfter: skipInitialTimestamp && position?.resumeAfter == null ? position?.startAfter : undefined,
100
+ signal: options.signal,
101
+ logger: options.logger
102
+ };
103
+ const openRaw = async function* ({ pipelineStages = [], imageOptions = {} }) {
104
+ const clusterScope = isDocumentDb || namespaceFilter.multipleDatabases;
105
+ const streamOptions = {
106
+ ...imageOptions,
107
+ fullDocument: !isDocumentDb && usePostImages ? 'required' : 'updateLookup',
108
+ ...(!isDocumentDb ? { showExpandedEvents: true } : {}),
109
+ ...(clusterScope ? { allChangesForCluster: true } : {})
110
+ };
111
+ // Only one resume option is legal. Legacy MongoDB snapshot positions may contain just a timestamp;
112
+ // a fresh DocumentDB stream has neither and opens from now.
113
+ if (position?.resumeAfter != null) {
114
+ streamOptions.resumeAfter = position.resumeAfter;
115
+ }
116
+ else if (position?.startAfter != null) {
117
+ streamOptions.startAtOperationTime = position.startAfter;
118
+ }
119
+ const pipeline = buildMongoChangeStreamPipeline({
120
+ streamOptions,
121
+ namespaceMatch: namespaceFilter.$match,
122
+ pipelineStages,
123
+ includeSplitLargeEvent: !isDocumentDb
124
+ });
125
+ for await (const batch of rawChangeStream(clusterScope ? db.client.db('admin') : db, pipeline, options)) {
126
+ options.signal?.throwIfAborted();
127
+ using batchScope = onBatch?.(batch) || undefined;
128
+ yield { events: batch.events, resumeToken: batch.resumeToken };
129
+ }
130
+ };
131
+ return queryProvider.openChangeStream({
132
+ open: (options) => parseMongoReplicationStream({ batches: openRaw(options), ...parsing })
133
+ });
134
+ }
135
+ /**
136
+ * Creates a stateful parser for one raw MongoDB stream. Parses BSON entries, joins split-event
137
+ * fragments across batches, normalizes namespaces and skips events covered by legacy timestamps.
138
+ * After processing a batch, callers can request safe progress. Check completion on natural EOF,
139
+ * not cancellation.
140
+ */
141
+ export function createMongoReplicationStreamParser({ defaultSchema, multipleDatabases, startAfter, signal, logger }) {
142
+ let splitDocument = null;
143
+ let flexDbNameWorkaroundLogged = false;
144
+ return {
145
+ parse(rawEvent) {
146
+ signal?.throwIfAborted();
147
+ let event = parseChangeDocument(rawEvent);
148
+ const fragment = event.splitEvent;
149
+ if (fragment != null) {
150
+ // A retry can resume after a received fragment inside the raw reader. Keep the partial event in
151
+ // memory across batches/retries, but never expose its token as a durable recovery boundary.
152
+ const expectedFragment = splitDocument == null ? 1 : splitDocument.splitEvent.fragment + 1;
153
+ if (fragment.fragment != expectedFragment ||
154
+ fragment.fragment > fragment.of ||
155
+ (splitDocument != null && fragment.of != splitDocument.splitEvent.of)) {
156
+ throw new ReplicationAssertionError(`Unexpected splitEvent: ${JSON.stringify(fragment)}`);
157
+ }
158
+ splitDocument = splitDocument == null ? event : Object.assign(splitDocument, event);
159
+ if (fragment.fragment != fragment.of) {
160
+ return null;
161
+ }
162
+ event = splitDocument;
163
+ splitDocument = null;
164
+ }
165
+ else if (splitDocument != null) {
166
+ throw new ReplicationAssertionError(`Incomplete splitEvent: ${JSON.stringify(splitDocument.splitEvent)}`);
167
+ }
168
+ if (startAfter != null && event.clusterTime?.lte(startAfter)) {
169
+ return null;
170
+ }
171
+ if (!multipleDatabases &&
172
+ 'ns' in event &&
173
+ event.ns.db != defaultSchema &&
174
+ event.ns.db.endsWith(`_${defaultSchema}`)) {
175
+ // Atlas Flex can prefix the database name on events recorded while replication was paused.
176
+ // Normalize before adapters inspect namespaces, just as the ordinary replication loop does.
177
+ const originalDatabase = event.ns.db;
178
+ event.ns.db = defaultSchema;
179
+ if (!flexDbNameWorkaroundLogged) {
180
+ flexDbNameWorkaroundLogged = true;
181
+ logger?.warn(`Incorrect DB name in change stream: ${originalDatabase}. Changed to ${defaultSchema}.`);
182
+ }
183
+ }
184
+ return event;
185
+ },
186
+ /**
187
+ * Returns the given transport token if it is safe to persist, or undefined while a split event is unfinished.
188
+ */
189
+ getSafeResumeToken(resumeToken) {
190
+ return splitDocument == null ? resumeToken : undefined;
191
+ },
192
+ assertComplete() {
193
+ if (splitDocument != null) {
194
+ throw new ReplicationAssertionError(`Incomplete splitEvent: ${JSON.stringify(splitDocument.splitEvent)}`);
195
+ }
196
+ }
197
+ };
198
+ }
199
+ /**
200
+ * Wrap raw batches in lazy event iterables. BSON parsing and split-event assembly happen
201
+ * as consumers request events, without building a parsed array. After exhaustion, each batch retains
202
+ * its own resume-token result even when later batches change the parser state.
203
+ * Consume each batch completely before requesting the next; returning early closes the source.
204
+ */
205
+ export async function* parseMongoReplicationStream({ batches, ...options }) {
206
+ const parser = createMongoReplicationStreamParser(options);
207
+ for await (const sourceBatch of batches) {
208
+ options.signal?.throwIfAborted();
209
+ const batch = createMongoReplicationStreamBatch({
210
+ events: parseEvents(sourceBatch.events),
211
+ resolveResumeToken: () => parser.getSafeResumeToken(sourceBatch.resumeToken)
212
+ });
213
+ yield batch;
214
+ // Split-event state is shared across batches, so the consumer must finish this one before the next is read.
215
+ // This also covers empty batches.
216
+ batch.getResumeToken();
217
+ }
218
+ parser.assertComplete();
219
+ function* parseEvents(rawEvents) {
220
+ for (let index = 0; index < rawEvents.length; index++) {
221
+ const event = parser.parse(rawEvents[index]);
222
+ if (event != null) {
223
+ yield { event, hasBufferedChanges: index < rawEvents.length - 1 };
224
+ }
225
+ }
226
+ }
227
+ }
228
+ //# sourceMappingURL=MongoReplicationStream.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MongoReplicationStream.js","sourceRoot":"","sources":["../../src/replication/MongoReplicationStream.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,157 @@
1
+ import type { mongo } from '@powersync/lib-service-mongodb';
2
+ import type { Logger } from '@powersync/lib-services-framework';
3
+ import type { ProjectedChangeStreamDocument } from './RawChangeStream.js';
4
+ /**
5
+ * An unparsed MongoDB response batch. Consumers parse its entries incrementally and retain unfinished
6
+ * split events across batches before deciding whether its resume token is safe to persist.
7
+ */
8
+ export interface RawMongoReplicationStreamBatch {
9
+ /**
10
+ * Original BSON entries in source order, including possible split-event fragments.
11
+ */
12
+ events: Buffer[];
13
+ /**
14
+ * Transport position after this batch. It may cover an incomplete event and is not yet safe progress.
15
+ */
16
+ resumeToken: mongo.ResumeToken;
17
+ }
18
+ /**
19
+ * A complete event and its position within the original source batch.
20
+ */
21
+ export interface MongoReplicationStreamChange {
22
+ event: ProjectedChangeStreamDocument;
23
+ /**
24
+ * MongoDB returned more entries after this event, even if a provider later excludes them or the
25
+ * parser retains them as unfinished split fragments. For [checkpoint, excluded change], preserve
26
+ * true on the checkpoint so ChangeStream groups commits instead of treating it as caught up.
27
+ * Providers must preserve this value when forwarding or transforming events.
28
+ */
29
+ hasBufferedChanges: boolean;
30
+ }
31
+ /**
32
+ * Statistics for one fully consumed batch, independent of whether its resume token is safe.
33
+ */
34
+ export interface MongoReplicationStreamBatchMetadata {
35
+ /**
36
+ * Complete events excluded from this batch. Null means no filtering was applied; zero means
37
+ * filtering was applied but no events were excluded. Counts do not carry across batches.
38
+ */
39
+ readonly filteredCount: number | null;
40
+ }
41
+ /**
42
+ * A single-use batch of complete events, parsed or filtered lazily as the consumer iterates.
43
+ * Exhaust events before reading its resume token, metadata or the next batch.
44
+ */
45
+ export interface MongoReplicationStreamBatch {
46
+ /**
47
+ * Complete changes in source order, parsed or filtered lazily during synchronous iteration.
48
+ * Consume once and fully. It may be empty after filtering or while assembling a split event.
49
+ */
50
+ events: Iterable<MongoReplicationStreamChange>;
51
+ /**
52
+ * Returns the safe resume token after events are fully consumed, or undefined while a split event
53
+ * is unfinished. Throws before exhaustion. The result remains stable after later batches.
54
+ */
55
+ getResumeToken(): mongo.ResumeToken | undefined;
56
+ /**
57
+ * Final statistics for this batch, available even without a safe resume token.
58
+ * Throws before events are fully consumed; the result is immutable and cached afterward.
59
+ */
60
+ readonly metadata: MongoReplicationStreamBatchMetadata;
61
+ }
62
+ /**
63
+ * Provider-controlled additions to the shared cursor setup. Source scope, resume position, post-image
64
+ * requirements and cancellation remain controlled by the MongoDB replication module.
65
+ */
66
+ export interface MongoReplicationStreamOptions {
67
+ /**
68
+ * Inserted after namespace selection and before the final large-event split stage.
69
+ */
70
+ pipelineStages?: mongo.Document[];
71
+ /**
72
+ * Request pre-images without overriding the reader's post-image, resume or scope options.
73
+ */
74
+ imageOptions?: Pick<mongo.ChangeStreamOptions, 'fullDocumentBeforeChange'>;
75
+ }
76
+ /**
77
+ * Bound source opener supplied to a query provider for one stream invocation.
78
+ * Providers may wrap the lazy event iterables to filter or transform complete changes.
79
+ */
80
+ export interface MongoReplicationStreamContext {
81
+ /**
82
+ * Open batches whose events are parsed lazily, with cursor scope, position, cancellation and
83
+ * accounting already bound. Each call owns independent split-event assembly and parser state.
84
+ * Events are complete; progress is withheld while a split event is unfinished.
85
+ * Close the iterator on completion, cancellation or failure (for await handles this).
86
+ */
87
+ open(options: MongoReplicationStreamOptions): AsyncIterableIterator<MongoReplicationStreamBatch>;
88
+ }
89
+ /**
90
+ * Source context for lazy parsing of raw BSON events in default and filtering providers.
91
+ * These options control namespace normalization, legacy timestamp skipping and cancellation; split-event
92
+ * state belongs to each parser instance and must not be shared between independently opened streams.
93
+ */
94
+ export interface MongoReplicationParserOptions {
95
+ /**
96
+ * Expected database name when correcting Atlas Flex's prefixed namespaces in single-database mode.
97
+ */
98
+ defaultSchema: string;
99
+ /**
100
+ * Preserve database names when the stream covers multiple databases instead of normalizing them.
101
+ */
102
+ multipleDatabases: boolean;
103
+ /**
104
+ * Exclude complete events at or before this legacy resume timestamp. Leave unset for exact-token
105
+ * resumes, where later events can share the same timestamp, and for snapshot barrier probes.
106
+ */
107
+ startAfter?: mongo.Timestamp | null;
108
+ /**
109
+ * Abort parsing when the owning replication attempt is cancelled. Resolving a batch's progress is not
110
+ * interrupted, so consumers must check the signal themselves before persisting a token.
111
+ */
112
+ signal?: AbortSignal;
113
+ /**
114
+ * Receives the namespace-correction warning, at most once per parser instance.
115
+ */
116
+ logger?: Logger;
117
+ }
118
+ /**
119
+ * A complete data change eligible for filtering. Checkpoints and DDL bypass the filter.
120
+ */
121
+ export type MongoReplicationDataChange = Extract<ProjectedChangeStreamDocument, {
122
+ operationType: 'insert' | 'update' | 'replace' | 'delete';
123
+ }>;
124
+ /**
125
+ * The action to apply to a complete data change after evaluating filter membership.
126
+ */
127
+ export declare enum MongoReplicationFilterResult {
128
+ /**
129
+ * Forward the original change.
130
+ */
131
+ KEEP = "keep",
132
+ /**
133
+ * Omit the change while retaining its batch's recovery progress.
134
+ */
135
+ EXCLUDE = "exclude",
136
+ /**
137
+ * Emit a delete because the document left the filtered set.
138
+ */
139
+ DELETE = "delete"
140
+ }
141
+ /**
142
+ * Synchronously decide how to replicate a complete data change. Checkpoints and DDL bypass this callback.
143
+ */
144
+ export type MongoReplicationFilter = (event: MongoReplicationDataChange) => MongoReplicationFilterResult;
145
+ /**
146
+ * Source batches and membership decisions for the shared replication filter.
147
+ */
148
+ export interface MongoReplicationFilterOptions {
149
+ /**
150
+ * Ordered source batches whose boundaries and recovery progress must be preserved.
151
+ */
152
+ batches: AsyncIterable<MongoReplicationStreamBatch>;
153
+ /**
154
+ * Decide whether to keep, exclude or delete each complete data change.
155
+ */
156
+ filter: MongoReplicationFilter;
157
+ }