@powersync/service-module-postgres-storage 0.0.0-dev-20260313100403 → 0.0.0-dev-20260511080634

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 (68) hide show
  1. package/CHANGELOG.md +84 -9
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/@types/storage/PostgresBucketStorageFactory.d.ts +2 -1
  4. package/dist/@types/storage/PostgresReportStorage.d.ts +4 -4
  5. package/dist/@types/storage/PostgresSyncRulesStorage.d.ts +4 -2
  6. package/dist/@types/storage/batch/PostgresBucketBatch.d.ts +1 -1
  7. package/dist/@types/types/models/SyncRules.d.ts +9 -0
  8. package/dist/@types/types/models/models-index.d.ts +1 -1
  9. package/dist/@types/utils/test-utils.d.ts +2 -2
  10. package/dist/@types/utils/utils-index.d.ts +1 -1
  11. package/dist/migrations/migration-utils.js +2 -2
  12. package/dist/migrations/migration-utils.js.map +1 -1
  13. package/dist/migrations/scripts/1684951997326-init.js +24 -100
  14. package/dist/migrations/scripts/1684951997326-init.js.map +1 -1
  15. package/dist/migrations/scripts/1749024804042-snapshot-progress.js +12 -88
  16. package/dist/migrations/scripts/1749024804042-snapshot-progress.js.map +1 -1
  17. package/dist/migrations/scripts/1756282360128-connection-reporting.js +12 -88
  18. package/dist/migrations/scripts/1756282360128-connection-reporting.js.map +1 -1
  19. package/dist/migrations/scripts/1771232439485-storage-version.js +14 -90
  20. package/dist/migrations/scripts/1771232439485-storage-version.js.map +1 -1
  21. package/dist/migrations/scripts/1771424826685-current-data-pending-deletes.js +1 -1
  22. package/dist/migrations/scripts/1771491856000-sync-plan.js +6 -82
  23. package/dist/migrations/scripts/1771491856000-sync-plan.js.map +1 -1
  24. package/dist/storage/PostgresBucketStorageFactory.js +6 -5
  25. package/dist/storage/PostgresBucketStorageFactory.js.map +1 -1
  26. package/dist/storage/PostgresReportStorage.js +10 -10
  27. package/dist/storage/PostgresReportStorage.js.map +1 -1
  28. package/dist/storage/PostgresSyncRulesStorage.js +63 -104
  29. package/dist/storage/PostgresSyncRulesStorage.js.map +1 -1
  30. package/dist/storage/batch/PostgresBucketBatch.js +5 -5
  31. package/dist/storage/batch/PostgresBucketBatch.js.map +1 -1
  32. package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js +1 -1
  33. package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js.map +1 -1
  34. package/dist/storage/current-data-store.js +1 -1
  35. package/dist/storage/current-data-store.js.map +1 -1
  36. package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js +3 -3
  37. package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js.map +1 -1
  38. package/dist/types/models/SyncRules.js +3 -1
  39. package/dist/types/models/SyncRules.js.map +1 -1
  40. package/dist/types/models/models-index.js +1 -1
  41. package/dist/types/models/models-index.js.map +1 -1
  42. package/dist/utils/test-utils.js +36 -112
  43. package/dist/utils/test-utils.js.map +1 -1
  44. package/dist/utils/utils-index.js +1 -1
  45. package/dist/utils/utils-index.js.map +1 -1
  46. package/package.json +11 -12
  47. package/src/migrations/migration-utils.ts +2 -2
  48. package/src/migrations/scripts/1771424826685-current-data-pending-deletes.ts +1 -1
  49. package/src/storage/PostgresBucketStorageFactory.ts +7 -5
  50. package/src/storage/PostgresReportStorage.ts +12 -12
  51. package/src/storage/PostgresSyncRulesStorage.ts +63 -36
  52. package/src/storage/batch/PostgresBucketBatch.ts +5 -5
  53. package/src/storage/checkpoints/PostgresWriteCheckpointAPI.ts +3 -1
  54. package/src/storage/current-data-store.ts +1 -1
  55. package/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts +3 -6
  56. package/src/types/models/SyncRules.ts +3 -1
  57. package/src/types/models/models-index.ts +1 -1
  58. package/src/utils/test-utils.ts +3 -3
  59. package/src/utils/utils-index.ts +1 -1
  60. package/test/src/__snapshots__/{client-connections-storage.test.ts.snap → connection-report-storage.test.ts.snap} +22 -22
  61. package/test/src/__snapshots__/storage_sync.test.ts.snap +282 -0
  62. package/test/src/{client-connections-storage.test.ts → connection-report-storage.test.ts} +5 -5
  63. package/test/src/setup.ts +1 -1
  64. package/test/tsconfig.json +0 -1
  65. package/dist/@types/storage/current-data-table.d.ts +0 -9
  66. package/dist/storage/current-data-table.js +0 -22
  67. package/dist/storage/current-data-table.js.map +0 -1
  68. package/src/storage/current-data-table.ts +0 -26
