@powersync/service-module-mongodb-storage 0.0.0-dev-20260114113449 → 0.0.0-dev-20260114145741
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/CHANGELOG.md +5 -5
- package/dist/storage/implementation/MongoSyncRulesLock.js +4 -2
- package/dist/storage/implementation/MongoSyncRulesLock.js.map +1 -1
- package/dist/types/types.d.ts +3 -0
- package/dist/types/types.js +4 -0
- package/dist/types/types.js.map +1 -1
- package/dist/utils/util.d.ts +3 -2
- package/dist/utils/util.js +23 -18
- package/dist/utils/util.js.map +1 -1
- package/package.json +6 -6
- package/src/storage/implementation/MongoSyncRulesLock.ts +5 -2
- package/src/types/types.ts +4 -0
- package/src/utils/util.ts +22 -18
- package/tsconfig.tsbuildinfo +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @powersync/service-module-mongodb-storage
|
|
2
2
|
|
|
3
|
-
## 0.0.0-dev-
|
|
3
|
+
## 0.0.0-dev-20260114145741
|
|
4
4
|
|
|
5
5
|
### Minor Changes
|
|
6
6
|
|
|
@@ -11,10 +11,10 @@
|
|
|
11
11
|
- Updated dependencies [781d0e3]
|
|
12
12
|
- Updated dependencies [e578245]
|
|
13
13
|
- Updated dependencies [3040079]
|
|
14
|
-
- @powersync/service-core@0.0.0-dev-
|
|
15
|
-
- @powersync/service-sync-rules@0.0.0-dev-
|
|
16
|
-
- @powersync/lib-services-framework@0.0.0-dev-
|
|
17
|
-
- @powersync/lib-service-mongodb@0.0.0-dev-
|
|
14
|
+
- @powersync/service-core@0.0.0-dev-20260114145741
|
|
15
|
+
- @powersync/service-sync-rules@0.0.0-dev-20260114145741
|
|
16
|
+
- @powersync/lib-services-framework@0.0.0-dev-20260114145741
|
|
17
|
+
- @powersync/lib-service-mongodb@0.0.0-dev-20260114145741
|
|
18
18
|
|
|
19
19
|
## 0.12.16
|
|
20
20
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import crypto from 'crypto';
|
|
2
2
|
import { ErrorCode, logger, ServiceError } from '@powersync/lib-services-framework';
|
|
3
3
|
import { fsCache, syncLockCheck } from '../../utils/util.js';
|
|
4
|
-
import { FsCachePaths } from '../../types/types.js';
|
|
4
|
+
import { FsCacheDirs, FsCachePaths } from '../../types/types.js';
|
|
5
|
+
import path from 'node:path';
|
|
5
6
|
/**
|
|
6
7
|
* Manages a lock on a sync rules document, so that only one process
|
|
7
8
|
* replicates those sync rules at a time.
|
|
@@ -28,7 +29,8 @@ export class MongoSyncRulesLock {
|
|
|
28
29
|
// Query the existing lock to get the expiration time (best effort - it may have been released in the meantime).
|
|
29
30
|
const heldLock = await db.sync_rules.findOne({ _id: sync_rules.id }, { projection: { lock: 1 } });
|
|
30
31
|
if (heldLock?.lock?.expires_at) {
|
|
31
|
-
const
|
|
32
|
+
const dir = path.join(process.cwd(), FsCacheDirs.SYNC_RULES_LOCK);
|
|
33
|
+
const alert = await fsCache(FsCachePaths.SYNC_RULES_LOCK, dir, heldLock.lock.expires_at.toISOString(), syncLockCheck(dir));
|
|
32
34
|
/** If the date has changed on the expires_at the alert key will be true, we want to notify that another process has a lock */
|
|
33
35
|
if (alert) {
|
|
34
36
|
throw new ServiceError(ErrorCode.PSYNC_S1003, `Sync rules: ${sync_rules.id} have been locked by another process for replication, expiring at ${heldLock.lock.expires_at.toISOString()}.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MongoSyncRulesLock.js","sourceRoot":"","sources":["../../../src/storage/implementation/MongoSyncRulesLock.ts"],"names":[],"mappings":"AAAA,OAAO,MAAM,MAAM,QAAQ,CAAC;AAE5B,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAGpF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;
|
|
1
|
+
{"version":3,"file":"MongoSyncRulesLock.js","sourceRoot":"","sources":["../../../src/storage/implementation/MongoSyncRulesLock.ts"],"names":[],"mappings":"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"}
|
package/dist/types/types.d.ts
CHANGED
|
@@ -3,6 +3,9 @@ import * as t from 'ts-codec';
|
|
|
3
3
|
export declare enum FsCachePaths {
|
|
4
4
|
SYNC_RULES_LOCK = "sync_rules_lock"
|
|
5
5
|
}
|
|
6
|
+
export declare enum FsCacheDirs {
|
|
7
|
+
SYNC_RULES_LOCK = ".sync"
|
|
8
|
+
}
|
|
6
9
|
export declare const MongoStorageConfig: t.Intersection<t.Codec<{
|
|
7
10
|
uri: string;
|
|
8
11
|
type: "mongodb";
|
package/dist/types/types.js
CHANGED
|
@@ -4,6 +4,10 @@ export var FsCachePaths;
|
|
|
4
4
|
(function (FsCachePaths) {
|
|
5
5
|
FsCachePaths["SYNC_RULES_LOCK"] = "sync_rules_lock";
|
|
6
6
|
})(FsCachePaths || (FsCachePaths = {}));
|
|
7
|
+
export var FsCacheDirs;
|
|
8
|
+
(function (FsCacheDirs) {
|
|
9
|
+
FsCacheDirs["SYNC_RULES_LOCK"] = ".sync";
|
|
10
|
+
})(FsCacheDirs || (FsCacheDirs = {}));
|
|
7
11
|
export const MongoStorageConfig = lib_mongo.BaseMongoConfig.and(t.object({
|
|
8
12
|
// Add any mongo specific storage settings here in future
|
|
9
13
|
}));
|
package/dist/types/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,gCAAgC,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B,MAAM,CAAN,IAAY,YAEX;AAFD,WAAY,YAAY;IACtB,mDAAmC,CAAA;AACrC,CAAC,EAFW,YAAY,KAAZ,YAAY,QAEvB;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAC,eAAe,CAAC,GAAG,CAC7D,CAAC,CAAC,MAAM,CAAC;AACP,yDAAyD;CAC1D,CAAC,CACH,CAAC;AAKF,MAAM,UAAU,oBAAoB,CAClC,MAAqD;IAErD,OAAO,MAAM,CAAC,IAAI,IAAI,SAAS,CAAC,qBAAqB,CAAC;AACxD,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,gCAAgC,CAAC;AAE5D,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B,MAAM,CAAN,IAAY,YAEX;AAFD,WAAY,YAAY;IACtB,mDAAmC,CAAA;AACrC,CAAC,EAFW,YAAY,KAAZ,YAAY,QAEvB;AAED,MAAM,CAAN,IAAY,WAEX;AAFD,WAAY,WAAW;IACrB,wCAAyB,CAAA;AAC3B,CAAC,EAFW,WAAW,KAAX,WAAW,QAEtB;AAED,MAAM,CAAC,MAAM,kBAAkB,GAAG,SAAS,CAAC,eAAe,CAAC,GAAG,CAC7D,CAAC,CAAC,MAAM,CAAC;AACP,yDAAyD;CAC1D,CAAC,CACH,CAAC;AAKF,MAAM,UAAU,oBAAoB,CAClC,MAAqD;IAErD,OAAO,MAAM,CAAC,IAAI,IAAI,SAAS,CAAC,qBAAqB,CAAC;AACxD,CAAC"}
|
package/dist/utils/util.d.ts
CHANGED
|
@@ -40,15 +40,16 @@ export declare const createPaginatedConnectionQuery: <T extends mongo.Document>(
|
|
|
40
40
|
*
|
|
41
41
|
* @template T - The return type of the `func` callback.
|
|
42
42
|
* @param {FsCachePaths} filename - The path to the cache file.
|
|
43
|
+
* @param dir
|
|
43
44
|
* @param {string} text - The text to cache or compare against the cached data.
|
|
44
45
|
* @param {(cache: string, text: string) => Promise<T>} func - A callback function that processes the cached data
|
|
45
46
|
* and the provided text. It receives the cached data (or the `text` if no cache exists) as the first argument
|
|
46
47
|
* and the `text` as the second argument.
|
|
47
48
|
* @returns {Promise<T>} - A promise that resolves to the result of the `func` callback.
|
|
48
49
|
*/
|
|
49
|
-
export declare function fsCache<T>(filename: FsCachePaths, text: string, func: (cache: string, text: string) => Promise<T>): Promise<T>;
|
|
50
|
+
export declare function fsCache<T>(filename: FsCachePaths, dir: string, text: string, func: (cache: string, text: string) => Promise<T>): Promise<T>;
|
|
50
51
|
/**
|
|
51
52
|
* Compares cached text with new text and updates the cache file if they differ.
|
|
52
53
|
* Returns true if the cache was updated, false otherwise.
|
|
53
54
|
*/
|
|
54
|
-
export declare function syncLockCheck(cache: string, text: string)
|
|
55
|
+
export declare function syncLockCheck(dir: string): (cache: string, text: string) => Promise<boolean>;
|
package/dist/utils/util.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import * as bson from 'bson';
|
|
2
2
|
import * as crypto from 'crypto';
|
|
3
3
|
import * as uuid from 'uuid';
|
|
4
|
-
import
|
|
4
|
+
import * as fsPromises from 'node:fs/promises';
|
|
5
5
|
import { storage, utils } from '@powersync/service-core';
|
|
6
6
|
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
7
|
-
import { promisify } from 'node:util';
|
|
8
7
|
import { FsCachePaths } from '../types/types.js';
|
|
8
|
+
import path from 'node:path';
|
|
9
9
|
export function idPrefixFilter(prefix, rest) {
|
|
10
10
|
let filter = {
|
|
11
11
|
$gte: {
|
|
@@ -151,23 +151,27 @@ export const createPaginatedConnectionQuery = async (query, collection, limit, c
|
|
|
151
151
|
*
|
|
152
152
|
* @template T - The return type of the `func` callback.
|
|
153
153
|
* @param {FsCachePaths} filename - The path to the cache file.
|
|
154
|
+
* @param dir
|
|
154
155
|
* @param {string} text - The text to cache or compare against the cached data.
|
|
155
156
|
* @param {(cache: string, text: string) => Promise<T>} func - A callback function that processes the cached data
|
|
156
157
|
* and the provided text. It receives the cached data (or the `text` if no cache exists) as the first argument
|
|
157
158
|
* and the `text` as the second argument.
|
|
158
159
|
* @returns {Promise<T>} - A promise that resolves to the result of the `func` callback.
|
|
159
160
|
*/
|
|
160
|
-
export async function fsCache(filename, text, func) {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
161
|
+
export async function fsCache(filename, dir, text, func) {
|
|
162
|
+
try {
|
|
163
|
+
await fsPromises.access(dir, fsPromises.constants.R_OK);
|
|
164
|
+
}
|
|
165
|
+
catch (error) {
|
|
166
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
167
|
+
}
|
|
168
|
+
try {
|
|
169
|
+
await fsPromises.access(path.join(dir, filename), fsPromises.constants.R_OK);
|
|
170
|
+
const cache = await fsPromises.readFile(path.join(dir, filename), 'utf-8');
|
|
167
171
|
return func(cache, text);
|
|
168
172
|
}
|
|
169
|
-
|
|
170
|
-
await
|
|
173
|
+
catch (error) {
|
|
174
|
+
await fsPromises.writeFile(path.join(dir, filename), text, 'utf-8');
|
|
171
175
|
return func(text, text);
|
|
172
176
|
}
|
|
173
177
|
}
|
|
@@ -175,12 +179,13 @@ export async function fsCache(filename, text, func) {
|
|
|
175
179
|
* Compares cached text with new text and updates the cache file if they differ.
|
|
176
180
|
* Returns true if the cache was updated, false otherwise.
|
|
177
181
|
*/
|
|
178
|
-
export
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
182
|
+
export function syncLockCheck(dir) {
|
|
183
|
+
return async (cache, text) => {
|
|
184
|
+
if (cache === text) {
|
|
185
|
+
return false;
|
|
186
|
+
}
|
|
187
|
+
await fsPromises.writeFile(path.join(dir, FsCachePaths.SYNC_RULES_LOCK), text, 'utf-8');
|
|
188
|
+
return true;
|
|
189
|
+
};
|
|
185
190
|
}
|
|
186
191
|
//# sourceMappingURL=util.js.map
|
package/dist/utils/util.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/utils/util.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAC;AACjC,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/utils/util.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@powersync/service-module-mongodb-storage",
|
|
3
3
|
"repository": "https://github.com/powersync-ja/powersync-service",
|
|
4
4
|
"types": "dist/index.d.ts",
|
|
5
|
-
"version": "0.0.0-dev-
|
|
5
|
+
"version": "0.0.0-dev-20260114145741",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"license": "FSL-1.1-ALv2",
|
|
8
8
|
"type": "module",
|
|
@@ -27,15 +27,15 @@
|
|
|
27
27
|
"lru-cache": "^10.2.2",
|
|
28
28
|
"ts-codec": "^1.3.0",
|
|
29
29
|
"uuid": "^11.1.0",
|
|
30
|
-
"@powersync/lib-service-mongodb": "0.0.0-dev-
|
|
31
|
-
"@powersync/lib-services-framework": "0.0.0-dev-
|
|
32
|
-
"@powersync/service-core": "0.0.0-dev-
|
|
30
|
+
"@powersync/lib-service-mongodb": "0.0.0-dev-20260114145741",
|
|
31
|
+
"@powersync/lib-services-framework": "0.0.0-dev-20260114145741",
|
|
32
|
+
"@powersync/service-core": "0.0.0-dev-20260114145741",
|
|
33
33
|
"@powersync/service-jsonbig": "0.17.12",
|
|
34
|
-
"@powersync/service-sync-rules": "0.0.0-dev-
|
|
34
|
+
"@powersync/service-sync-rules": "0.0.0-dev-20260114145741",
|
|
35
35
|
"@powersync/service-types": "0.13.3"
|
|
36
36
|
},
|
|
37
37
|
"devDependencies": {
|
|
38
|
-
"@powersync/service-core-tests": "0.0.0-dev-
|
|
38
|
+
"@powersync/service-core-tests": "0.0.0-dev-20260114145741"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsc -b",
|
|
@@ -4,7 +4,8 @@ import { ErrorCode, logger, ServiceError } from '@powersync/lib-services-framewo
|
|
|
4
4
|
import { storage } from '@powersync/service-core';
|
|
5
5
|
import { PowerSyncMongo } from './db.js';
|
|
6
6
|
import { fsCache, syncLockCheck } from '../../utils/util.js';
|
|
7
|
-
import { FsCachePaths } from '../../types/types.js';
|
|
7
|
+
import { FsCacheDirs, FsCachePaths } from '../../types/types.js';
|
|
8
|
+
import path from 'node:path';
|
|
8
9
|
|
|
9
10
|
/**
|
|
10
11
|
* Manages a lock on a sync rules document, so that only one process
|
|
@@ -38,10 +39,12 @@ export class MongoSyncRulesLock implements storage.ReplicationLock {
|
|
|
38
39
|
// Query the existing lock to get the expiration time (best effort - it may have been released in the meantime).
|
|
39
40
|
const heldLock = await db.sync_rules.findOne({ _id: sync_rules.id }, { projection: { lock: 1 } });
|
|
40
41
|
if (heldLock?.lock?.expires_at) {
|
|
42
|
+
const dir = path.join(process.cwd(), FsCacheDirs.SYNC_RULES_LOCK);
|
|
41
43
|
const alert = await fsCache(
|
|
42
44
|
FsCachePaths.SYNC_RULES_LOCK,
|
|
45
|
+
dir,
|
|
43
46
|
heldLock.lock.expires_at.toISOString(),
|
|
44
|
-
syncLockCheck
|
|
47
|
+
syncLockCheck(dir)
|
|
45
48
|
);
|
|
46
49
|
/** If the date has changed on the expires_at the alert key will be true, we want to notify that another process has a lock */
|
|
47
50
|
if (alert) {
|
package/src/types/types.ts
CHANGED
|
@@ -6,6 +6,10 @@ export enum FsCachePaths {
|
|
|
6
6
|
SYNC_RULES_LOCK = 'sync_rules_lock'
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
export enum FsCacheDirs {
|
|
10
|
+
SYNC_RULES_LOCK = '.sync'
|
|
11
|
+
}
|
|
12
|
+
|
|
9
13
|
export const MongoStorageConfig = lib_mongo.BaseMongoConfig.and(
|
|
10
14
|
t.object({
|
|
11
15
|
// Add any mongo specific storage settings here in future
|
package/src/utils/util.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import * as bson from 'bson';
|
|
2
2
|
import * as crypto from 'crypto';
|
|
3
3
|
import * as uuid from 'uuid';
|
|
4
|
-
import
|
|
4
|
+
import * as fsPromises from 'node:fs/promises';
|
|
5
5
|
import { mongo } from '@powersync/lib-service-mongodb';
|
|
6
6
|
import { storage, utils } from '@powersync/service-core';
|
|
7
7
|
import { ServiceAssertionError } from '@powersync/lib-services-framework';
|
|
8
8
|
import { BucketDataDocument } from '../storage/implementation/models.js';
|
|
9
|
-
import { promisify } from 'node:util';
|
|
10
9
|
import { FsCachePaths } from '../types/types.js';
|
|
10
|
+
import path from 'node:path';
|
|
11
11
|
|
|
12
12
|
export function idPrefixFilter<T>(prefix: Partial<T>, rest: (keyof T)[]): mongo.Condition<T> {
|
|
13
13
|
let filter = {
|
|
@@ -167,6 +167,7 @@ export const createPaginatedConnectionQuery = async <T extends mongo.Document>(
|
|
|
167
167
|
*
|
|
168
168
|
* @template T - The return type of the `func` callback.
|
|
169
169
|
* @param {FsCachePaths} filename - The path to the cache file.
|
|
170
|
+
* @param dir
|
|
170
171
|
* @param {string} text - The text to cache or compare against the cached data.
|
|
171
172
|
* @param {(cache: string, text: string) => Promise<T>} func - A callback function that processes the cached data
|
|
172
173
|
* and the provided text. It receives the cached data (or the `text` if no cache exists) as the first argument
|
|
@@ -175,19 +176,21 @@ export const createPaginatedConnectionQuery = async <T extends mongo.Document>(
|
|
|
175
176
|
*/
|
|
176
177
|
export async function fsCache<T>(
|
|
177
178
|
filename: FsCachePaths,
|
|
179
|
+
dir: string,
|
|
178
180
|
text: string,
|
|
179
181
|
func: (cache: string, text: string) => Promise<T>
|
|
180
182
|
): Promise<T> {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
183
|
+
try {
|
|
184
|
+
await fsPromises.access(dir, fsPromises.constants.R_OK);
|
|
185
|
+
} catch (error) {
|
|
186
|
+
await fsPromises.mkdir(dir, { recursive: true });
|
|
187
|
+
}
|
|
188
|
+
try {
|
|
189
|
+
await fsPromises.access(path.join(dir, filename), fsPromises.constants.R_OK);
|
|
190
|
+
const cache = await fsPromises.readFile(path.join(dir, filename), 'utf-8');
|
|
188
191
|
return func(cache, text);
|
|
189
|
-
}
|
|
190
|
-
await
|
|
192
|
+
} catch (error) {
|
|
193
|
+
await fsPromises.writeFile(path.join(dir, filename), text, 'utf-8');
|
|
191
194
|
return func(text, text);
|
|
192
195
|
}
|
|
193
196
|
}
|
|
@@ -196,11 +199,12 @@ export async function fsCache<T>(
|
|
|
196
199
|
* Compares cached text with new text and updates the cache file if they differ.
|
|
197
200
|
* Returns true if the cache was updated, false otherwise.
|
|
198
201
|
*/
|
|
199
|
-
export
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
202
|
+
export function syncLockCheck(dir: string) {
|
|
203
|
+
return async (cache: string, text: string): Promise<boolean> => {
|
|
204
|
+
if (cache === text) {
|
|
205
|
+
return false;
|
|
206
|
+
}
|
|
207
|
+
await fsPromises.writeFile(path.join(dir, FsCachePaths.SYNC_RULES_LOCK), text, 'utf-8');
|
|
208
|
+
return true;
|
|
209
|
+
};
|
|
206
210
|
}
|