@powersync/service-module-mongodb-storage 0.0.0-dev-20250108073049

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 (123) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/LICENSE +67 -0
  3. package/README.md +3 -0
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.js +6 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/migrations/MongoMigrationAgent.d.ts +12 -0
  8. package/dist/migrations/MongoMigrationAgent.js +25 -0
  9. package/dist/migrations/MongoMigrationAgent.js.map +1 -0
  10. package/dist/migrations/db/migrations/1684951997326-init.d.ts +3 -0
  11. package/dist/migrations/db/migrations/1684951997326-init.js +30 -0
  12. package/dist/migrations/db/migrations/1684951997326-init.js.map +1 -0
  13. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.d.ts +2 -0
  14. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js +5 -0
  15. package/dist/migrations/db/migrations/1688556755264-initial-sync-rules.js.map +1 -0
  16. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.d.ts +3 -0
  17. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js +54 -0
  18. package/dist/migrations/db/migrations/1702295701188-sync-rule-state.js.map +1 -0
  19. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.d.ts +3 -0
  20. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js +26 -0
  21. package/dist/migrations/db/migrations/1711543888062-write-checkpoint-index.js.map +1 -0
  22. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.d.ts +3 -0
  23. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js +28 -0
  24. package/dist/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.js.map +1 -0
  25. package/dist/migrations/mongo-migration-store.d.ts +7 -0
  26. package/dist/migrations/mongo-migration-store.js +49 -0
  27. package/dist/migrations/mongo-migration-store.js.map +1 -0
  28. package/dist/module/MongoStorageModule.d.ts +10 -0
  29. package/dist/module/MongoStorageModule.js +31 -0
  30. package/dist/module/MongoStorageModule.js.map +1 -0
  31. package/dist/storage/MongoBucketStorage.d.ts +48 -0
  32. package/dist/storage/MongoBucketStorage.js +426 -0
  33. package/dist/storage/MongoBucketStorage.js.map +1 -0
  34. package/dist/storage/implementation/MongoBucketBatch.d.ts +72 -0
  35. package/dist/storage/implementation/MongoBucketBatch.js +681 -0
  36. package/dist/storage/implementation/MongoBucketBatch.js.map +1 -0
  37. package/dist/storage/implementation/MongoCompactor.d.ts +40 -0
  38. package/dist/storage/implementation/MongoCompactor.js +300 -0
  39. package/dist/storage/implementation/MongoCompactor.js.map +1 -0
  40. package/dist/storage/implementation/MongoIdSequence.d.ts +12 -0
  41. package/dist/storage/implementation/MongoIdSequence.js +21 -0
  42. package/dist/storage/implementation/MongoIdSequence.js.map +1 -0
  43. package/dist/storage/implementation/MongoPersistedSyncRules.d.ts +9 -0
  44. package/dist/storage/implementation/MongoPersistedSyncRules.js +9 -0
  45. package/dist/storage/implementation/MongoPersistedSyncRules.js.map +1 -0
  46. package/dist/storage/implementation/MongoPersistedSyncRulesContent.d.ts +20 -0
  47. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js +26 -0
  48. package/dist/storage/implementation/MongoPersistedSyncRulesContent.js.map +1 -0
  49. package/dist/storage/implementation/MongoStorageProvider.d.ts +5 -0
  50. package/dist/storage/implementation/MongoStorageProvider.js +33 -0
  51. package/dist/storage/implementation/MongoStorageProvider.js.map +1 -0
  52. package/dist/storage/implementation/MongoSyncBucketStorage.d.ts +36 -0
  53. package/dist/storage/implementation/MongoSyncBucketStorage.js +529 -0
  54. package/dist/storage/implementation/MongoSyncBucketStorage.js.map +1 -0
  55. package/dist/storage/implementation/MongoSyncRulesLock.d.ts +16 -0
  56. package/dist/storage/implementation/MongoSyncRulesLock.js +65 -0
  57. package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -0
  58. package/dist/storage/implementation/MongoTestStorageFactoryGenerator.d.ts +7 -0
  59. package/dist/storage/implementation/MongoTestStorageFactoryGenerator.js +16 -0
  60. package/dist/storage/implementation/MongoTestStorageFactoryGenerator.js.map +1 -0
  61. package/dist/storage/implementation/MongoWriteCheckpointAPI.d.ts +20 -0
  62. package/dist/storage/implementation/MongoWriteCheckpointAPI.js +104 -0
  63. package/dist/storage/implementation/MongoWriteCheckpointAPI.js.map +1 -0
  64. package/dist/storage/implementation/OperationBatch.d.ts +34 -0
  65. package/dist/storage/implementation/OperationBatch.js +119 -0
  66. package/dist/storage/implementation/OperationBatch.js.map +1 -0
  67. package/dist/storage/implementation/PersistedBatch.d.ts +46 -0
  68. package/dist/storage/implementation/PersistedBatch.js +223 -0
  69. package/dist/storage/implementation/PersistedBatch.js.map +1 -0
  70. package/dist/storage/implementation/db.d.ts +36 -0
  71. package/dist/storage/implementation/db.js +47 -0
  72. package/dist/storage/implementation/db.js.map +1 -0
  73. package/dist/storage/implementation/models.d.ts +139 -0
  74. package/dist/storage/implementation/models.js +2 -0
  75. package/dist/storage/implementation/models.js.map +1 -0
  76. package/dist/storage/implementation/util.d.ts +46 -0
  77. package/dist/storage/implementation/util.js +155 -0
  78. package/dist/storage/implementation/util.js.map +1 -0
  79. package/dist/storage/storage-index.d.ts +14 -0
  80. package/dist/storage/storage-index.js +15 -0
  81. package/dist/storage/storage-index.js.map +1 -0
  82. package/dist/types/types.d.ts +18 -0
  83. package/dist/types/types.js +9 -0
  84. package/dist/types/types.js.map +1 -0
  85. package/package.json +48 -0
  86. package/src/index.ts +7 -0
  87. package/src/migrations/MongoMigrationAgent.ts +39 -0
  88. package/src/migrations/db/migrations/1684951997326-init.ts +39 -0
  89. package/src/migrations/db/migrations/1688556755264-initial-sync-rules.ts +5 -0
  90. package/src/migrations/db/migrations/1702295701188-sync-rule-state.ts +105 -0
  91. package/src/migrations/db/migrations/1711543888062-write-checkpoint-index.ts +38 -0
  92. package/src/migrations/db/migrations/1727099539247-custom-write-checkpoint-index.ts +40 -0
  93. package/src/migrations/mongo-migration-store.ts +62 -0
  94. package/src/module/MongoStorageModule.ts +37 -0
  95. package/src/storage/MongoBucketStorage.ts +531 -0
  96. package/src/storage/implementation/MongoBucketBatch.ts +896 -0
  97. package/src/storage/implementation/MongoCompactor.ts +381 -0
  98. package/src/storage/implementation/MongoIdSequence.ts +24 -0
  99. package/src/storage/implementation/MongoPersistedSyncRules.ts +16 -0
  100. package/src/storage/implementation/MongoPersistedSyncRulesContent.ts +49 -0
  101. package/src/storage/implementation/MongoStorageProvider.ts +39 -0
  102. package/src/storage/implementation/MongoSyncBucketStorage.ts +612 -0
  103. package/src/storage/implementation/MongoSyncRulesLock.ts +88 -0
  104. package/src/storage/implementation/MongoTestStorageFactoryGenerator.ts +25 -0
  105. package/src/storage/implementation/MongoWriteCheckpointAPI.ts +146 -0
  106. package/src/storage/implementation/OperationBatch.ts +129 -0
  107. package/src/storage/implementation/PersistedBatch.ts +283 -0
  108. package/src/storage/implementation/db.ts +87 -0
  109. package/src/storage/implementation/models.ts +161 -0
  110. package/src/storage/implementation/util.ts +169 -0
  111. package/src/storage/storage-index.ts +14 -0
  112. package/src/types/types.ts +18 -0
  113. package/test/src/__snapshots__/storage_sync.test.ts.snap +332 -0
  114. package/test/src/env.ts +6 -0
  115. package/test/src/setup.ts +9 -0
  116. package/test/src/storage.test.ts +7 -0
  117. package/test/src/storage_compacting.test.ts +6 -0
  118. package/test/src/storage_sync.test.ts +113 -0
  119. package/test/src/util.ts +8 -0
  120. package/test/tsconfig.json +31 -0
  121. package/tsconfig.json +31 -0
  122. package/tsconfig.tsbuildinfo +1 -0
  123. package/vitest.config.ts +15 -0