@@ -1 +1 @@
1
- {"version":3,"file":"SyncRules.js","sourceRoot":"","sources":["../../../src/types/models/SyncRules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;IACpC;;;;OAIG;IACH,aAAa,EAAE,CAAC,CAAC,OAAO;IACxB;;OAEG;IACH,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACjC;;;;OAIG;IACH,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAClC;;OAEG;IACH,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACxC;;OAEG;IACH,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM;IACnB;;;;OAIG;IACH,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACpD;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACnD;;OAEG;IACH,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACrC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAC/B,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE;IACpD,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAClB,mBAAmB,CACjB,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,GAAG;QACX,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC;YACtB,OAAO,EAAE,CAAC,CAAC,MAAM;YACjB,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9B,qBAAqB,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;SAC3C,CAAC;QACF,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;KAC9C,CAAC,CACH,CACF;CACF,CAAC,CAAC"}
1
+ {"version":3,"file":"SyncRules.js","sourceRoot":"","sources":["../../../src/types/models/SyncRules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAC5D,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAC;AAEhD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,EAAE,EAAE,aAAa;IACjB,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;IACpC;;;;OAIG;IACH,aAAa,EAAE,CAAC,CAAC,OAAO;IACxB;;OAEG;IACH,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACjC;;;;OAIG;IACH,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAClC;;OAEG;IACH,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACxC;;OAEG;IACH,oBAAoB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzC,SAAS,EAAE,CAAC,CAAC,MAAM;IACnB;;;;OAIG;IACH,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACpD;;;;OAIG;IACH,iBAAiB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC;IACnD;;OAEG;IACH,gBAAgB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACrC,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAC/B,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,QAAQ,EAAE;IACpD,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAClB,mBAAmB,CACjB,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,GAAG;QACX,aAAa,EAAE,CAAC,CAAC,MAAM,CAAC;YACtB,OAAO,EAAE,CAAC,CAAC,MAAM;YACjB,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9B,qBAAqB,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;SAC3C,CAAC;QACF,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QAC7C,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,QAAQ,EAAE;KAC7C,CAAC,CACH,CACF;CACF,CAAC,CAAC"}
@@ -5,8 +5,8 @@ export * from './BucketParameters.js';
5
5
  export * from './CurrentData.js';
6
6
  export * from './Instance.js';
7
7
  export * from './Migration.js';
8
+ export * from './SdkReporting.js';
8
9
  export * from './SourceTable.js';
9
10
  export * from './SyncRules.js';
10
11
  export * from './WriteCheckpoint.js';
11
- export * from './SdkReporting.js';
12
12
  //# sourceMappingURL=models-index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"models-index.js","sourceRoot":"","sources":["../../../src/types/models/models-index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC"}
1
+ {"version":3,"file":"models-index.js","sourceRoot":"","sources":["../../../src/types/models/models-index.ts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,mCAAmC,CAAC;AAClD,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,sBAAsB,CAAC"}
@@ -1,61 +1,9 @@
1
- var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
- if (value !== null && value !== void 0) {
3
- if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
- var dispose, inner;
5
- if (async) {
6
- if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
- dispose = value[Symbol.asyncDispose];
8
- }
9
- if (dispose === void 0) {
10
- if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
- dispose = value[Symbol.dispose];
12
- if (async) inner = dispose;
13
- }
14
- if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
- if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
- env.stack.push({ value: value, dispose: dispose, async: async });
17
- }
18
- else if (async) {
19
- env.stack.push({ async: true });
20
- }
21
- return value;
22
- };
23
- var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
- return function (env) {
25
- function fail(e) {
26
- env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
- env.hasError = true;
28
- }
29
- var r, s = 0;
30
- function next() {
31
- while (r = env.stack.pop()) {
32
- try {
33
- if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
- if (r.dispose) {
35
- var result = r.dispose.call(r.value);
36
- if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
- }
38
- else s |= 1;
39
- }
40
- catch (e) {
41
- fail(e);
42
- }
43
- }
44
- if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
- if (env.hasError) throw env.error;
46
- }
47
- return next();
48
- };
49
- })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
- var e = new Error(message);
51
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
- });
1
+ import { createLogger, logger as defaultLogger, transports } from '@powersync/lib-services-framework';
53
2
  import { framework } from '@powersync/service-core';
