@powersync/service-module-postgres 0.0.0-dev-20260225160713 → 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 (84) hide show
  1. package/dist/api/PostgresRouteAPIAdapter.d.ts +1 -1
  2. package/dist/api/PostgresRouteAPIAdapter.js +63 -72
  3. package/dist/api/PostgresRouteAPIAdapter.js.map +1 -1
  4. package/dist/module/PostgresModule.js.map +1 -1
  5. package/dist/replication/MissingReplicationSlotError.d.ts +41 -0
  6. package/dist/replication/MissingReplicationSlotError.js +33 -0
  7. package/dist/replication/MissingReplicationSlotError.js.map +1 -0
  8. package/dist/replication/PgManager.js +3 -2
  9. package/dist/replication/PgManager.js.map +1 -1
  10. package/dist/replication/PostgresErrorRateLimiter.js +1 -1
  11. package/dist/replication/PostgresErrorRateLimiter.js.map +1 -1
  12. package/dist/replication/SnapshotQuery.js +8 -7
  13. package/dist/replication/SnapshotQuery.js.map +1 -1
  14. package/dist/replication/WalStream.d.ts +46 -16
  15. package/dist/replication/WalStream.js +203 -69
  16. package/dist/replication/WalStream.js.map +1 -1
  17. package/dist/replication/WalStreamReplicationJob.d.ts +1 -1
  18. package/dist/replication/WalStreamReplicationJob.js +9 -6
  19. package/dist/replication/WalStreamReplicationJob.js.map +1 -1
  20. package/dist/replication/WalStreamReplicator.d.ts +0 -1
  21. package/dist/replication/WalStreamReplicator.js +0 -22
  22. package/dist/replication/WalStreamReplicator.js.map +1 -1
  23. package/dist/replication/replication-index.d.ts +3 -1
  24. package/dist/replication/replication-index.js +3 -1
  25. package/dist/replication/replication-index.js.map +1 -1
  26. package/dist/replication/replication-utils.d.ts +3 -11
  27. package/dist/replication/replication-utils.js +103 -165
  28. package/dist/replication/replication-utils.js.map +1 -1
  29. package/dist/replication/rquery.d.ts +5 -0
  30. package/dist/replication/rquery.js +35 -0
  31. package/dist/replication/rquery.js.map +1 -0
  32. package/dist/replication/wal-budget-utils.d.ts +23 -0
  33. package/dist/replication/wal-budget-utils.js +57 -0
  34. package/dist/replication/wal-budget-utils.js.map +1 -0
  35. package/dist/types/registry.js +1 -1
  36. package/dist/types/registry.js.map +1 -1
  37. package/dist/utils/errors.d.ts +2 -0
  38. package/dist/utils/errors.js +30 -0
  39. package/dist/utils/errors.js.map +1 -0
  40. package/package.json +17 -13
  41. package/sql/check-source-configuration.plpgsql +13 -0
  42. package/sql/debug-tables-info-batched.plpgsql +230 -0
  43. package/CHANGELOG.md +0 -794
  44. package/src/api/PostgresRouteAPIAdapter.ts +0 -356
  45. package/src/index.ts +0 -1
  46. package/src/module/PostgresModule.ts +0 -122
  47. package/src/replication/ConnectionManagerFactory.ts +0 -33
  48. package/src/replication/PgManager.ts +0 -122
  49. package/src/replication/PgRelation.ts +0 -41
  50. package/src/replication/PostgresErrorRateLimiter.ts +0 -48
  51. package/src/replication/SnapshotQuery.ts +0 -213
  52. package/src/replication/WalStream.ts +0 -1138
  53. package/src/replication/WalStreamReplicationJob.ts +0 -138
  54. package/src/replication/WalStreamReplicator.ts +0 -79
  55. package/src/replication/replication-index.ts +0 -5
  56. package/src/replication/replication-utils.ts +0 -398
  57. package/src/types/registry.ts +0 -275
  58. package/src/types/resolver.ts +0 -227
  59. package/src/types/types.ts +0 -44
  60. package/src/utils/application-name.ts +0 -8
  61. package/src/utils/migration_lib.ts +0 -80
  62. package/src/utils/populate_test_data.ts +0 -37
  63. package/src/utils/populate_test_data_worker.ts +0 -53
  64. package/src/utils/postgres_version.ts +0 -8
  65. package/test/src/checkpoints.test.ts +0 -88
  66. package/test/src/chunked_snapshots.test.ts +0 -160
  67. package/test/src/env.ts +0 -11
  68. package/test/src/large_batch.test.ts +0 -239
  69. package/test/src/pg_test.test.ts +0 -729
  70. package/test/src/resuming_snapshots.test.ts +0 -163
  71. package/test/src/route_api_adapter.test.ts +0 -62
  72. package/test/src/schema_changes.test.ts +0 -675
  73. package/test/src/setup.ts +0 -12
  74. package/test/src/slow_tests.test.ts +0 -412
  75. package/test/src/storage_combination.test.ts +0 -35
  76. package/test/src/types/registry.test.ts +0 -149
  77. package/test/src/util.ts +0 -145
  78. package/test/src/validation.test.ts +0 -63
  79. package/test/src/wal_stream.test.ts +0 -618
  80. package/test/src/wal_stream_utils.ts +0 -292
  81. package/test/tsconfig.json +0 -27
  82. package/tsconfig.json +0 -34
  83. package/tsconfig.tsbuildinfo +0 -1
  84. package/vitest.config.ts +0 -3