@@ -0,0 +1,105 @@
1
+ import * as lib_mongo from '@powersync/lib-service-mongodb';
2
+ import { storage as core_storage, migrations } from '@powersync/service-core';
3
+ import * as storage from '../../../storage/storage-index.js';
4
+ import { MongoStorageConfig } from '../../../types/types.js';
5
+
6
+ interface LegacySyncRulesDocument extends storage.SyncRuleDocument {
7
+ /**
8
+ * True if this is the active sync rules.
9
+ * requires `snapshot_done == true` and `replicating == true`.
10
+ */
11
+ active?: boolean;
12
+
13
+ /**
14
+ * True if this sync rules should be used for replication.
15
+ *
16
+ * During reprocessing, there is one sync rules with `replicating = true, active = true`,
17
+ * and one with `replicating = true, active = false, auto_activate = true`.
18
+ */
19
+ replicating?: boolean;
20
+
21
+ /**
22
+ * True if the sync rules should set `active = true` when `snapshot_done` = true.
23
+ */
24
+ auto_activate?: boolean;
25
+ }
26
+
27
+ export const up: migrations.PowerSyncMigrationFunction = async (context) => {
28
+ const {
29
+ service_context: { configuration }
30
+ } = context;
31
+ const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
32
+
33
+ await lib_mongo.waitForAuth(db.db);
34
+ try {
35
+ // We keep the old flags for existing deployments still shutting down.
36
+
37
+ // 1. New sync rules: `active = false, snapshot_done = false, replicating = true, auto_activate = true`
38
+ await db.sync_rules.updateMany(
39
+ {
40
+ active: { $ne: true },
41
+ replicating: true,
42
+ auto_activate: true
43
+ },
44
+ { $set: { state: core_storage.SyncRuleState.PROCESSING } }
45
+ );
46
+
47
+ // 2. Snapshot done: `active = true, snapshot_done = true, replicating = true, auto_activate = false`
48
+ await db.sync_rules.updateMany(
49
+ {
50
+ active: true
51
+ },
52
+ { $set: { state: core_storage.SyncRuleState.ACTIVE } }
53
+ );
54
+
55
+ // 3. Stopped: `active = false, snapshot_done = true, replicating = false, auto_activate = false`.
56
+ await db.sync_rules.updateMany(
57
+ {
58
+ active: { $ne: true },
59
+ replicating: { $ne: true },
60
+ auto_activate: { $ne: true }
61
+ },
62
+ { $set: { state: core_storage.SyncRuleState.STOP } }
63
+ );
64
+
65
+ const remaining = await db.sync_rules.find({ state: null as any }).toArray();
66
+ if (remaining.length > 0) {
67
+ const slots = remaining.map((doc) => doc.slot_name).join(', ');
68
+ throw new Error(`Invalid state for sync rules: ${slots}`);
69
+ }
70
+ } finally {
71
+ await db.client.close();
72
+ }
73
+ };
74
+
75
+ export const down: migrations.PowerSyncMigrationFunction = async (context) => {
76
+ const {
77
+ service_context: { configuration }
78
+ } = context;
79
+
80
+ const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
81
+ try {
82
+ await db.sync_rules.updateMany(
83
+ {
84
+ state: core_storage.SyncRuleState.ACTIVE
85
+ },
86
+ { $set: { active: true, replicating: true } }
87
+ );
88
+
89
+ await db.sync_rules.updateMany(
90
+ {
91
+ state: core_storage.SyncRuleState.PROCESSING
92
+ },
93
+ { $set: { active: false, replicating: true, auto_activate: true } }
94
+ );
95
+
96
+ await db.sync_rules.updateMany(
97
+ {
98
+ $or: [{ state: core_storage.SyncRuleState.STOP }, { state: core_storage.SyncRuleState.TERMINATED }]
99
+ },
100
+ { $set: { active: false, replicating: false, auto_activate: false } }
101
+ );
102
+ } finally {
103
+ await db.client.close();
104
+ }
105
+ };
@@ -0,0 +1,38 @@
1
+ import { migrations } from '@powersync/service-core';
2
+
3
+ import * as storage from '../../../storage/storage-index.js';
4
+ import { MongoStorageConfig } from '../../../types/types.js';
5
+
6
+ export const up: migrations.PowerSyncMigrationFunction = async (context) => {
7
+ const {
8
+ service_context: { configuration }
9
+ } = context;
10
+ const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
11
+
12
+ try {
13
+ await db.write_checkpoints.createIndex(
14
+ {
15
+ user_id: 1
16
+ },
17
+ { name: 'user_id' }
18
+ );
19
+ } finally {
20
+ await db.client.close();
21
+ }
22
+ };
23
+
24
+ export const down: migrations.PowerSyncMigrationFunction = async (context) => {
25
+ const {
26
+ service_context: { configuration }
27
+ } = context;
28
+
29
+ const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
30
+
31
+ try {
32
+ if (await db.write_checkpoints.indexExists('user_id')) {
33
+ await db.write_checkpoints.dropIndex('user_id');
34
+ }
35
+ } finally {
36
+ await db.client.close();
37
+ }
38
+ };
@@ -0,0 +1,40 @@
1
+ import { migrations } from '@powersync/service-core';
2
+ import * as storage from '../../../storage/storage-index.js';
3
+ import { MongoStorageConfig } from '../../../types/types.js';
4
+
5
+ const INDEX_NAME = 'user_sync_rule_unique';
6
+
7
+ export const up: migrations.PowerSyncMigrationFunction = async (context) => {
8
+ const {
9
+ service_context: { configuration }
10
+ } = context;
11
+ const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
12
+
13
+ try {
14
+ await db.custom_write_checkpoints.createIndex(
15
+ {
16
+ user_id: 1,
17
+ sync_rules_id: 1
18
+ },
19
+ { name: INDEX_NAME, unique: true }
20
+ );
21
+ } finally {
22
+ await db.client.close();
23
+ }
24
+ };
25
+
26
+ export const down: migrations.PowerSyncMigrationFunction = async (context) => {
27
+ const {
28
+ service_context: { configuration }
29
+ } = context;
30
+
31
+ const db = storage.createPowerSyncMongo(configuration.storage as MongoStorageConfig);
32
+
33
+ try {
34
+ if (await db.custom_write_checkpoints.indexExists(INDEX_NAME)) {
35
+ await db.custom_write_checkpoints.dropIndex(INDEX_NAME);
36
+ }
37
+ } finally {
38
+ await db.client.close();
39
+ }
40
+ };
@@ -0,0 +1,62 @@
1
+ import { migrations } from '@powersync/lib-services-framework';
2
+ import { Db } from 'mongodb';
3
+ import * as path from 'path';
4
+
5
+ /**
6
+ * A custom store for node-migrate which is used to save and load migrations that have
7
+ * been operated on to mongo.
8
+ */
9
+ export const createMongoMigrationStore = (db: Db): migrations.MigrationStore => {
10
+ const collection = db.collection<migrations.MigrationState>('migrations');
11
+
12
+ return {
13
+ load: async () => {
14
+ const state_entry = await collection.findOne();
15
+ if (!state_entry) {
16
+ return;
17
+ }
18
+
19
+ const { _id, ...state } = state_entry;
20
+
21
+ /**
22
+ * This is for backwards compatibility. A previous version of the migration tool used to save
23
+ * state as `lastRun`.
24
+ */
25
+ let last_run = state.last_run;
26
+ if ('lastRun' in state) {
27
+ last_run = (state as any).lastRun;
28
+ }
29
+
30
+ /**
31
+ * This is for backwards compatibility. A previous version of the migration tool used to include the
32
+ * file extension in migration names. This strips that extension off if it exists
33
+ */
34
+ const extension = path.extname(last_run);
35
+ if (extension) {
36
+ last_run = last_run.replace(extension, '');
37
+ }
38
+
39
+ return {
40
+ last_run,
41
+ log: state.log || []
42
+ };
43
+ },
44
+
45
+ clear: async () => {
46
+ await collection.deleteMany({});
47
+ },
48
+
49
+ save: async (state: migrations.MigrationState) => {
50
+ await collection.replaceOne(
51
+ {},
52
+ {
53
+ last_run: state.last_run,
54
+ log: state.log
55
+ },
56
+ {
57
+ upsert: true
58
+ }
59
+ );
60
+ }
61
+ };
62
+ };
@@ -0,0 +1,37 @@
1
+ import * as lib_mongo from '@powersync/lib-service-mongodb';
2
+ import * as core from '@powersync/service-core';
3
+ import { MongoMigrationAgent } from '../migrations/MongoMigrationAgent.js';
4
+ import { MongoStorageProvider } from '../storage/storage-index.js';
5
+ import * as types from '../types/types.js';
6
+
7
+ export class MongoStorageModule extends core.modules.AbstractModule {
8
+ constructor() {
9
+ super({
10
+ name: 'MongoDB Storage'
11
+ });
12
+ }
13
+
14
+ async initialize(context: core.system.ServiceContextContainer): Promise<void> {
15
+ context.storageEngine.registerProvider(new MongoStorageProvider());
16
+
17
+ if (types.isMongoStorageConfig(context.configuration.storage)) {
18
+ context.migrations.registerMigrationAgent(
19
+ new MongoMigrationAgent(this.resolveConfig(context.configuration.storage))
20
+ );
21
+ }
22
+ }
23
+
24
+ /**
25
+ * Combines base config with normalized connection settings
26
+ */
27
+ private resolveConfig(config: types.MongoStorageConfig) {
28
+ return {
29
+ ...config,
30
+ ...lib_mongo.normalizeMongoConfig(config)
31
+ };
32
+ }
33
+
34
+ async teardown(options: core.modules.TearDownOptions): Promise<void> {
35
+ // teardown is implemented in the storage engine
36
+ }
37
+ }