@semics-tech/mongolite 1.3.0 → 1.4.1

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 (67) hide show
  1. package/README.md +80 -21
  2. package/dist/cjs/collection.js +9 -6
  3. package/dist/cjs/cursors/findCursor.js +6 -4
  4. package/dist/cjs/index.js +108 -1
  5. package/dist/cjs/mongo-client.js +18 -1
  6. package/dist/cjs/server.js +164 -0
  7. package/dist/cjs/sync/commands.js +126 -0
  8. package/dist/cjs/sync/diff.js +174 -0
  9. package/dist/cjs/sync/httpSink.js +159 -0
  10. package/dist/cjs/sync/index.js +40 -0
  11. package/dist/cjs/sync/mongoExecutor.js +306 -0
  12. package/dist/cjs/sync/mongoSink.js +161 -0
  13. package/dist/cjs/sync/outbox.js +358 -0
  14. package/dist/cjs/sync/protocol.js +177 -0
  15. package/dist/cjs/sync/replicator.js +747 -0
  16. package/dist/cjs/sync/shadow.js +178 -0
  17. package/dist/cjs/sync/types.js +2 -0
  18. package/dist/cloudflare.d.ts +1 -1
  19. package/dist/cloudflare.js.map +1 -1
  20. package/dist/collection.js +9 -6
  21. package/dist/collection.js.map +1 -1
  22. package/dist/cursors/findCursor.d.ts +2 -1
  23. package/dist/cursors/findCursor.js +6 -4
  24. package/dist/cursors/findCursor.js.map +1 -1
  25. package/dist/index.d.ts +68 -2
  26. package/dist/index.js +96 -1
  27. package/dist/index.js.map +1 -1
  28. package/dist/mongo-client.d.ts +13 -0
  29. package/dist/mongo-client.js +18 -1
  30. package/dist/mongo-client.js.map +1 -1
  31. package/dist/server.d.ts +97 -0
  32. package/dist/server.js +158 -0
  33. package/dist/server.js.map +1 -0
  34. package/dist/sync/commands.d.ts +49 -0
  35. package/dist/sync/commands.js +118 -0
  36. package/dist/sync/commands.js.map +1 -0
  37. package/dist/sync/diff.d.ts +55 -0
  38. package/dist/sync/diff.js +169 -0
  39. package/dist/sync/diff.js.map +1 -0
  40. package/dist/sync/httpSink.d.ts +93 -0
  41. package/dist/sync/httpSink.js +155 -0
  42. package/dist/sync/httpSink.js.map +1 -0
  43. package/dist/sync/index.d.ts +17 -0
  44. package/dist/sync/index.js +10 -0
  45. package/dist/sync/index.js.map +1 -0
  46. package/dist/sync/mongoExecutor.d.ts +37 -0
  47. package/dist/sync/mongoExecutor.js +302 -0
  48. package/dist/sync/mongoExecutor.js.map +1 -0
  49. package/dist/sync/mongoSink.d.ts +109 -0
  50. package/dist/sync/mongoSink.js +123 -0
  51. package/dist/sync/mongoSink.js.map +1 -0
  52. package/dist/sync/outbox.d.ts +120 -0
  53. package/dist/sync/outbox.js +355 -0
  54. package/dist/sync/outbox.js.map +1 -0
  55. package/dist/sync/protocol.d.ts +93 -0
  56. package/dist/sync/protocol.js +168 -0
  57. package/dist/sync/protocol.js.map +1 -0
  58. package/dist/sync/replicator.d.ts +177 -0
  59. package/dist/sync/replicator.js +744 -0
  60. package/dist/sync/replicator.js.map +1 -0
  61. package/dist/sync/shadow.d.ts +54 -0
  62. package/dist/sync/shadow.js +173 -0
  63. package/dist/sync/shadow.js.map +1 -0
  64. package/dist/sync/types.d.ts +388 -0
  65. package/dist/sync/types.js +2 -0
  66. package/dist/sync/types.js.map +1 -0
  67. package/package.json +16 -2