54
3
  import { PostgresMigrationAgent } from '../migrations/PostgresMigrationAgent.js';
55
- import { normalizePostgresStorageConfig } from '../types/types.js';
56
- import { PostgresReportStorage } from '../storage/PostgresReportStorage.js';
57
4
  import { PostgresBucketStorageFactory } from '../storage/PostgresBucketStorageFactory.js';
58
- import { logger as defaultLogger, createLogger, transports } from '@powersync/lib-services-framework';
5
+ import { PostgresReportStorage } from '../storage/PostgresReportStorage.js';
6
+ import { normalizePostgresStorageConfig } from '../types/types.js';
59
7
  import { truncateTables } from './db.js';
60
8
  export function postgresTestSetup(factoryOptions) {
61
9
  const BASE_CONFIG = {
@@ -65,47 +13,35 @@ export function postgresTestSetup(factoryOptions) {
65
13
  };
66
14
  const TEST_CONNECTION_OPTIONS = normalizePostgresStorageConfig(BASE_CONFIG);
67
15
  const runMigrations = async (options) => {
68
- const env_1 = { stack: [], error: void 0, hasError: false };
69
- try {
70
- const migrationManager = __addDisposableResource(env_1, new framework.MigrationManager(), true);
71
- const migrationAgent = __addDisposableResource(env_1, factoryOptions.migrationAgent
72
- ? factoryOptions.migrationAgent(BASE_CONFIG)
73
- : new PostgresMigrationAgent(BASE_CONFIG), true);
74
- migrationManager.registerMigrationAgent(migrationAgent);
75
- const mockServiceContext = { configuration: { storage: BASE_CONFIG } };
76
- // Migration logs can get really verbose in tests, so only log warnings and up.
77
- const logger = createLogger({
78
- level: 'warn',
79
- format: defaultLogger.format,
80
- transports: [new transports.Console()]
16
+ await using migrationManager = new framework.MigrationManager();
17
+ await using migrationAgent = factoryOptions.migrationAgent
18
+ ? factoryOptions.migrationAgent(BASE_CONFIG)
19
+ : new PostgresMigrationAgent(BASE_CONFIG);
20
+ migrationManager.registerMigrationAgent(migrationAgent);
21
+ const mockServiceContext = { configuration: { storage: BASE_CONFIG } };
22
+ // Migration logs can get really verbose in tests, so only log warnings and up.
23
+ const logger = createLogger({
24
+ level: 'warn',
25
+ format: defaultLogger.format,
26
+ transports: [new transports.Console()]
27
+ });
28
+ if (options.down) {
29
+ await migrationManager.migrate({
30
+ direction: framework.migrations.Direction.Down,
31
+ migrationContext: {
32
+ service_context: mockServiceContext
33
+ },
34
+ logger
81
35
  });
82
- if (options.down) {
83
- await migrationManager.migrate({
84
- direction: framework.migrations.Direction.Down,
85
- migrationContext: {
86
- service_context: mockServiceContext
87
- },
88
- logger
89
- });
90
- }
91
- if (options.up) {
92
- await migrationManager.migrate({
93
- direction: framework.migrations.Direction.Up,
94
- migrationContext: {
95
- service_context: mockServiceContext
96
- },
97
- logger
98
- });
99
- }
100
- }
101
- catch (e_1) {
102
- env_1.error = e_1;
103
- env_1.hasError = true;
104
36
  }
105
- finally {
106
- const result_1 = __disposeResources(env_1);
107
- if (result_1)
108
- await result_1;
37
+ if (options.up) {
38
+ await migrationManager.migrate({
39
+ direction: framework.migrations.Direction.Up,
40
+ migrationContext: {
41
+ service_context: mockServiceContext
42
+ },
43
+ logger
44
+ });
109
45
  }
110
46
  };
111
47
  const migrate = async (direction) => {
@@ -115,24 +51,12 @@ export function postgresTestSetup(factoryOptions) {
115
51
  });
116
52
  };
117
53
  const clearStorage = async () => {
118
- const env_2 = { stack: [], error: void 0, hasError: false };
119
- try {
120
- await runMigrations({ down: false, up: true });
121
- const storageFactory = __addDisposableResource(env_2, new PostgresBucketStorageFactory({
122
- config: TEST_CONNECTION_OPTIONS,
123
- slot_name_prefix: 'test_'
124
- }), true);
125
- await truncateTables(storageFactory.db);
126
- }
127
- catch (e_2) {
128
- env_2.error = e_2;
129
- env_2.hasError = true;
130
- }
131
- finally {
132
- const result_2 = __disposeResources(env_2);
133
- if (result_2)
134
- await result_2;
135
- }
54
+ await runMigrations({ down: false, up: true });
55
+ await using storageFactory = new PostgresBucketStorageFactory({
56
+ config: TEST_CONNECTION_OPTIONS,
57
+ slot_name_prefix: 'test_'
58
+ });
59
+ await truncateTables(storageFactory.db);
136
60
  };
137
61
  return {
138
62
  reportFactory: async (options) => {
@@ -1 +1 @@
1
- {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/utils/test-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"test-utils.js","sourceRoot":"","sources":["../../src/utils/test-utils.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  export * from './bson.js';
2
2
  export * from './bucket-data.js';
3
3
  export * from './db.js';
4
- export * from './ts-codec.js';
5
4
  export * as test_utils from './test-utils.js';
5
+ export * from './ts-codec.js';
6
6
  //# sourceMappingURL=utils-index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils-index.js","sourceRoot":"","sources":["../../src/utils/utils-index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,cAAc,eAAe,CAAC;AAC9B,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC"}
1
+ {"version":3,"file":"utils-index.js","sourceRoot":"","sources":["../../src/utils/utils-index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,SAAS,CAAC;AACxB,OAAO,KAAK,UAAU,MAAM,iBAAiB,CAAC;AAC9C,cAAc,eAAe,CAAC"}
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@powersync/service-module-postgres-storage",
3
3
  "repository": "https://github.com/powersync-ja/powersync-service",
4
4
  "types": "dist/@types/index.d.ts",
5
- "version": "0.0.0-dev-20260313100403",
5
+ "version": "0.0.0-dev-20260511080634",
6
6
  "main": "dist/index.js",
7
7
  "license": "FSL-1.1-ALv2",
8
8
  "type": "module",
@@ -26,20 +26,19 @@
26
26
  "dependencies": {
27
27
  "ix": "^5.0.0",
28
28
  "lru-cache": "^10.2.2",
29
- "p-defer": "^4.0.1",
30
29
  "ts-codec": "^1.3.0",
31
- "uuid": "^11.1.0",
32
- "@powersync/lib-service-postgres": "0.0.0-dev-20260313100403",
33
- "@powersync/lib-services-framework": "0.0.0-dev-20260313100403",
34
- "@powersync/service-core": "0.0.0-dev-20260313100403",
35
- "@powersync/service-types": "0.0.0-dev-20260313100403",
36
- "@powersync/service-jpgwire": "0.0.0-dev-20260313100403",
37
- "@powersync/service-jsonbig": "0.17.12",
38
- "@powersync/service-sync-rules": "0.0.0-dev-20260313100403"
30
+ "uuid": "^14.0.0",
31
+ "@powersync/lib-service-postgres": "0.0.0-dev-20260511080634",
32
+ "@powersync/lib-services-framework": "0.0.0-dev-20260511080634",
33
+ "@powersync/service-core": "0.0.0-dev-20260511080634",
34
+ "@powersync/service-types": "0.0.0-dev-20260511080634",
35
+ "@powersync/service-jpgwire": "0.0.0-dev-20260511080634",
36
+ "@powersync/service-jsonbig": "0.0.0-dev-20260511080634",
37
+ "@powersync/service-sync-rules": "0.0.0-dev-20260511080634"
39
38
  },
40
39
  "devDependencies": {
41
- "typescript": "^5.7.3",
42
- "@powersync/service-core-tests": "0.0.0-dev-20260313100403"
40
+ "typescript": "~6.0.3",
41
+ "@powersync/service-core-tests": "0.0.0-dev-20260511080634"
43
42
  },
44
43
  "scripts": {
45
44
  "build": "tsc -b",
@@ -1,9 +1,9 @@
1
1
  import * as lib_postgres from '@powersync/lib-service-postgres';
2
+ import { ServiceAssertionError } from '@powersync/lib-services-framework';
2
3
  import { configFile } from '@powersync/service-types';
3
4
  import { isPostgresStorageConfig, normalizePostgresStorageConfig, PostgresStorageConfig } from '../types/types.js';
4
- import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
5
- import { ServiceAssertionError } from '@powersync/lib-services-framework';
6
5
  import { getStorageApplicationName } from '../utils/application-name.js';
6
+ import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
7
7
 
8
8
  export const openMigrationDB = (config: configFile.BaseStorageConfig) => {
9
9
  if (!isPostgresStorageConfig(config)) {
@@ -2,7 +2,7 @@ import { migrations } from '@powersync/service-core';
2
2
 
3
3
  export const up: migrations.PowerSyncMigrationFunction = async (_context) => {
4
4
  // No-op.
5
- // Pending-delete support is now storage-version specific and initialized when v3 sync rules are deployed.
5
+ // Pending-delete support is now storage-version specific and initialized when v3 sync config is deployed.
6
6
  };
7
7
 
8
8
  export const down: migrations.PowerSyncMigrationFunction = async (_context) => {
@@ -18,6 +18,7 @@ export type PostgresBucketStorageOptions = {
18
18
  };
19
19
 
20
20
  export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
21
+ [framework.DO_NOT_LOG] = true;
21
22
  readonly db: lib_postgres.DatabaseClient;
22
23
  public readonly slot_name_prefix: string;
23
24
 
@@ -153,7 +154,8 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
153
154
  }
154
155
 
155
156
  async updateSyncRules(options: storage.UpdateSyncRulesOptions): Promise<PostgresPersistedSyncRulesContent> {
156
- const storageVersion = options.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
157
+ const storageVersion =
158
+ options.storageVersion ?? options.config.parsed.config.storageVersion ?? storage.CURRENT_STORAGE_VERSION;
157
159
  const storageConfig = storage.STORAGE_VERSION_CONFIG[storageVersion];
158
160
  if (storageConfig == null) {
159
161
  throw new framework.ServiceError(
@@ -254,10 +256,10 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
254
256
  const next = await this.getNextSyncRulesContent();
255
257
  const active = await this.getActiveSyncRulesContent();
256
258
 
257
- // In both the below cases, we create a new sync rules instance.
259
+ // In both the below cases, we create a new replication stream.
258
260
  // The current one will continue serving sync requests until the next one has finished processing.
259
261
  if (next != null && next.id == sync_rules_group_id) {
260
- // We need to redo the "next" sync rules
262
+ // We need to redo the "next" replication stream
261
263
 
262
264
  await this.updateSyncRules(next.asUpdateOptions());
263
265
  // Pro-actively stop replicating
@@ -270,7 +272,7 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
270
272
  AND state = ${{ value: storage.SyncRuleState.PROCESSING, type: 'varchar' }}
271
273
  `.execute();
272
274
  } else if (next == null && active?.id == sync_rules_group_id) {
273
- // Slot removed for "active" sync rules, while there is no "next" one.
275
+ // Slot removed for "active" replication stream, while there is no "next" one.
274
276
  await this.updateSyncRules(active.asUpdateOptions());
275
277
 
276
278
  // Pro-actively stop replicating, but still serve clients with existing data
@@ -283,7 +285,7 @@ export class PostgresBucketStorageFactory extends storage.BucketStorageFactory {
283
285
  AND state = ${{ value: storage.SyncRuleState.ACTIVE, type: 'varchar' }}
284
286
  `.execute();
285
287
  } else if (next != null && active?.id == sync_rules_group_id) {
286
- // Already have "next" sync rules - don't update any.
288
+ // Already have "next" replication stream - don't update any.
287
289
 
288
290
  // Pro-actively stop replicating, but still serve clients with existing data
289
291
  await this.db.sql`
@@ -1,15 +1,15 @@
1
+ import * as lib_postgres from '@powersync/lib-service-postgres';
2
+ import { logger } from '@powersync/lib-services-framework';
1
3
  import { storage } from '@powersync/service-core';
2
4
  import * as pg_wire from '@powersync/service-jpgwire';
3
5
  import { event_types } from '@powersync/service-types';
6
+ import { ClientConnectionResponse } from '@powersync/service-types/dist/reports.js';
7
+ import { toInteger } from 'ix/util/tointeger.js';
4
8
  import { v4 } from 'uuid';
5
- import * as lib_postgres from '@powersync/lib-service-postgres';
6
- import { NormalizedPostgresStorageConfig } from '../types/types.js';
7
9
  import { SdkReporting, SdkReportingDecoded } from '../types/models/SdkReporting.js';
8
- import { toInteger } from 'ix/util/tointeger.js';
9
- import { logger } from '@powersync/lib-services-framework';
10
+ import { NormalizedPostgresStorageConfig } from '../types/types.js';
10
11
  import { getStorageApplicationName } from '../utils/application-name.js';
11
12
  import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
12
- import { ClientConnectionResponse } from '@powersync/service-types/dist/reports.js';
13
13
 
14
14
  export type PostgresReportStorageOptions = {
15
15
  config: NormalizedPostgresStorageConfig;
@@ -48,13 +48,13 @@ export class PostgresReportStorage implements storage.ReportStorage {
48
48
  ): event_types.ClientConnectionReportResponse {
49
49
  if (!result) {
50
50
  return {
51
- total_users: 0,
52
- sdk_breakdown: []
51
+ users: 0,
52
+ sdks: []
53
53
  };
54
54
  }
55
55
  return {
56
- total_users: Number(result.users),
57
- sdk_breakdown: result.sdks?.data || []
56
+ users: Number(result.users),
57
+ sdks: result.sdks?.data || []
58
58
  };
59
59
  }
60
60
  private async listConnectionsQuery() {
@@ -234,12 +234,12 @@ export class PostgresReportStorage implements storage.ReportStorage {
234
234
  AND connected_at = ${{ type: 1184, value: connectIsoString }}
235
235
  `.execute();
236
236
  }
237
- async getCurrentConnections(): Promise<event_types.ClientConnectionReportResponse> {
237
+ async getConnectedClients(): Promise<event_types.ClientConnectionReportResponse> {
238
238
  const result = await this.listConnectionsQuery();
239
239
  return this.mapListCurrentConnectionsResponse(result);
240
240
  }
241
241
 
242
- async getClientConnectionsSummary(
242
+ async getClientConnectionReports(
243
243
  data: event_types.ClientConnectionReportRequest
244
244
  ): Promise<event_types.ClientConnectionReportResponse> {
245
245
  const { start, end } = data;
@@ -289,7 +289,7 @@ export class PostgresReportStorage implements storage.ReportStorage {
289
289
  return this.mapListCurrentConnectionsResponse(result);
290
290
  }
291
291
 
292
- async getClientSessions(
292
+ async getGeneralClientConnectionAnalytics(
293
293
  data: event_types.ClientConnectionAnalyticsRequest
294
294
  ): Promise<event_types.PaginatedResponse<event_types.ClientConnection>> {
295
295
  const limit = data.limit || 100;
@@ -9,6 +9,7 @@ import {
9
9
  internalToExternalOpId,
10
10
  LastValueSink,
11
11
  maxLsn,
12
+ ParameterSetLimitExceededError,
12
13
  PartialChecksum,
13
14
  PopulateChecksumCacheOptions,
14
15
  PopulateChecksumCacheResults,
@@ -34,9 +35,9 @@ import { SourceTableDecoded, StoredRelationId } from '../types/models/SourceTabl
34
35
  import { pick } from '../utils/ts-codec.js';
35
36
  import { PostgresBucketBatch } from './batch/PostgresBucketBatch.js';
36
37
  import { PostgresWriteCheckpointAPI } from './checkpoints/PostgresWriteCheckpointAPI.js';
38
+ import { PostgresCurrentDataStore } from './current-data-store.js';
37
39
  import { PostgresBucketStorageFactory } from './PostgresBucketStorageFactory.js';
38
40
  import { PostgresCompactor } from './PostgresCompactor.js';
39
- import { PostgresCurrentDataStore } from './current-data-store.js';
40
41
 
41
42
  export type PostgresSyncRulesStorageOptions = {
42
43
  factory: PostgresBucketStorageFactory;
@@ -50,11 +51,14 @@ export class PostgresSyncRulesStorage
50
51
  extends framework.BaseObserver<storage.SyncRulesBucketStorageListener>
51
52
  implements storage.SyncRulesBucketStorage
52
53
  {
54
+ [framework.DO_NOT_LOG] = true;
55
+
53
56
  public readonly group_id: number;
54
57
  public readonly sync_rules: storage.PersistedSyncRulesContent;
55
58
  public readonly slot_name: string;
56
59
  public readonly factory: PostgresBucketStorageFactory;
57
60
  public readonly storageConfig: StorageVersionConfig;
61
+ public readonly logger: framework.Logger;
58
62
 
59
63
  private sharedIterator = new BroadcastIterable((signal) => this.watchActiveCheckpoint(signal));
60
64
 
@@ -77,6 +81,7 @@ export class PostgresSyncRulesStorage
77
81
  this.factory = options.factory;
78
82
  this.storageConfig = options.sync_rules.getStorageConfig();
79
83
  this.currentDataStore = new PostgresCurrentDataStore(this.storageConfig);
84
+ this.logger = options.sync_rules.logger;
80
85
 
81
86
  this.writeCheckpointAPI = new PostgresWriteCheckpointAPI({
82
87
  db: this.db,
@@ -106,8 +111,8 @@ export class PostgresSyncRulesStorage
106
111
  getParsedSyncRules(options: storage.ParseSyncRulesOptions): sync_rules.HydratedSyncRules {
107
112
  const { parsed, options: cachedOptions } = this.parsedSyncRulesCache ?? {};
108
113
  /**
109
- * Check if the cached sync rules, if present, had the same options.
110
- * Parse sync rules if the options are different or if there is no cached value.
114
+ * Check if the cached sync config, if present, had the same options.
115
+ * Parse sync config if the options are different or if there is no cached value.
111
116
  */
112
117
  if (!parsed || options.defaultSchema != cachedOptions?.defaultSchema) {
113
118
  this.parsedSyncRulesCache = { parsed: this.sync_rules.parsed(options).hydratedSyncRules(), options };
@@ -137,11 +142,12 @@ export class PostgresSyncRulesStorage
137
142
 
138
143
  return new PostgresCompactor(this.db, this.group_id, {
139
144
  ...options,
140
- maxOpId
145
+ maxOpId,
146
+ logger: this.logger
141
147
  }).compact();
142
148
  }
143
149
 
144
- async populatePersistentChecksumCache(options: PopulateChecksumCacheOptions): Promise<PopulateChecksumCacheResults> {
150
+ async populatePersistentChecksumCache(_options: PopulateChecksumCacheOptions): Promise<PopulateChecksumCacheResults> {
145
151
  // no-op - checksum cache is not implemented for Postgres yet
146
152
  return { buckets: 0 };
147
153
  }
@@ -361,7 +367,7 @@ export class PostgresSyncRulesStorage
361
367
  const checkpoint_lsn = syncRules?.last_checkpoint_lsn ?? null;
362
368
 
363
369
  const writer = new PostgresBucketBatch({
364
- logger: options.logger ?? framework.logger,
370
+ logger: options.logger ?? this.logger,
365
371
  db: this.db,
366
372
  sync_rules: this.sync_rules.parsed(options).hydratedSyncRules(),
367
373
  group_id: this.group_id,
@@ -394,42 +400,63 @@ export class PostgresSyncRulesStorage
394
400
 
395
401
  async getParameterSets(
396
402
  checkpoint: ReplicationCheckpoint,
397
- lookups: sync_rules.ScopedParameterLookup[]
403
+ lookups: sync_rules.ScopedParameterLookup[],
404
+ limit: number
398
405
  ): Promise<sync_rules.SqliteJsonRow[]> {
399
406
  const rows = await this.db.sql`
400
- SELECT DISTINCT
401
- ON (lookup, source_table, source_key) lookup,
402
- source_table,
403
- source_key,
404
- id,
405
- bucket_parameters
406
- FROM
407
- bucket_parameters
408
- WHERE
409
- group_id = ${{ type: 'int4', value: this.group_id }}
410
- AND lookup = ANY (
411
- SELECT
412
- decode((FILTER ->> 0)::text, 'hex') -- Decode the hex string to bytea
407
+ WITH
408
+ rows AS (
409
+ SELECT DISTINCT
410
+ ON (lookup, source_table, source_key) lookup,
411
+ source_table,
412
+ source_key,
413
+ id,
414
+ bucket_parameters
413
415
  FROM
414
- jsonb_array_elements(${{
416
+ bucket_parameters
417
+ WHERE
418
+ group_id = ${{ type: 'int4', value: this.group_id }}
419
+ AND lookup = ANY (
420
+ SELECT
421
+ decode((FILTER ->> 0)::text, 'hex') -- Decode the hex string to bytea
422
+ FROM
423
+ jsonb_array_elements(${{
415
424
  type: 'jsonb',
416
425
  value: lookups.map((l) => storage.serializeLookupBuffer(l).toString('hex'))
417
426
  }}) AS FILTER
427
+ )
428
+ AND id <= ${{ type: 'int8', value: checkpoint.checkpoint }}
429
+ ORDER BY
430
+ lookup,
431
+ source_table,
432
+ source_key,
433
+ id DESC
418
434
  )
419
- AND id <= ${{ type: 'int8', value: checkpoint.checkpoint }}
420
- ORDER BY
421
- lookup,
422
- source_table,
423
- source_key,
424
- id DESC
435
+ SELECT
436
+ bucket_parameters
437
+ FROM
438
+ rows
439
+ WHERE
440
+ bucket_parameters != '[]'
441
+ LIMIT
442
+ ${{ type: 'int4', value: limit + 1 }}
425
443
  `
426
444
  .decoded(pick(models.BucketParameters, ['bucket_parameters']))
427
445
  .rows();
428
446
 
429
- const groupedParameters = rows.map((row) => {
430
- return JSONBig.parse(row.bucket_parameters) as sync_rules.SqliteJsonRow;
431
- });
432
- return groupedParameters.flat();
447
+ const parameters = rows
448
+ .map((row) => {
449
+ return JSONBig.parse(row.bucket_parameters) as sync_rules.SqliteJsonRow[];
450
+ })
451
+ .flat();
452
+
453
+ if (parameters.length > limit) {
454
+ // Note that the LIMIT in the query allows more rows than parameters (because each row stores an array of
455
+ // parameter results). That array is very small though, and it doesn't allow fewer rows (due to the != []), so
456
+ // the SQL limit is good enough.
457
+ throw new ParameterSetLimitExceededError(limit);
458
+ }
459
+ return parameters;
433
460
  }
434
461
 
435
462
  async *getBucketDataBatch(
@@ -646,7 +673,7 @@ export class PostgresSyncRulesStorage
646
673
  .first();
647
674
 
648
675
  if (syncRulesRow == null) {
649
- throw new Error('Cannot find sync rules status');
676
+ throw new Error('Cannot find replication stream status');
650
677
  }
651
678
 
652
679
  return {
@@ -839,7 +866,7 @@ export class PostgresSyncRulesStorage
839
866
 
840
867
  if (doc == null) {
841
868
  // Abort the connections - clients will have to retry later.
842
- throw new framework.ServiceError(framework.ErrorCode.PSYNC_S2302, 'No active sync rules available');
869
+ throw new framework.ServiceError(framework.ErrorCode.PSYNC_S2302, 'No active replication stream available');
843
870
  }
844
871
 
845
872
  const sink = new LastValueSink<string>(undefined);
@@ -866,7 +893,7 @@ export class PostgresSyncRulesStorage
866
893
  continue;
867
894
  }
868
895
  if (Number(notification.active_checkpoint.id) != doc.id) {
869
- // Active sync rules changed - abort and restart the stream
896
+ // Active replication stream changed - abort and restart the stream
870
897
  break;
871
898
  }
872
899
 
@@ -896,7 +923,7 @@ class PostgresReplicationCheckpoint implements storage.ReplicationCheckpoint {
896
923
  public readonly lsn: string | null
897
924
  ) {}
898
925
 
899
- getParameterSets(lookups: sync_rules.ScopedParameterLookup[]): Promise<sync_rules.SqliteJsonRow[]> {
900
- return this.storage.getParameterSets(this, lookups);
926
+ getParameterSets(lookups: sync_rules.ScopedParameterLookup[], limit: number): Promise<sync_rules.SqliteJsonRow[]> {
927
+ return this.storage.getParameterSets(this, lookups, limit);
901
928
  }
902
929
  }
@@ -20,16 +20,16 @@ import {
20
20
  import * as sync_rules from '@powersync/service-sync-rules';
21
21
  import * as timers from 'timers/promises';
22
22
  import * as t from 'ts-codec';
23
+ import { bigint } from '../../types/codecs.js';
23
24
  import { CurrentBucket, V3CurrentDataDecoded } from '../../types/models/CurrentData.js';
24
25
  import { models, RequiredOperationBatchLimits } from '../../types/types.js';
25
26
  import { NOTIFICATION_CHANNEL } from '../../utils/db.js';
26
27
  import { pick } from '../../utils/ts-codec.js';
27
28
  import { batchCreateCustomWriteCheckpoints } from '../checkpoints/PostgresWriteCheckpointAPI.js';
28
- import { cacheKey, encodedCacheKey, OperationBatch, RecordOperation } from './OperationBatch.js';
29
- import { PostgresPersistedBatch } from './PostgresPersistedBatch.js';
30
- import { bigint } from '../../types/codecs.js';
31
29
  import { PostgresCurrentDataStore } from '../current-data-store.js';
32
30
  import { postgresTableId } from '../table-id.js';
31
+ import { cacheKey, encodedCacheKey, OperationBatch, RecordOperation } from './OperationBatch.js';
32
+ import { PostgresPersistedBatch } from './PostgresPersistedBatch.js';
33
33
 
34
34
  export interface PostgresBucketBatchOptions {
35
35
  logger: Logger;
@@ -52,7 +52,7 @@ export interface PostgresBucketBatchOptions {
52
52
  }
53
53
 
54
54
  /**
55
- * Intermediate type which helps for only watching the active sync rules
55
+ * Intermediate type which helps for only watching the active replication stream
56
56
  * via the Postgres NOTIFY protocol.
57
57
  */
58
58
  const StatefulCheckpoint = models.ActiveCheckpoint.and(t.object({ state: t.Enum(storage.SyncRuleState) }));
@@ -1054,7 +1054,7 @@ export class PostgresBucketBatch
1054
1054
  }
1055
1055
  });
1056
1056
  if (didActivate) {
1057
- this.logger.info(`Activated new sync rules at ${lsn}`);
1057
+ this.logger.info(`Activated new replication stream at ${lsn}`);
1058
1058
  }
1059
1059
  }
1060
1060