@@ -1,292 +0,0 @@
1
- import { PgManager } from '@module/replication/PgManager.js';
2
- import { PUBLICATION_NAME, WalStream, WalStreamOptions } from '@module/replication/WalStream.js';
3
- import { CustomTypeRegistry } from '@module/types/registry.js';
4
- import {
5
- BucketStorageFactory,
6
- createCoreReplicationMetrics,
7
- initializeCoreReplicationMetrics,
8
- InternalOpId,
9
- LEGACY_STORAGE_VERSION,
10
- OplogEntry,
11
- STORAGE_VERSION_CONFIG,
12
- storage,
13
- SyncRulesBucketStorage,
14
- updateSyncRulesFromYaml
15
- } from '@powersync/service-core';
16
- import { METRICS_HELPER, test_utils } from '@powersync/service-core-tests';
17
- import * as pgwire from '@powersync/service-jpgwire';
18
- import { clearTestDb, getClientCheckpoint, TEST_CONNECTION_OPTIONS } from './util.js';
19
-
20
- export class WalStreamTestContext implements AsyncDisposable {
21
- private _walStream?: WalStream;
22
- private abortController = new AbortController();
23
- private streamPromise?: Promise<void>;
24
- private syncRulesId?: number;
25
- public storage?: SyncRulesBucketStorage;
26
- private replicationConnection?: pgwire.PgConnection;
27
- private snapshotPromise?: Promise<void>;
28
-
29
- /**
30
- * Tests operating on the wal stream need to configure the stream and manage asynchronous
31
- * replication, which gets a little tricky.
32
- *
33
- * This configures all the context, and tears it down afterwards.
34
- */
35
- static async open(
36
- factory: (options: storage.TestStorageOptions) => Promise<BucketStorageFactory>,
37
- options?: { doNotClear?: boolean; storageVersion?: number; walStreamOptions?: Partial<WalStreamOptions> }
38
- ) {
39
- const f = await factory({ doNotClear: options?.doNotClear });
40
- const connectionManager = new PgManager(TEST_CONNECTION_OPTIONS, {});
41
-
42
- if (!options?.doNotClear) {
43
- await clearTestDb(connectionManager.pool);
44
- }
45
-
46
- const storageVersion = options?.storageVersion ?? LEGACY_STORAGE_VERSION;
47
- const versionedBuckets = STORAGE_VERSION_CONFIG[storageVersion]?.versionedBuckets ?? false;
48
-
49
- return new WalStreamTestContext(f, connectionManager, options?.walStreamOptions, storageVersion, versionedBuckets);
50
- }
51
-
52
- constructor(
53
- public factory: BucketStorageFactory,
54
- public connectionManager: PgManager,
55
- private walStreamOptions?: Partial<WalStreamOptions>,
56
- private storageVersion: number = LEGACY_STORAGE_VERSION,
57
- private versionedBuckets: boolean = STORAGE_VERSION_CONFIG[storageVersion]?.versionedBuckets ?? false
58
- ) {
59
- createCoreReplicationMetrics(METRICS_HELPER.metricsEngine);
60
- initializeCoreReplicationMetrics(METRICS_HELPER.metricsEngine);
61
- }
62
-
63
- async [Symbol.asyncDispose]() {
64
- await this.dispose();
65
- }
66
-
67
- /**
68
- * Clear any errors from startStream, to allow for a graceful dispose when streaming errors
69
- * were expected.
70
- */
71
- async clearStreamError() {
72
- if (this.streamPromise != null) {
73
- this.streamPromise = this.streamPromise.catch((e) => {});
74
- }
75
- }
76
-
77
- async dispose() {
78
- this.abortController.abort();
79
- try {
80
- await this.snapshotPromise;
81
- await this.streamPromise;
82
- await this.connectionManager.destroy();
83
- await this.factory?.[Symbol.asyncDispose]();
84
- } catch (e) {
85
- // Throwing here may result in SuppressedError. The underlying errors often don't show up
86
- // in the test output, so we log it here.
87
- // If we could get vitest to log SuppressedError.error and SuppressedError.suppressed, we
88
- // could remove this.
89
- console.error('Error during WalStreamTestContext dispose', e);
90
- throw e;
91
- }
92
- }
93
-
94
- get pool() {
95
- return this.connectionManager.pool;
96
- }
97
-
98
- get connectionTag() {
99
- return this.connectionManager.connectionTag;
100
- }
101
-
102
- get publicationName() {
103
- return PUBLICATION_NAME;
104
- }
105
-
106
- async updateSyncRules(content: string) {
107
- const syncRules = await this.factory.updateSyncRules(
108
- updateSyncRulesFromYaml(content, { validate: true, storageVersion: this.storageVersion })
109
- );
110
- this.syncRulesId = syncRules.id;
111
- this.storage = this.factory.getInstance(syncRules);
112
- return this.storage!;
113
- }
114
-
115
- async loadNextSyncRules() {
116
- const syncRules = await this.factory.getNextSyncRulesContent();
117
- if (syncRules == null) {
118
- throw new Error(`Next sync rules not available`);
119
- }
120
-
121
- this.syncRulesId = syncRules.id;
122
- this.storage = this.factory.getInstance(syncRules);
123
- return this.storage!;
124
- }
125
-
126
- async loadActiveSyncRules() {
127
- const syncRules = await this.factory.getActiveSyncRulesContent();
128
- if (syncRules == null) {
129
- throw new Error(`Active sync rules not available`);
130
- }
131
-
132
- this.syncRulesId = syncRules.id;
133
- this.storage = this.factory.getInstance(syncRules);
134
- return this.storage!;
135
- }
136
-
137
- get walStream() {
138
- if (this.storage == null) {
139
- throw new Error('updateSyncRules() first');
140
- }
141
- if (this._walStream) {
142
- return this._walStream;
143
- }
144
- const options: WalStreamOptions = {
145
- storage: this.storage,
146
- metrics: METRICS_HELPER.metricsEngine,
147
- connections: this.connectionManager,
148
- abort_signal: this.abortController.signal,
149
- ...this.walStreamOptions
150
- };
151
- this._walStream = new WalStream(options);
152
- return this._walStream!;
153
- }
154
-
155
- /**
156
- * Replicate a snapshot, start streaming, and wait for a consistent checkpoint.
157
- */
158
- async initializeReplication() {
159
- await this.replicateSnapshot();
160
- this.startStreaming();
161
- // Make sure we're up to date
162
- await this.getCheckpoint();
163
- }
164
-
165
- async replicateSnapshot() {
166
- const promise = (async () => {
167
- this.replicationConnection = await this.connectionManager.replicationConnection();
168
- await this.walStream.initReplication(this.replicationConnection);
169
- })();
170
- this.snapshotPromise = promise.catch((e) => e);
171
- await promise;
172
- }
173
-
174
- startStreaming() {
175
- if (this.replicationConnection == null) {
176
- throw new Error('Call replicateSnapshot() before startStreaming()');
177
- }
178
- this.streamPromise = this.walStream.streamChanges(this.replicationConnection!);
179
- }
180
-
181
- async getCheckpoint(options?: { timeout?: number }) {
182
- let checkpoint = await Promise.race([
183
- getClientCheckpoint(this.pool, this.factory, { timeout: options?.timeout ?? 15_000 }),
184
- this.streamPromise
185
- ]);
186
- if (checkpoint == null) {
187
- // This indicates an issue with the test setup - streamingPromise completed instead
188
- // of getClientCheckpoint()
189
- throw new Error('Test failure - streamingPromise completed');
190
- }
191
- return checkpoint;
192
- }
193
-
194
- private resolveBucketName(bucket: string) {
195
- if (!this.versionedBuckets || /^\d+#/.test(bucket)) {
196
- return bucket;
197
- }
198
- if (this.syncRulesId == null) {
199
- throw new Error('Sync rules not configured - call updateSyncRules() first');
200
- }
201
- return `${this.syncRulesId}#${bucket}`;
202
- }
203
-
204
- async getBucketsDataBatch(buckets: Record<string, InternalOpId>, options?: { timeout?: number }) {
205
- let checkpoint = await this.getCheckpoint(options);
206
- const map = new Map<string, InternalOpId>(
207
- Object.entries(buckets).map(([bucket, opId]) => [this.resolveBucketName(bucket), opId])
208
- );
209
- return test_utils.fromAsync(this.storage!.getBucketDataBatch(checkpoint, map));
210
- }
211
-
212
- /**
213
- * This waits for a client checkpoint.
214
- */
215
- async getBucketData(bucket: string, start?: InternalOpId | string | undefined, options?: { timeout?: number }) {
216
- start ??= 0n;
217
- if (typeof start == 'string') {
218
- start = BigInt(start);
219
- }
220
- const resolvedBucket = this.resolveBucketName(bucket);
221
- const checkpoint = await this.getCheckpoint(options);
222
- const map = new Map<string, InternalOpId>([[resolvedBucket, start]]);
223
- let data: OplogEntry[] = [];
224
- while (true) {
225
- const batch = this.storage!.getBucketDataBatch(checkpoint, map);
226
-
227
- const batches = await test_utils.fromAsync(batch);
228
- data = data.concat(batches[0]?.chunkData.data ?? []);
229
- if (batches.length == 0 || !batches[0]!.chunkData.has_more) {
230
- break;
231
- }
232
- map.set(resolvedBucket, BigInt(batches[0]!.chunkData.next_after));
233
- }
234
- return data;
235
- }
236
-
237
- async getChecksums(buckets: string[], options?: { timeout?: number }) {
238
- const checkpoint = await this.getCheckpoint(options);
239
- const versionedBuckets = buckets.map((bucket) => this.resolveBucketName(bucket));
240
- const checksums = await this.storage!.getChecksums(checkpoint, versionedBuckets);
241
-
242
- const unversioned = new Map();
243
- for (let i = 0; i < buckets.length; i++) {
244
- unversioned.set(buckets[i], checksums.get(versionedBuckets[i])!);
245
- }
246
-
247
- return unversioned;
248
- }
249
-
250
- async getChecksum(bucket: string, options?: { timeout?: number }) {
251
- const checksums = await this.getChecksums([bucket], options);
252
- return checksums.get(bucket);
253
- }
254
-
255
- /**
256
- * This does not wait for a client checkpoint.
257
- */
258
- async getCurrentBucketData(bucket: string, start?: InternalOpId | string | undefined) {
259
- start ??= 0n;
260
- if (typeof start == 'string') {
261
- start = BigInt(start);
262
- }
263
- const resolvedBucket = this.resolveBucketName(bucket);
264
- const { checkpoint } = await this.storage!.getCheckpoint();
265
- const map = new Map<string, InternalOpId>([[resolvedBucket, start]]);
266
- const batch = this.storage!.getBucketDataBatch(checkpoint, map);
267
- const batches = await test_utils.fromAsync(batch);
268
- return batches[0]?.chunkData.data ?? [];
269
- }
270
- }
271
-
272
- export async function withMaxWalSize(db: pgwire.PgClient, size: string) {
273
- try {
274
- const r1 = await db.query(`SHOW max_slot_wal_keep_size`);
275
-
276
- await db.query(`ALTER SYSTEM SET max_slot_wal_keep_size = '100MB'`);
277
- await db.query(`SELECT pg_reload_conf()`);
278
-
279
- const oldSize = r1.results[0].rows[0].decodeWithoutCustomTypes(0);
280
-
281
- return {
282
- [Symbol.asyncDispose]: async () => {
283
- await db.query(`ALTER SYSTEM SET max_slot_wal_keep_size = '${oldSize}'`);
284
- await db.query(`SELECT pg_reload_conf()`);
285
- }
286
- };
287
- } catch (e) {
288
- const err = new Error(`Failed to configure max_slot_wal_keep_size for test`);
289
- err.cause = e;
290
- throw err;
291
- }
292
- }
@@ -1,27 +0,0 @@
1
- {
2
- "extends": "../../../tsconfig.tests.json",
3
- "compilerOptions": {
4
- "baseUrl": "./",
5
- "paths": {
6
- "@/*": ["../../../packages/service-core/src/*"],
7
- "@module/*": ["../src/*"],
8
- "@core-tests/*": ["../../../packages/service-core/test/src/*"]
9
- },
10
- "rootDir": "src"
11
- },
12
- "include": ["src"],
13
- "references": [
14
- {
15
- "path": "../"
16
- },
17
- {
18
- "path": "../../../packages/service-core-tests"
19
- },
20
- {
21
- "path": "../../module-mongodb-storage"
22
- },
23
- {
24
- "path": "../../module-postgres-storage"
25
- }
26
- ]
27
- }
package/tsconfig.json DELETED
@@ -1,34 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.base.json",
3
- "compilerOptions": {
4
- "rootDir": "src",
5
- "outDir": "dist",
6
- "esModuleInterop": true,
7
- "skipLibCheck": true,
8
- "sourceMap": true
9
- },
10
- "include": ["src"],
11
- "references": [
12
- {
13
- "path": "../../packages/types"
14
- },
15
- {
16
- "path": "../../packages/jsonbig"
17
- },
18
- {
19
- "path": "../../packages/jpgwire"
20
- },
21
- {
22
- "path": "../../packages/sync-rules"
23
- },
24
- {
25
- "path": "../../packages/service-core"
26
- },
27
- {
28
- "path": "../../libs/lib-services"
29
- },
30
- {
31
- "path": "../../libs/lib-postgres"
32
- }
33
- ]
34
- }