@powersync/service-module-postgres-storage 0.1.0

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 (157) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/LICENSE +67 -0
  3. package/README.md +67 -0
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/@types/index.d.ts +7 -0
  6. package/dist/@types/migrations/PostgresMigrationAgent.d.ts +12 -0
  7. package/dist/@types/migrations/PostgresMigrationStore.d.ts +14 -0
  8. package/dist/@types/migrations/migration-utils.d.ts +3 -0
  9. package/dist/@types/migrations/scripts/1684951997326-init.d.ts +3 -0
  10. package/dist/@types/module/PostgresStorageModule.d.ts +6 -0
  11. package/dist/@types/storage/PostgresBucketStorageFactory.d.ts +42 -0
  12. package/dist/@types/storage/PostgresCompactor.d.ts +40 -0
  13. package/dist/@types/storage/PostgresStorageProvider.d.ts +5 -0
  14. package/dist/@types/storage/PostgresSyncRulesStorage.d.ts +46 -0
  15. package/dist/@types/storage/PostgresTestStorageFactoryGenerator.d.ts +13 -0
  16. package/dist/@types/storage/batch/OperationBatch.d.ts +47 -0
  17. package/dist/@types/storage/batch/PostgresBucketBatch.d.ts +90 -0
  18. package/dist/@types/storage/batch/PostgresPersistedBatch.d.ts +64 -0
  19. package/dist/@types/storage/checkpoints/PostgresWriteCheckpointAPI.d.ts +20 -0
  20. package/dist/@types/storage/storage-index.d.ts +5 -0
  21. package/dist/@types/storage/sync-rules/PostgresPersistedSyncRulesContent.d.ts +17 -0
  22. package/dist/@types/types/codecs.d.ts +61 -0
  23. package/dist/@types/types/models/ActiveCheckpoint.d.ts +12 -0
  24. package/dist/@types/types/models/ActiveCheckpointNotification.d.ts +19 -0
  25. package/dist/@types/types/models/BucketData.d.ts +22 -0
  26. package/dist/@types/types/models/BucketParameters.d.ts +11 -0
  27. package/dist/@types/types/models/CurrentData.d.ts +22 -0
  28. package/dist/@types/types/models/Instance.d.ts +6 -0
  29. package/dist/@types/types/models/Migration.d.ts +12 -0
  30. package/dist/@types/types/models/SourceTable.d.ts +31 -0
  31. package/dist/@types/types/models/SyncRules.d.ts +47 -0
  32. package/dist/@types/types/models/WriteCheckpoint.d.ts +15 -0
  33. package/dist/@types/types/models/models-index.d.ts +10 -0
  34. package/dist/@types/types/types.d.ts +94 -0
  35. package/dist/@types/utils/bson.d.ts +6 -0
  36. package/dist/@types/utils/bucket-data.d.ts +18 -0
  37. package/dist/@types/utils/db.d.ts +8 -0
  38. package/dist/@types/utils/ts-codec.d.ts +5 -0
  39. package/dist/@types/utils/utils-index.d.ts +4 -0
  40. package/dist/index.js +8 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/migrations/PostgresMigrationAgent.js +36 -0
  43. package/dist/migrations/PostgresMigrationAgent.js.map +1 -0
  44. package/dist/migrations/PostgresMigrationStore.js +60 -0
  45. package/dist/migrations/PostgresMigrationStore.js.map +1 -0
  46. package/dist/migrations/migration-utils.js +13 -0
  47. package/dist/migrations/migration-utils.js.map +1 -0
  48. package/dist/migrations/scripts/1684951997326-init.js +196 -0
  49. package/dist/migrations/scripts/1684951997326-init.js.map +1 -0
  50. package/dist/module/PostgresStorageModule.js +23 -0
  51. package/dist/module/PostgresStorageModule.js.map +1 -0
  52. package/dist/storage/PostgresBucketStorageFactory.js +433 -0
  53. package/dist/storage/PostgresBucketStorageFactory.js.map +1 -0
  54. package/dist/storage/PostgresCompactor.js +298 -0
  55. package/dist/storage/PostgresCompactor.js.map +1 -0
  56. package/dist/storage/PostgresStorageProvider.js +35 -0
  57. package/dist/storage/PostgresStorageProvider.js.map +1 -0
  58. package/dist/storage/PostgresSyncRulesStorage.js +619 -0
  59. package/dist/storage/PostgresSyncRulesStorage.js.map +1 -0
  60. package/dist/storage/PostgresTestStorageFactoryGenerator.js +110 -0
  61. package/dist/storage/PostgresTestStorageFactoryGenerator.js.map +1 -0
  62. package/dist/storage/batch/OperationBatch.js +93 -0
  63. package/dist/storage/batch/OperationBatch.js.map +1 -0
  64. package/dist/storage/batch/PostgresBucketBatch.js +732 -0
  65. package/dist/storage/batch/PostgresBucketBatch.js.map +1 -0
  66. package/dist/storage/batch/PostgresPersistedBatch.js +367 -0
  67. package/dist/storage/batch/PostgresPersistedBatch.js.map +1 -0
  68. package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js +148 -0
  69. package/dist/storage/checkpoints/PostgresWriteCheckpointAPI.js.map +1 -0
  70. package/dist/storage/storage-index.js +6 -0
  71. package/dist/storage/storage-index.js.map +1 -0
  72. package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js +58 -0
  73. package/dist/storage/sync-rules/PostgresPersistedSyncRulesContent.js.map +1 -0
  74. package/dist/types/codecs.js +97 -0
  75. package/dist/types/codecs.js.map +1 -0
  76. package/dist/types/models/ActiveCheckpoint.js +12 -0
  77. package/dist/types/models/ActiveCheckpoint.js.map +1 -0
  78. package/dist/types/models/ActiveCheckpointNotification.js +8 -0
  79. package/dist/types/models/ActiveCheckpointNotification.js.map +1 -0
  80. package/dist/types/models/BucketData.js +23 -0
  81. package/dist/types/models/BucketData.js.map +1 -0
  82. package/dist/types/models/BucketParameters.js +11 -0
  83. package/dist/types/models/BucketParameters.js.map +1 -0
  84. package/dist/types/models/CurrentData.js +16 -0
  85. package/dist/types/models/CurrentData.js.map +1 -0
  86. package/dist/types/models/Instance.js +5 -0
  87. package/dist/types/models/Instance.js.map +1 -0
  88. package/dist/types/models/Migration.js +12 -0
  89. package/dist/types/models/Migration.js.map +1 -0
  90. package/dist/types/models/SourceTable.js +24 -0
  91. package/dist/types/models/SourceTable.js.map +1 -0
  92. package/dist/types/models/SyncRules.js +47 -0
  93. package/dist/types/models/SyncRules.js.map +1 -0
  94. package/dist/types/models/WriteCheckpoint.js +13 -0
  95. package/dist/types/models/WriteCheckpoint.js.map +1 -0
  96. package/dist/types/models/models-index.js +11 -0
  97. package/dist/types/models/models-index.js.map +1 -0
  98. package/dist/types/types.js +46 -0
  99. package/dist/types/types.js.map +1 -0
  100. package/dist/utils/bson.js +16 -0
  101. package/dist/utils/bson.js.map +1 -0
  102. package/dist/utils/bucket-data.js +25 -0
  103. package/dist/utils/bucket-data.js.map +1 -0
  104. package/dist/utils/db.js +24 -0
  105. package/dist/utils/db.js.map +1 -0
  106. package/dist/utils/ts-codec.js +11 -0
  107. package/dist/utils/ts-codec.js.map +1 -0
  108. package/dist/utils/utils-index.js +5 -0
  109. package/dist/utils/utils-index.js.map +1 -0
  110. package/package.json +50 -0
  111. package/src/index.ts +10 -0
  112. package/src/migrations/PostgresMigrationAgent.ts +46 -0
  113. package/src/migrations/PostgresMigrationStore.ts +70 -0
  114. package/src/migrations/migration-utils.ts +14 -0
  115. package/src/migrations/scripts/1684951997326-init.ts +141 -0
  116. package/src/module/PostgresStorageModule.ts +30 -0
  117. package/src/storage/PostgresBucketStorageFactory.ts +496 -0
  118. package/src/storage/PostgresCompactor.ts +366 -0
  119. package/src/storage/PostgresStorageProvider.ts +42 -0
  120. package/src/storage/PostgresSyncRulesStorage.ts +666 -0
  121. package/src/storage/PostgresTestStorageFactoryGenerator.ts +61 -0
  122. package/src/storage/batch/OperationBatch.ts +101 -0
  123. package/src/storage/batch/PostgresBucketBatch.ts +885 -0
  124. package/src/storage/batch/PostgresPersistedBatch.ts +441 -0
  125. package/src/storage/checkpoints/PostgresWriteCheckpointAPI.ts +176 -0
  126. package/src/storage/storage-index.ts +5 -0
  127. package/src/storage/sync-rules/PostgresPersistedSyncRulesContent.ts +67 -0
  128. package/src/types/codecs.ts +136 -0
  129. package/src/types/models/ActiveCheckpoint.ts +15 -0
  130. package/src/types/models/ActiveCheckpointNotification.ts +14 -0
  131. package/src/types/models/BucketData.ts +26 -0
  132. package/src/types/models/BucketParameters.ts +14 -0
  133. package/src/types/models/CurrentData.ts +23 -0
  134. package/src/types/models/Instance.ts +8 -0
  135. package/src/types/models/Migration.ts +19 -0
  136. package/src/types/models/SourceTable.ts +32 -0
  137. package/src/types/models/SyncRules.ts +50 -0
  138. package/src/types/models/WriteCheckpoint.ts +20 -0
  139. package/src/types/models/models-index.ts +10 -0
  140. package/src/types/types.ts +73 -0
  141. package/src/utils/bson.ts +17 -0
  142. package/src/utils/bucket-data.ts +25 -0
  143. package/src/utils/db.ts +27 -0
  144. package/src/utils/ts-codec.ts +14 -0
  145. package/src/utils/utils-index.ts +4 -0
  146. package/test/src/__snapshots__/storage.test.ts.snap +9 -0
  147. package/test/src/__snapshots__/storage_sync.test.ts.snap +332 -0
  148. package/test/src/env.ts +6 -0
  149. package/test/src/migrations.test.ts +34 -0
  150. package/test/src/setup.ts +16 -0
  151. package/test/src/storage.test.ts +131 -0
  152. package/test/src/storage_compacting.test.ts +5 -0
  153. package/test/src/storage_sync.test.ts +12 -0
  154. package/test/src/util.ts +34 -0
  155. package/test/tsconfig.json +20 -0
  156. package/tsconfig.json +36 -0
  157. package/vitest.config.ts +13 -0