@@ -0,0 +1,109 @@
1
+ /**
2
+ * A {@link SyncSink} that writes to a MongoDB deployment using the official
3
+ * `mongodb` driver.
4
+ *
5
+ * The driver is an **optional peer dependency**, imported dynamically the first
6
+ * time a connection is opened. Projects that never replicate upstream do not
7
+ * need it installed, and bundlers that never reach this module do not pull it in.
8
+ */
9
+ import type { MongoDriverLike, SyncApplyResult, SyncIdMapping, SyncOperation, SyncSink } from './types.js';
10
+ export { VERSION_FIELD, UPDATED_AT_FIELD } from './commands.js';
11
+ /**
12
+ * Authentication and transport settings for the upstream connection.
13
+ *
14
+ * Most deployments need nothing beyond the connection string — it already
15
+ * carries username, password, `authSource`, `replicaSet` and `tls`. These
16
+ * options cover the cases a URI cannot express, chiefly the certificate-file
17
+ * based mechanisms (X.509, mTLS, a private CA).
18
+ */
19
+ export interface MongoUpstreamAuth {
20
+ /** Database to authenticate against, when it differs from the target database. */
21
+ authSource?: string;
22
+ /**
23
+ * SASL/auth mechanism, e.g. `'SCRAM-SHA-256'`, `'MONGODB-X509'`,
24
+ * `'MONGODB-AWS'`, `'MONGODB-OIDC'`, `'GSSAPI'`, `'PLAIN'`.
25
+ * Omit to let the driver negotiate.
26
+ */
27
+ authMechanism?: string;
28
+ /** Mechanism-specific properties, e.g. `{ AWS_SESSION_TOKEN: '…' }`. */
29
+ authMechanismProperties?: Record<string, unknown>;
30
+ /** Username, when not embedded in the connection string. */
31
+ username?: string;
32
+ /** Password, when not embedded in the connection string. */
33
+ password?: string;
34
+ /** Force TLS on or off. Usually inferred from the connection string. */
35
+ tls?: boolean;
36
+ /** Path to a PEM file with the certificate authority chain, for a private CA. */
37
+ tlsCAFile?: string;
38
+ /**
39
+ * Path to a PEM file holding the client certificate **and** its private key —
40
+ * required for mutual TLS and for `MONGODB-X509` authentication.
41
+ */
42
+ tlsCertificateKeyFile?: string;
43
+ /** Passphrase for an encrypted `tlsCertificateKeyFile`. */
44
+ tlsCertificateKeyFilePassword?: string;
45
+ /** Path to a PEM file listing revoked certificates. */
46
+ tlsCRLFile?: string;
47
+ /**
48
+ * Skip hostname verification. Never enable this against a production
49
+ * deployment — it removes the protection TLS is there to provide.
50
+ */
51
+ tlsAllowInvalidHostnames?: boolean;
52
+ /**
53
+ * Accept certificates that fail validation. Never enable this against a
54
+ * production deployment.
55
+ */
56
+ tlsAllowInvalidCertificates?: boolean;
57
+ }
58
+ export interface MongoSinkOptions extends MongoUpstreamAuth {
59
+ /** Upstream connection string, e.g. `mongodb+srv://host/db`. */
60
+ connectionString: string;
61
+ /** Target database. Defaults to the one in the connection string's path. */
62
+ database?: string;
63
+ /** See {@link SyncIdMapping}. Defaults to `'auto'`. */
64
+ idMapping?: SyncIdMapping;
65
+ /**
66
+ * Guard writes with a conditional update against each document's last-known `_v`.
67
+ * Defaults to `true`. See {@link SyncOptions.versioning}.
68
+ */
69
+ versioning?: boolean;
70
+ /**
71
+ * Write concern for replicated batches. Defaults to `{ w: 'majority' }` so an
72
+ * acknowledged batch has actually survived upstream before it is checkpointed
73
+ * locally.
74
+ */
75
+ writeConcern?: Record<string, unknown>;
76
+ /**
77
+ * Extra options passed straight through to `new MongoClient(...)`. Anything
78
+ * the driver supports — `serverApi`, `proxyHost`, `compressors`,
79
+ * `autoEncryption`, connection-pool tuning — belongs here.
80
+ */
81
+ driverOptions?: Record<string, unknown>;
82
+ /**
83
+ * Supply the `mongodb` module yourself instead of having it imported
84
+ * dynamically. Useful for bundlers that cannot resolve dynamic imports, and
85
+ * for tests.
86
+ */
87
+ driver?: MongoDriverLike;
88
+ }
89
+ export declare class MongoUpstreamSink implements SyncSink {
90
+ private readonly options;
91
+ readonly name = "mongodb";
92
+ private client;
93
+ private db;
94
+ private driver;
95
+ private readonly idMapping;
96
+ private readonly versioning;
97
+ constructor(options: MongoSinkOptions);
98
+ connect(): Promise<void>;
99
+ apply(operations: SyncOperation[]): Promise<SyncApplyResult>;
100
+ /**
101
+ * Command-building settings. The driver's own `ObjectId` is used when available so
102
+ * BSON instances match the connection that will serialise them.
103
+ */
104
+ private commandOptions;
105
+ fetch(collection: string, documentIds: string[]): Promise<Record<string, unknown>[]>;
106
+ close(): Promise<void>;
107
+ private loadDriver;
108
+ private clientOptions;
109
+ }
@@ -0,0 +1,123 @@
1
+ /**
2
+ * A {@link SyncSink} that writes to a MongoDB deployment using the official
3
+ * `mongodb` driver.
4
+ *
5
+ * The driver is an **optional peer dependency**, imported dynamically the first
6
+ * time a connection is opened. Projects that never replicate upstream do not
7
+ * need it installed, and bundlers that never reach this module do not pull it in.
8
+ */
9
+ import { buildWriteCommand } from './commands.js';
10
+ import { executeWrites, fetchDocuments } from './mongoExecutor.js';
11
+ export { VERSION_FIELD, UPDATED_AT_FIELD } from './commands.js';
12
+ export class MongoUpstreamSink {
13
+ constructor(options) {
14
+ this.options = options;
15
+ this.name = 'mongodb';
16
+ this.client = null;
17
+ this.db = null;
18
+ this.driver = null;
19
+ if (!options.connectionString) {
20
+ throw new Error('MongoUpstreamSink requires a `connectionString`.');
21
+ }
22
+ this.idMapping = options.idMapping ?? 'auto';
23
+ this.versioning = options.versioning ?? true;
24
+ this.driver = options.driver ?? null;
25
+ }
26
+ async connect() {
27
+ if (this.client && this.db)
28
+ return;
29
+ const driver = await this.loadDriver();
30
+ const client = new driver.MongoClient(this.options.connectionString, this.clientOptions());
31
+ await client.connect();
32
+ this.client = client;
33
+ this.db = client.db(this.options.database);
34
+ }
35
+ async apply(operations) {
36
+ if (!this.db)
37
+ await this.connect();
38
+ const db = this.db;
39
+ if (!db)
40
+ throw new Error('MongoUpstreamSink is not connected.');
41
+ const writes = operations.map((op, index) => ({
42
+ index,
43
+ op,
44
+ command: buildWriteCommand(op, this.commandOptions()),
45
+ }));
46
+ return executeWrites(db, writes, {
47
+ writeConcern: this.options.writeConcern ?? { w: 'majority' },
48
+ versioning: this.versioning,
49
+ idMapping: this.idMapping,
50
+ ObjectId: this.driver?.ObjectId,
51
+ });
52
+ }
53
+ /**
54
+ * Command-building settings. The driver's own `ObjectId` is used when available so
55
+ * BSON instances match the connection that will serialise them.
56
+ */
57
+ commandOptions() {
58
+ return {
59
+ idMapping: this.idMapping,
60
+ versioning: this.versioning,
61
+ ObjectId: this.driver?.ObjectId,
62
+ };
63
+ }
64
+ async fetch(collection, documentIds) {
65
+ if (documentIds.length === 0)
66
+ return [];
67
+ if (!this.db)
68
+ await this.connect();
69
+ const db = this.db;
70
+ if (!db)
71
+ throw new Error('MongoUpstreamSink is not connected.');
72
+ return fetchDocuments(db, collection, documentIds, this.idMapping, this.driver?.ObjectId);
73
+ }
74
+ async close() {
75
+ const client = this.client;
76
+ this.client = null;
77
+ this.db = null;
78
+ if (client)
79
+ await client.close();
80
+ }
81
+ // ---------------------------------------------------------------- internals
82
+ async loadDriver() {
83
+ if (this.driver)
84
+ return this.driver;
85
+ try {
86
+ // Indirect specifier: `mongodb` is optional, and a literal import would
87
+ // make it a hard build-time dependency for everyone compiling this package.
88
+ const specifier = 'mongodb';
89
+ const mod = (await import(specifier));
90
+ this.driver = mod;
91
+ return mod;
92
+ }
93
+ catch (err) {
94
+ throw new Error('MongoDB sync requires the `mongodb` driver. Install it with `npm install mongodb`, ' +
95
+ `or pass a \`driver\` explicitly. Original error: ${err instanceof Error ? err.message : String(err)}`);
96
+ }
97
+ }
98
+ clientOptions() {
99
+ const { authSource, authMechanism, authMechanismProperties, username, password, tls, tlsCAFile, tlsCertificateKeyFile, tlsCertificateKeyFilePassword, tlsCRLFile, tlsAllowInvalidHostnames, tlsAllowInvalidCertificates, driverOptions, } = this.options;
100
+ const auth = username !== undefined || password !== undefined ? { username, password } : undefined;
101
+ // Undefined keys are stripped so they never override a setting that the
102
+ // connection string already specified.
103
+ return stripUndefined({
104
+ authSource,
105
+ authMechanism,
106
+ authMechanismProperties,
107
+ auth,
108
+ tls,
109
+ tlsCAFile,
110
+ tlsCertificateKeyFile,
111
+ tlsCertificateKeyFilePassword,
112
+ tlsCRLFile,
113
+ tlsAllowInvalidHostnames,
114
+ tlsAllowInvalidCertificates,
115
+ ...driverOptions,
116
+ });
117
+ }
118
+ }
119
+ /** Drops unset keys so they never override what the connection string specified. */
120
+ function stripUndefined(value) {
121
+ return Object.fromEntries(Object.entries(value).filter(([, v]) => v !== undefined));
122
+ }
123
+ //# sourceMappingURL=mongoSink.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mongoSink.js","sourceRoot":"","sources":["../../src/sync/mongoSink.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAYnE,OAAO,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAmGhE,MAAM,OAAO,iBAAiB;IAS5B,YAA6B,OAAyB;QAAzB,YAAO,GAAP,OAAO,CAAkB;QAR7C,SAAI,GAAG,SAAS,CAAC;QAElB,WAAM,GAA2B,IAAI,CAAC;QACtC,OAAE,GAAuB,IAAI,CAAC;QAC9B,WAAM,GAA2B,IAAI,CAAC;QAK5C,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAC;QACtE,CAAC;QACD,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;QAC7C,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,IAAI,CAAC;QAC7C,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,IAAI,CAAC;IACvC,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,MAAM,IAAI,IAAI,CAAC,EAAE;YAAE,OAAO;QAEnC,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC;QAC3F,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;QAEvB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAA2B;QACrC,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACnB,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAEhE,MAAM,MAAM,GAAoB,UAAU,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;YAC7D,KAAK;YACL,EAAE;YACF,OAAO,EAAE,iBAAiB,CAAC,EAAE,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC;SACtD,CAAC,CAAC,CAAC;QAEJ,OAAO,aAAa,CAAC,EAAE,EAAE,MAAM,EAAE;YAC/B,YAAY,EAAE,IAAI,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,CAAC,EAAE,UAAU,EAAE;YAC5D,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ;SAChC,CAAC,CAAC;IACL,CAAC;IAED;;;OAGG;IACK,cAAc;QACpB,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,QAAQ,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ;SAChC,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,KAAK,CAAC,UAAkB,EAAE,WAAqB;QACnD,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,EAAE,CAAC;QACxC,IAAI,CAAC,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;QACnC,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,CAAC;QACnB,IAAI,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QAEhE,OAAO,cAAc,CAAC,EAAE,EAAE,UAAU,EAAE,WAAW,EAAE,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC5F,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;QACf,IAAI,MAAM;YAAE,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;IACnC,CAAC;IAED,6EAA6E;IAErE,KAAK,CAAC,UAAU;QACtB,IAAI,IAAI,CAAC,MAAM;YAAE,OAAO,IAAI,CAAC,MAAM,CAAC;QAEpC,IAAI,CAAC;YACH,wEAAwE;YACxE,4EAA4E;YAC5E,MAAM,SAAS,GAAG,SAAS,CAAC;YAC5B,MAAM,GAAG,GAAG,CAAC,MAAM,MAAM,CAAC,SAAS,CAAC,CAA+B,CAAC;YACpE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC;YAClB,OAAO,GAAG,CAAC;QACb,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,qFAAqF;gBACnF,oDACE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CACjD,EAAE,CACL,CAAC;QACJ,CAAC;IACH,CAAC;IAEO,aAAa;QACnB,MAAM,EACJ,UAAU,EACV,aAAa,EACb,uBAAuB,EACvB,QAAQ,EACR,QAAQ,EACR,GAAG,EACH,SAAS,EACT,qBAAqB,EACrB,6BAA6B,EAC7B,UAAU,EACV,wBAAwB,EACxB,2BAA2B,EAC3B,aAAa,GACd,GAAG,IAAI,CAAC,OAAO,CAAC;QAEjB,MAAM,IAAI,GACR,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;QAExF,wEAAwE;QACxE,uCAAuC;QACvC,OAAO,cAAc,CAAC;YACpB,UAAU;YACV,aAAa;YACb,uBAAuB;YACvB,IAAI;YACJ,GAAG;YACH,SAAS;YACT,qBAAqB;YACrB,6BAA6B;YAC7B,UAAU;YACV,wBAAwB;YACxB,2BAA2B;YAC3B,GAAG,aAAa;SACjB,CAAC,CAAC;IACL,CAAC;CACF;AAED,oFAAoF;AACpF,SAAS,cAAc,CAAC,KAA8B;IACpD,OAAO,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC;AACtF,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * The durable change log ("outbox") that backs MongoDB replication.
3
+ *
4
+ * SQLite triggers append a row here inside the very same transaction as the
5
+ * write that caused it, so a change is either committed locally *and* queued for
6
+ * replication, or neither. Replicators then drain the log at their own pace and
7
+ * record a checkpoint; nothing is dropped because the process crashed or the
8
+ * upstream was unreachable.
9
+ */
10
+ import type { IDatabaseAdapter } from '../db.js';
11
+ import type { SyncDeadLetter, SyncOutboxRecord } from './types.js';
12
+ export declare const OUTBOX_TABLE = "__mongolite_sync_outbox__";
13
+ export declare const STATE_TABLE = "__mongolite_sync_state__";
14
+ export declare const DEAD_LETTER_TABLE = "__mongolite_sync_deadletter__";
15
+ /** Prefix shared by every table and trigger this module creates. */
16
+ export declare const SYNC_OBJECT_PREFIX = "__mongolite_sync";
17
+ /**
18
+ * Owns the outbox tables, the capture triggers, and every replicator's
19
+ * checkpoint. A single outbox serves any number of replicators: each keeps its
20
+ * own checkpoint row, and rows are pruned only once *every* replicator has
21
+ * passed them.
22
+ */
23
+ export declare class SyncOutbox {
24
+ private readonly db;
25
+ private schemaReady;
26
+ private readonly installedTriggers;
27
+ constructor(db: IDatabaseAdapter);
28
+ /** Creates the outbox, checkpoint and dead-letter tables. Idempotent. */
29
+ ensureSchema(): Promise<void>;
30
+ private createSchema;
31
+ /**
32
+ * Installs the insert/update/delete capture triggers for a collection.
33
+ *
34
+ * Triggers deliberately outlive the replicator that created them: changes made
35
+ * while replication is stopped still need to be captured, or restarting would
36
+ * silently skip them. Use {@link SyncOutbox.removeTriggers} to opt out.
37
+ */
38
+ ensureTriggers(collection: string): Promise<void>;
39
+ /**
40
+ * Removes the capture triggers for a collection. Changes to it stop being
41
+ * recorded — existing queued rows are untouched.
42
+ */
43
+ removeTriggers(collection: string): Promise<void>;
44
+ /** Lists user collections, excluding MongoLite's own bookkeeping tables. */
45
+ listCollections(): Promise<string[]>;
46
+ /**
47
+ * Reconciles the in-memory "already installed" cache with what is actually in
48
+ * the schema.
49
+ *
50
+ * Dropping a table drops its triggers with it, so a collection that was
51
+ * dropped and recreated would otherwise be silently uncaptured — the cache
52
+ * would insist its triggers were still there.
53
+ */
54
+ refreshTriggerCache(): Promise<void>;
55
+ /** The newest outbox id, or 0 when the log is empty. */
56
+ currentSequence(): Promise<number>;
57
+ /** Reads the persisted checkpoint for a replicator, creating its state row if absent. */
58
+ loadState(name: string): Promise<{
59
+ checkpoint: number;
60
+ backfilled: string[];
61
+ }>;
62
+ /**
63
+ * Advances a replicator's checkpoint.
64
+ *
65
+ * This is the acknowledgement, and it is a single atomic statement: a crash
66
+ * either leaves the old checkpoint (the batch is replayed, which is safe
67
+ * because upstream writes are idempotent) or the new one.
68
+ */
69
+ saveCheckpoint(name: string, checkpoint: number): Promise<void>;
70
+ /** Records that a collection's existing contents have been backfilled. */
71
+ markBackfilled(name: string, collections: string[]): Promise<void>;
72
+ /** Forgets a replicator, releasing the outbox rows its checkpoint was pinning. */
73
+ unregister(name: string): Promise<void>;
74
+ /** Reads the next batch of changes after `checkpoint`, oldest first. */
75
+ readBatch(checkpoint: number, limit: number, collections: string[] | null): Promise<SyncOutboxRecord[]>;
76
+ /** Count of rows a replicator still has to apply. */
77
+ pendingCount(checkpoint: number, collections: string[] | null): Promise<number>;
78
+ /**
79
+ * Deletes rows every registered replicator has already applied.
80
+ * @returns Number of rows removed.
81
+ */
82
+ prune(): Promise<number>;
83
+ /**
84
+ * Drops superseded revisions, keeping only the newest row per document.
85
+ *
86
+ * Safe because replication carries whole documents rather than deltas: the
87
+ * newest row alone reproduces the same upstream state. Rows at or below the
88
+ * slowest replicator's checkpoint are left to {@link SyncOutbox.prune}.
89
+ *
90
+ * @returns Number of rows removed.
91
+ */
92
+ compact(): Promise<number>;
93
+ /**
94
+ * Appends a change back onto the log so it is retried on a later drain.
95
+ *
96
+ * Used when a conflict is resolved in favour of the local version: the shadow has
97
+ * since been refreshed, so the replayed push diffs against current upstream state and
98
+ * carries the version it actually lost to.
99
+ */
100
+ requeue(collection: string, documentId: string, document: Record<string, unknown> | null): Promise<void>;
101
+ /** Moves a permanently-rejected change out of the stream so it cannot stall replication. */
102
+ deadLetter(replicator: string, record: {
103
+ collection: string;
104
+ documentId: string;
105
+ operation: string;
106
+ document: unknown;
107
+ }, error: string): Promise<void>;
108
+ /** Reads dead-lettered changes, newest first. */
109
+ listDeadLetters(replicator?: string, limit?: number): Promise<SyncDeadLetter[]>;
110
+ /** Removes dead-lettered rows, e.g. after replaying them by hand. */
111
+ clearDeadLetters(replicator?: string): Promise<number>;
112
+ /**
113
+ * Streams a collection's current contents in `_id` order, for the initial
114
+ * backfill. Keyset pagination keeps memory flat on large collections.
115
+ */
116
+ scanCollection(collection: string, chunkSize: number): AsyncGenerator<Array<{
117
+ documentId: string;
118
+ document: Record<string, unknown> | null;
119
+ }>>;
120
+ }