@@ -0,0 +1,97 @@
1
+ import * as t from 'ts-codec';
2
+ export const BIGINT_MAX = BigInt('9223372036854775807');
3
+ /**
4
+ * The use of ts-codec:
5
+ * We currently use pgwire for Postgres queries. This library provides fine-grained control
6
+ * over parameter typings and efficient streaming of query responses. Additionally, configuring
7
+ * pgwire with default certificates allows us to use the same connection configuration process
8
+ * for both replication and storage libraries.
9
+ *
10
+ * Unfortunately, ORM driver support for pgwire is limited, so we rely on pure SQL queries in the
11
+ * absence of writing an ORM driver from scratch.
12
+ *
13
+ * [Opinion]: Writing pure SQL queries throughout a codebase can be daunting from a maintenance
14
+ * and debugging perspective. For example, row response types are often declared when performing a query:
15
+ *
16
+ * ```typescript
17
+ * const rows = await db.queryRows<MyRowType>(`SELECT one, two FROM my_table`);
18
+ * ```
19
+ * This type declaration suggests `rows` is an array of `MyRowType` objects, even though no validation
20
+ * is enforced. Adding a field to the `MyRowType` interface without updating the query could easily
21
+ * introduce subtle bugs. Similarly, type mismatches between SQL results and TypeScript interfaces, such as
22
+ * a `Date` field returned as a `string`, require manual conversion.
23
+ *
24
+ * `ts-codec` is not an ORM, but it simplifies working with pure SQL query responses in several ways:
25
+ *
26
+ * - **Validations**: The `decode` operation ensures that the returned row matches the expected object
27
+ * structure, throwing an error if it doesn't.
28
+ * - **Decoding Columns**: pgwire already decodes common SQLite types, but `ts-codec` adds an extra layer
29
+ * for JS-native values. For instance, `jsonb` columns are returned as `JsonContainer`/`string` and can
30
+ * be automatically parsed into objects. Similarly, fields like `group_id` are converted from `Bigint`
31
+ * to `Number` for easier use.
32
+ * - **Encoded Forms**: A single `ts-codec` type definition can infer both encoded and decoded forms. This
33
+ * is especially useful for persisted batch operations that rely on JSON query parameters for bulk inserts.
34
+ * Collections like `bucket_data`, `current_data`, and `bucket_parameters` use encoded/decoded types, making
35
+ * changes easier to manage and validate. While some manual encoding is done for intermediate values (e.g.,
36
+ * size estimation), these types are validated with `ts-codec` to ensure consistency.
37
+ */
38
+ /**
39
+ * Wraps a codec which is encoded to a JSON string
40
+ */
41
+ export const jsonb = (subCodec) => t.codec('jsonb', (decoded) => {
42
+ return JSON.stringify(subCodec.encode(decoded));
43
+ }, (encoded) => {
44
+ const s = typeof encoded == 'object' ? encoded.data : encoded;
45
+ return subCodec.decode(JSON.parse(s));
46
+ });
47
+ /**
48
+ * Just performs a pure JSON.parse for the decoding step
49
+ */
50
+ export const jsonb_raw = () => t.codec('jsonb_raw', (decoded) => {
51
+ return JSON.stringify(decoded);
52
+ }, (encoded) => {
53
+ const s = typeof encoded == 'object' ? encoded.data : encoded;
54
+ return JSON.parse(s);
55
+ });
56
+ export const bigint = t.codec('bigint', (decoded) => {
57
+ return decoded.toString();
58
+ }, (encoded) => {
59
+ return BigInt(encoded);
60
+ });
61
+ export const uint8array = t.codec('uint8array', (d) => d, (e) => e);
62
+ /**
63
+ * PGWire returns BYTEA values as Uint8Array instances.
64
+ * We also serialize to a hex string for bulk inserts.
65
+ */
66
+ export const hexBuffer = t.codec('hexBuffer', (decoded) => {
67
+ return decoded.toString('hex');
68
+ }, (encoded) => {
69
+ if (encoded instanceof Uint8Array) {
70
+ return Buffer.from(encoded);
71
+ }
72
+ if (typeof encoded !== 'string') {
73
+ throw new Error(`Expected either a Buffer instance or hex encoded buffer string`);
74
+ }
75
+ return Buffer.from(encoded, 'hex');
76
+ });
77
+ /**
78
+ * PGWire returns INTEGER columns as a `bigint`.
79
+ * This does a decode operation to `number`.
80
+ */
81
+ export const pgwire_number = t.codec('pg_number', (decoded) => decoded, (encoded) => {
82
+ if (typeof encoded == 'number') {
83
+ return encoded;
84
+ }
85
+ if (typeof encoded !== 'bigint') {
86
+ throw new Error(`Expected either number or bigint for value`);
87
+ }
88
+ if (encoded > BigInt(Number.MAX_SAFE_INTEGER) || encoded < BigInt(Number.MIN_SAFE_INTEGER)) {
89
+ throw new RangeError('BigInt value is out of safe integer range for conversion to Number.');
90
+ }
91
+ return Number(encoded);
92
+ });
93
+ /**
94
+ * A codec which contains the same type on the input and output.
95
+ */
96
+ export const IdentityCodec = () => t.codec('identity', (encoded) => encoded, (decoded) => decoded);
97
+ //# sourceMappingURL=codecs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codecs.js","sourceRoot":"","sources":["../../src/types/codecs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import * as t from 'ts-codec';
2
+ import { bigint, pgwire_number } from '../codecs.js';
3
+ /**
4
+ * Notification payload sent via Postgres' NOTIFY API.
5
+ *
6
+ */
7
+ export const ActiveCheckpoint = t.object({
8
+ id: pgwire_number,
9
+ last_checkpoint: t.Null.or(bigint),
10
+ last_checkpoint_lsn: t.Null.or(t.string)
11
+ });
12
+ //# sourceMappingURL=ActiveCheckpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActiveCheckpoint.js","sourceRoot":"","sources":["../../../src/types/models/ActiveCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAErD;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,aAAa;IACjB,eAAe,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;IAClC,mBAAmB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;CACzC,CAAC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import * as t from 'ts-codec';
2
+ import { jsonb } from '../codecs.js';
3
+ import { ActiveCheckpoint } from './ActiveCheckpoint.js';
4
+ export const ActiveCheckpointPayload = t.object({
5
+ active_checkpoint: ActiveCheckpoint
6
+ });
7
+ export const ActiveCheckpointNotification = jsonb(ActiveCheckpointPayload);
8
+ //# sourceMappingURL=ActiveCheckpointNotification.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ActiveCheckpointNotification.js","sourceRoot":"","sources":["../../../src/types/models/ActiveCheckpointNotification.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEzD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,iBAAiB,EAAE,gBAAgB;CACpC,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,4BAA4B,GAAG,KAAK,CAAC,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import * as t from 'ts-codec';
2
+ import { bigint, hexBuffer, pgwire_number } from '../codecs.js';
3
+ export var OpType;
4
+ (function (OpType) {
5
+ OpType["PUT"] = "PUT";
6
+ OpType["REMOVE"] = "REMOVE";
7
+ OpType["MOVE"] = "MOVE";
8
+ OpType["CLEAR"] = "CLEAR";
9
+ })(OpType || (OpType = {}));
10
+ export const BucketData = t.object({
11
+ group_id: pgwire_number,
12
+ bucket_name: t.string,
13
+ op_id: bigint,
14
+ op: t.Enum(OpType),
15
+ source_table: t.Null.or(t.string),
16
+ source_key: t.Null.or(hexBuffer),
17
+ table_name: t.string.or(t.Null),
18
+ row_id: t.string.or(t.Null),
19
+ checksum: bigint,
20
+ data: t.Null.or(t.string),
21
+ target_op: t.Null.or(bigint)
22
+ });
23
+ //# sourceMappingURL=BucketData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BucketData.js","sourceRoot":"","sources":["../../../src/types/models/BucketData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,CAAN,IAAY,MAKX;AALD,WAAY,MAAM;IAChB,qBAAW,CAAA;IACX,2BAAiB,CAAA;IACjB,uBAAa,CAAA;IACb,yBAAe,CAAA;AACjB,CAAC,EALW,MAAM,KAAN,MAAM,QAKjB;AAED,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;IACjC,QAAQ,EAAE,aAAa;IACvB,WAAW,EAAE,CAAC,CAAC,MAAM;IACrB,KAAK,EAAE,MAAM;IACb,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC;IAClB,YAAY,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACjC,UAAU,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,CAAC;IAChC,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3B,QAAQ,EAAE,MAAM;IAChB,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC;IACzB,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,CAAC;CAC7B,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import * as t from 'ts-codec';
2
+ import { bigint, hexBuffer, pgwire_number } from '../codecs.js';
3
+ export const BucketParameters = t.object({
4
+ id: bigint,
5
+ group_id: pgwire_number,
6
+ source_table: t.string,
7
+ source_key: hexBuffer,
8
+ lookup: hexBuffer,
9
+ bucket_parameters: t.string
10
+ });
11
+ //# sourceMappingURL=BucketParameters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"BucketParameters.js","sourceRoot":"","sources":["../../../src/types/models/BucketParameters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAEhE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,EAAE,EAAE,MAAM;IACV,QAAQ,EAAE,aAAa;IACvB,YAAY,EAAE,CAAC,CAAC,MAAM;IACtB,UAAU,EAAE,SAAS;IACrB,MAAM,EAAE,SAAS;IACjB,iBAAiB,EAAE,CAAC,CAAC,MAAM;CAC5B,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import * as t from 'ts-codec';
2
+ import { hexBuffer, jsonb, pgwire_number } from '../codecs.js';
3
+ export const CurrentBucket = t.object({
4
+ bucket: t.string,
5
+ table: t.string,
6
+ id: t.string
7
+ });
8
+ export const CurrentData = t.object({
9
+ buckets: jsonb(t.array(CurrentBucket)),
10
+ data: hexBuffer,
11
+ group_id: pgwire_number,
12
+ lookups: t.array(hexBuffer),
13
+ source_key: hexBuffer,
14
+ source_table: t.string
15
+ });
16
+ //# sourceMappingURL=CurrentData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"CurrentData.js","sourceRoot":"","sources":["../../../src/types/models/CurrentData.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE/D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,MAAM,EAAE,CAAC,CAAC,MAAM;IAChB,KAAK,EAAE,CAAC,CAAC,MAAM;IACf,EAAE,EAAE,CAAC,CAAC,MAAM;CACb,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACtC,IAAI,EAAE,SAAS;IACf,QAAQ,EAAE,aAAa;IACvB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC;IAC3B,UAAU,EAAE,SAAS;IACrB,YAAY,EAAE,CAAC,CAAC,MAAM;CACvB,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ import * as t from 'ts-codec';
2
+ export const Instance = t.object({
3
+ id: t.string
4
+ });
5
+ //# sourceMappingURL=Instance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Instance.js","sourceRoot":"","sources":["../../../src/types/models/Instance.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/B,EAAE,EAAE,CAAC,CAAC,MAAM;CACb,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { framework } from '@powersync/service-core';
2
+ import * as t from 'ts-codec';
3
+ import { jsonb } from '../codecs.js';
4
+ export const Migration = t.object({
5
+ last_run: t.string,
6
+ log: jsonb(t.array(t.object({
7
+ name: t.string,
8
+ direction: t.Enum(framework.migrations.Direction),
9
+ timestamp: framework.codecs.date
10
+ })))
11
+ });
12
+ //# sourceMappingURL=Migration.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Migration.js","sourceRoot":"","sources":["../../../src/types/models/Migration.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAErC,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAC,MAAM,CAAC;IAChC,QAAQ,EAAE,CAAC,CAAC,MAAM;IAClB,GAAG,EAAE,KAAK,CACR,CAAC,CAAC,KAAK,CACL,CAAC,CAAC,MAAM,CAAC;QACP,IAAI,EAAE,CAAC,CAAC,MAAM;QACd,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,SAAS,CAAC;QACjD,SAAS,EAAE,SAAS,CAAC,MAAM,CAAC,IAAI;KACjC,CAAC,CACH,CACF;CACF,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import * as t from 'ts-codec';
2
+ import { bigint, jsonb, jsonb_raw, pgwire_number } from '../codecs.js';
3
+ export const ColumnDescriptor = t.object({
4
+ name: t.string,
5
+ /**
6
+ * The type of the column ie VARCHAR, INT, etc
7
+ */
8
+ type: t.string.optional(),
9
+ /**
10
+ * Some data sources have a type id that can be used to identify the type of the column
11
+ */
12
+ typeId: t.number.optional()
13
+ });
14
+ export const SourceTable = t.object({
15
+ id: t.string,
16
+ group_id: pgwire_number,
17
+ connection_id: bigint,
18
+ relation_id: t.Null.or(jsonb_raw()),
19
+ schema_name: t.string,
20
+ table_name: t.string,
21
+ replica_id_columns: t.Null.or(jsonb(t.array(ColumnDescriptor))),
22
+ snapshot_done: t.boolean
23
+ });
24
+ //# sourceMappingURL=SourceTable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SourceTable.js","sourceRoot":"","sources":["../../../src/types/models/SourceTable.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAMvE,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,CAAC,MAAM;IACd;;OAEG;IACH,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;IACzB;;OAEG;IACH,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,EAAE,EAAE,CAAC,CAAC,MAAM;IACZ,QAAQ,EAAE,aAAa;IACvB,aAAa,EAAE,MAAM;IACrB,WAAW,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,EAAoB,CAAC;IACrD,WAAW,EAAE,CAAC,CAAC,MAAM;IACrB,UAAU,EAAE,CAAC,CAAC,MAAM;IACpB,kBAAkB,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC;IAC/D,aAAa,EAAE,CAAC,CAAC,OAAO;CACzB,CAAC,CAAC"}
@@ -0,0 +1,47 @@
1
+ import { framework, storage } from '@powersync/service-core';
2
+ import * as t from 'ts-codec';
3
+ import { bigint, pgwire_number } from '../codecs.js';
4
+ export const SyncRules = t.object({
5
+ id: pgwire_number,
6
+ state: t.Enum(storage.SyncRuleState),
7
+ /**
8
+ * True if initial snapshot has been replicated.
9
+ *
10
+ * Can only be false if state == PROCESSING.
11
+ */
12
+ snapshot_done: t.boolean,
13
+ /**
14
+ * The last consistent checkpoint.
15
+ *
16
+ * There may be higher OpIds used in the database if we're in the middle of replicating a large transaction.
17
+ */
18
+ last_checkpoint: t.Null.or(bigint),
19
+ /**
20
+ * The LSN associated with the last consistent checkpoint.
21
+ */
22
+ last_checkpoint_lsn: t.Null.or(t.string),
23
+ /**
24
+ * If set, no new checkpoints may be created < this value.
25
+ */
26
+ no_checkpoint_before: t.Null.or(t.string),
27
+ slot_name: t.string,
28
+ /**
29
+ * Last time we persisted a checkpoint.
30
+ *
31
+ * This may be old if no data is incoming.
32
+ */
33
+ last_checkpoint_ts: t.Null.or(framework.codecs.date),
34
+ /**
35
+ * Last time we persisted a checkpoint or keepalive.
36
+ *
37
+ * This should stay fairly current while replicating.
38
+ */
39
+ last_keepalive_ts: t.Null.or(framework.codecs.date),
40
+ /**
41
+ * If an error is stopping replication, it will be stored here.
42
+ */
43
+ last_fatal_error: t.Null.or(t.string),
44
+ keepalive_op: t.Null.or(bigint),
45
+ content: t.string
46
+ });
47
+ //# sourceMappingURL=SyncRules.js.map
@@ -0,0 +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;AAErD,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;;;;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,OAAO,EAAE,CAAC,CAAC,MAAM;CAClB,CAAC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import * as t from 'ts-codec';
2
+ import { bigint, jsonb } from '../codecs.js';
3
+ export const WriteCheckpoint = t.object({
4
+ user_id: t.string,
5
+ lsns: jsonb(t.record(t.string)),
6
+ write_checkpoint: bigint
7
+ });
8
+ export const CustomWriteCheckpoint = t.object({
9
+ user_id: t.string,
10
+ write_checkpoint: bigint,
11
+ sync_rules_id: bigint
12
+ });
13
+ //# sourceMappingURL=WriteCheckpoint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WriteCheckpoint.js","sourceRoot":"","sources":["../../../src/types/models/WriteCheckpoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;IAC/B,gBAAgB,EAAE,MAAM;CACzB,CAAC,CAAC;AAKH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,MAAM;IACjB,gBAAgB,EAAE,MAAM;IACxB,aAAa,EAAE,MAAM;CACtB,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ export * from './ActiveCheckpoint.js';
2
+ export * from './ActiveCheckpointNotification.js';
3
+ export * from './BucketData.js';
4
+ export * from './BucketParameters.js';
5
+ export * from './CurrentData.js';
6
+ export * from './Instance.js';
7
+ export * from './Migration.js';
8
+ export * from './SourceTable.js';
9
+ export * from './SyncRules.js';
10
+ export * from './WriteCheckpoint.js';
11
+ //# sourceMappingURL=models-index.js.map
@@ -0,0 +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"}
@@ -0,0 +1,46 @@
1
+ import * as lib_postgres from '@powersync/lib-service-postgres';
2
+ import { configFile } from '@powersync/service-types';
3
+ import * as t from 'ts-codec';
4
+ export * as models from './models/models-index.js';
5
+ export const MAX_BATCH_RECORD_COUNT = 2000;
6
+ export const MAX_BATCH_ESTIMATED_SIZE = 5_000_000;
7
+ export const MAX_BATCH_CURRENT_DATA_SIZE = 50_000_000;
8
+ export const BatchLimits = t.object({
9
+ /**
10
+ * Maximum size of operations we write in a single transaction.
11
+ */
12
+ max_estimated_size: t.number.optional(),
13
+ /**
14
+ * Limit number of documents to write in a single transaction.
15
+ */
16
+ max_record_count: t.number.optional()
17
+ });
18
+ export const OperationBatchLimits = BatchLimits.and(t.object({
19
+ /**
20
+ * Maximum size of size of current_data documents we lookup at a time.
21
+ */
22
+ max_current_data_batch_size: t.number.optional()
23
+ }));
24
+ export const PostgresStorageConfig = configFile.BaseStorageConfig.and(lib_postgres.BasePostgresConnectionConfig).and(t.object({
25
+ /**
26
+ * Allow batch operation limits to be configurable.
27
+ * Postgres has less batch size restrictions compared to MongoDB.
28
+ * Increasing limits can drastically improve replication performance, but
29
+ * can come at the cost of higher memory usage or potential issues.
30
+ */
31
+ batch_limits: OperationBatchLimits.optional()
32
+ }));
33
+ export const normalizePostgresStorageConfig = (baseConfig) => {
34
+ return {
35
+ ...lib_postgres.normalizeConnectionConfig(baseConfig),
36
+ batch_limits: {
37
+ max_current_data_batch_size: baseConfig.batch_limits?.max_current_data_batch_size ?? MAX_BATCH_CURRENT_DATA_SIZE,
38
+ max_estimated_size: baseConfig.batch_limits?.max_estimated_size ?? MAX_BATCH_ESTIMATED_SIZE,
39
+ max_record_count: baseConfig.batch_limits?.max_record_count ?? MAX_BATCH_RECORD_COUNT
40
+ }
41
+ };
42
+ };
43
+ export const isPostgresStorageConfig = (config) => {
44
+ return config.type == lib_postgres.POSTGRES_CONNECTION_TYPE;
45
+ };
46
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAEhE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAC9B,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC;AAE3C,MAAM,CAAC,MAAM,wBAAwB,GAAG,SAAS,CAAC;AAElD,MAAM,CAAC,MAAM,2BAA2B,GAAG,UAAU,CAAC;AAEtD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC;;OAEG;IACH,kBAAkB,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;IACvC;;OAEG;IACH,gBAAgB,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;CACtC,CAAC,CAAC;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAG,WAAW,CAAC,GAAG,CACjD,CAAC,CAAC,MAAM,CAAC;IACP;;OAEG;IACH,2BAA2B,EAAE,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE;CACjD,CAAC,CACH,CAAC;AAIF,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC,iBAAiB,CAAC,GAAG,CAAC,YAAY,CAAC,4BAA4B,CAAC,CAAC,GAAG,CAClH,CAAC,CAAC,MAAM,CAAC;IACP;;;;;OAKG;IACH,YAAY,EAAE,oBAAoB,CAAC,QAAQ,EAAE;CAC9C,CAAC,CACH,CAAC;AAWF,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAC5C,UAAwC,EACP,EAAE;IACnC,OAAO;QACL,GAAG,YAAY,CAAC,yBAAyB,CAAC,UAAU,CAAC;QACrD,YAAY,EAAE;YACZ,2BAA2B,EAAE,UAAU,CAAC,YAAY,EAAE,2BAA2B,IAAI,2BAA2B;YAChH,kBAAkB,EAAE,UAAU,CAAC,YAAY,EAAE,kBAAkB,IAAI,wBAAwB;YAC3F,gBAAgB,EAAE,UAAU,CAAC,YAAY,EAAE,gBAAgB,IAAI,sBAAsB;SACtF;KACF,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,MAAoC,EAAmC,EAAE;IAC/G,OAAO,MAAM,CAAC,IAAI,IAAI,YAAY,CAAC,wBAAwB,CAAC;AAC9D,CAAC,CAAC"}
@@ -0,0 +1,16 @@
1
+ import { storage, utils } from '@powersync/service-core';
2
+ import * as uuid from 'uuid';
3
+ /**
4
+ * BSON is used to serialize certain documents for storage in BYTEA columns.
5
+ * JSONB columns do not directly support storing binary data which could be required in future.
6
+ */
7
+ export function replicaIdToSubkey(tableId, id) {
8
+ // Hashed UUID from the table and id
9
+ if (storage.isUUID(id)) {
10
+ // Special case for UUID for backwards-compatiblity
11
+ return `${tableId}/${id.toHexString()}`;
12
+ }
13
+ const repr = storage.serializeBson({ table: tableId, id });
14
+ return uuid.v5(repr, utils.ID_NAMESPACE);
15
+ }
16
+ //# sourceMappingURL=bson.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bson.js","sourceRoot":"","sources":["../../src/utils/bson.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AACzD,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAE7B;;;GAGG;AAEH,MAAM,UAAU,iBAAiB,CAAC,OAAe,EAAE,EAAqB;IACtE,oCAAoC;IACpC,IAAI,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC;QACvB,mDAAmD;QACnD,OAAO,GAAG,OAAO,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;IAC1C,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC;IAC3D,OAAO,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,YAAY,CAAC,CAAC;AAC3C,CAAC"}
@@ -0,0 +1,25 @@
1
+ import { utils } from '@powersync/service-core';
2
+ import { models } from '../types/types.js';
3
+ import { replicaIdToSubkey } from './bson.js';
4
+ export const mapOpEntry = (entry) => {
5
+ if (entry.op == models.OpType.PUT || entry.op == models.OpType.REMOVE) {
6
+ return {
7
+ op_id: utils.timestampToOpId(entry.op_id),
8
+ op: entry.op,
9
+ object_type: entry.table_name ?? undefined,
10
+ object_id: entry.row_id ?? undefined,
11
+ checksum: Number(entry.checksum),
12
+ subkey: replicaIdToSubkey(entry.source_table, entry.source_key),
13
+ data: entry.data
14
+ };
15
+ }
16
+ else {
17
+ // MOVE, CLEAR
18
+ return {
19
+ op_id: utils.timestampToOpId(entry.op_id),
20
+ op: entry.op,
21
+ checksum: Number(entry.checksum)
22
+ };
23
+ }
24
+ };
25
+ //# sourceMappingURL=bucket-data.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bucket-data.js","sourceRoot":"","sources":["../../src/utils/bucket-data.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,yBAAyB,CAAC;AAChD,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAE9C,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,KAA+B,EAAE,EAAE;IAC5D,IAAI,KAAK,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,EAAE,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACtE,OAAO;YACL,KAAK,EAAE,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;YACzC,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,WAAW,EAAE,KAAK,CAAC,UAAU,IAAI,SAAS;YAC1C,SAAS,EAAE,KAAK,CAAC,MAAM,IAAI,SAAS;YACpC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;YAChC,MAAM,EAAE,iBAAiB,CAAC,KAAK,CAAC,YAAa,EAAE,KAAK,CAAC,UAAW,CAAC;YACjE,IAAI,EAAE,KAAK,CAAC,IAAI;SACjB,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,cAAc;QAEd,OAAO;YACL,KAAK,EAAE,KAAK,CAAC,eAAe,CAAC,KAAK,CAAC,KAAK,CAAC;YACzC,EAAE,EAAE,KAAK,CAAC,EAAE;YACZ,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC;SACjC,CAAC;IACJ,CAAC;AACH,CAAC,CAAC"}
@@ -0,0 +1,24 @@
1
+ import * as lib_postgres from '@powersync/lib-service-postgres';
2
+ export const STORAGE_SCHEMA_NAME = 'powersync';
3
+ export const NOTIFICATION_CHANNEL = 'powersynccheckpoints';
4
+ /**
5
+ * Re export for prettier to detect the tag better
6
+ */
7
+ export const sql = lib_postgres.sql;
8
+ export const dropTables = async (client) => {
9
+ // Lock a connection for automatic schema search paths
10
+ await client.lockConnection(async (db) => {
11
+ await db.sql `DROP TABLE IF EXISTS bucket_data`.execute();
12
+ await db.sql `DROP TABLE IF EXISTS bucket_parameters`.execute();
13
+ await db.sql `DROP TABLE IF EXISTS sync_rules`.execute();
14
+ await db.sql `DROP TABLE IF EXISTS instance`.execute();
15
+ await db.sql `DROP TABLE IF EXISTS bucket_data`.execute();
16
+ await db.sql `DROP TABLE IF EXISTS current_data`.execute();
17
+ await db.sql `DROP TABLE IF EXISTS source_tables`.execute();
18
+ await db.sql `DROP TABLE IF EXISTS write_checkpoints`.execute();
19
+ await db.sql `DROP TABLE IF EXISTS custom_write_checkpoints`.execute();
20
+ await db.sql `DROP SEQUENCE IF EXISTS op_id_sequence`.execute();
21
+ await db.sql `DROP SEQUENCE IF EXISTS sync_rules_id_sequence`.execute();
22
+ });
23
+ };
24
+ //# sourceMappingURL=db.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.js","sourceRoot":"","sources":["../../src/utils/db.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,YAAY,MAAM,iCAAiC,CAAC;AAEhE,MAAM,CAAC,MAAM,mBAAmB,GAAG,WAAW,CAAC;AAE/C,MAAM,CAAC,MAAM,oBAAoB,GAAG,sBAAsB,CAAC;AAE3D;;GAEG;AACH,MAAM,CAAC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,CAAC;AAEpC,MAAM,CAAC,MAAM,UAAU,GAAG,KAAK,EAAE,MAAmC,EAAE,EAAE;IACtE,sDAAsD;IACtD,MAAM,MAAM,CAAC,cAAc,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QACvC,MAAM,EAAE,CAAC,GAAG,CAAA,kCAAkC,CAAC,OAAO,EAAE,CAAC;QACzD,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,iCAAiC,CAAC,OAAO,EAAE,CAAC;QACxD,MAAM,EAAE,CAAC,GAAG,CAAA,+BAA+B,CAAC,OAAO,EAAE,CAAC;QACtD,MAAM,EAAE,CAAC,GAAG,CAAA,kCAAkC,CAAC,OAAO,EAAE,CAAC;QACzD,MAAM,EAAE,CAAC,GAAG,CAAA,mCAAmC,CAAC,OAAO,EAAE,CAAC;QAC1D,MAAM,EAAE,CAAC,GAAG,CAAA,oCAAoC,CAAC,OAAO,EAAE,CAAC;QAC3D,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,+CAA+C,CAAC,OAAO,EAAE,CAAC;QACtE,MAAM,EAAE,CAAC,GAAG,CAAA,wCAAwC,CAAC,OAAO,EAAE,CAAC;QAC/D,MAAM,EAAE,CAAC,GAAG,CAAA,gDAAgD,CAAC,OAAO,EAAE,CAAC;IACzE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,11 @@
1
+ import * as t from 'ts-codec';
2
+ /**
3
+ * Returns a new codec with a subset of keys. Equivalent to the TypeScript Pick utility.
4
+ */
5
+ export const pick = (codec, keys) => {
6
+ // Filter the shape by the specified keys
7
+ const newShape = Object.fromEntries(Object.entries(codec.props.shape).filter(([key]) => keys.includes(key)));
8
+ // Return a new codec with the narrowed shape
9
+ return t.object(newShape);
10
+ };
11
+ //# sourceMappingURL=ts-codec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ts-codec.js","sourceRoot":"","sources":["../../src/utils/ts-codec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,UAAU,CAAC;AAE9B;;GAEG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG,CAAwD,KAAuB,EAAE,IAAY,EAAE,EAAE;IACnH,yCAAyC;IACzC,MAAM,QAAQ,GAAG,MAAM,CAAC,WAAW,CACjC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAW,CAAC,CAAC,CAC/D,CAAC;IAEnB,6CAA6C;IAC7C,OAAO,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAiC,CAAC;AAC5D,CAAC,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * from './bson.js';
2
+ export * from './bucket-data.js';
3
+ export * from './db.js';
4
+ export * from './ts-codec.js';
5
+ //# sourceMappingURL=utils-index.js.map
@@ -0,0 +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"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@powersync/service-module-postgres-storage",
3
+ "repository": "https://github.com/powersync-ja/powersync-service",
4
+ "types": "dist/@types/index.d.ts",
5
+ "version": "0.1.0",
6
+ "main": "dist/index.js",
7
+ "type": "module",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.js",
15
+ "default": "./dist/index.js",
16
+ "types": "./dist/@types/index.d.ts"
17
+ },
18
+ "./types": {
19
+ "import": "./dist/types/types.js",
20
+ "require": "./dist/types/types.js",
21
+ "default": "./dist/types/types.js",
22
+ "types": "./dist/@types/index.d.ts"
23
+ }
24
+ },
25
+ "dependencies": {
26
+ "@powersync/service-jsonbig": "^0.17.10",
27
+ "ix": "^5.0.0",
28
+ "lru-cache": "^10.2.2",
29
+ "p-defer": "^4.0.1",
30
+ "ts-codec": "^1.3.0",
31
+ "uuid": "^9.0.1",
32
+ "@powersync/lib-services-framework": "0.4.0",
33
+ "@powersync/lib-service-postgres": "0.1.0",
34
+ "@powersync/service-core": "0.15.0",
35
+ "@powersync/service-core-tests": "0.3.0",
36
+ "@powersync/service-jpgwire": "0.18.5",
37
+ "@powersync/service-sync-rules": "0.23.1",
38
+ "@powersync/service-types": "0.7.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/uuid": "^9.0.4",
42
+ "typescript": "^5.2.2"
43
+ },
44
+ "scripts": {
45
+ "build": "tsc -b",
46
+ "build:tests": "tsc -b test/tsconfig.json",
47
+ "clean": "rm -rf ./lib && tsc -b --clean",
48
+ "test": "vitest"
49
+ }
50
+ }
package/src/index.ts ADDED
@@ -0,0 +1,10 @@
1
+ export * from './module/PostgresStorageModule.js';
2
+
3
+ export * from './migrations/PostgresMigrationAgent.js';
4
+
5
+ export * from './utils/utils-index.js';
6
+ export * as utils from './utils/utils-index.js';
7
+
8
+ export * from './storage/storage-index.js';
9
+ export * as storage from './storage/storage-index.js';
10
+ export * from './types/types.js';
@@ -0,0 +1,46 @@
1
+ import * as lib_postgres from '@powersync/lib-service-postgres';
2
+ import * as framework from '@powersync/lib-services-framework';
3
+ import { migrations } from '@powersync/service-core';
4
+ import * as path from 'path';
5
+ import { fileURLToPath } from 'url';
6
+
7
+ import { normalizePostgresStorageConfig, PostgresStorageConfigDecoded } from '../types/types.js';
8
+
9
+ import { STORAGE_SCHEMA_NAME } from '../utils/db.js';
10
+ import { PostgresMigrationStore } from './PostgresMigrationStore.js';
11
+
12
+ const __filename = fileURLToPath(import.meta.url);
13
+ const __dirname = path.dirname(__filename);
14
+
15
+ const MIGRATIONS_DIR = path.join(__dirname, 'scripts');
16
+
17
+ export class PostgresMigrationAgent extends migrations.AbstractPowerSyncMigrationAgent {
18
+ store: framework.MigrationStore;
19
+ locks: framework.LockManager;
20
+
21
+ protected db: lib_postgres.DatabaseClient;
22
+
23
+ constructor(config: PostgresStorageConfigDecoded) {
24
+ super();
25
+
26
+ this.db = new lib_postgres.DatabaseClient({
27
+ config: normalizePostgresStorageConfig(config),
28
+ schema: STORAGE_SCHEMA_NAME
29
+ });
30
+ this.store = new PostgresMigrationStore({
31
+ db: this.db
32
+ });
33
+ this.locks = new lib_postgres.PostgresLockManager({
34
+ name: 'migrations',
35
+ db: this.db
36
+ });
37
+ }
38
+
39
+ getInternalScriptsDir(): string {
40
+ return MIGRATIONS_DIR;
41
+ }
42
+
43
+ async [Symbol.asyncDispose](): Promise<void> {
44
+ await this.db[Symbol.asyncDispose]();
45
+ }
46
+ }