@powersync/service-core 1.12.1 → 1.13.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 (78) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/dist/api/RouteAPI.d.ts +1 -1
  3. package/dist/api/diagnostics.js +1 -1
  4. package/dist/api/diagnostics.js.map +1 -1
  5. package/dist/entry/cli-entry.js +2 -2
  6. package/dist/entry/cli-entry.js.map +1 -1
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.d.ts +1 -1
  11. package/dist/metrics/open-telemetry/OpenTelemetryMetricsFactory.js.map +1 -1
  12. package/dist/replication/AbstractReplicationJob.d.ts +4 -0
  13. package/dist/replication/AbstractReplicationJob.js.map +1 -1
  14. package/dist/replication/AbstractReplicator.d.ts +25 -1
  15. package/dist/replication/AbstractReplicator.js +53 -3
  16. package/dist/replication/AbstractReplicator.js.map +1 -1
  17. package/dist/replication/RelationCache.d.ts +9 -0
  18. package/dist/replication/RelationCache.js +20 -0
  19. package/dist/replication/RelationCache.js.map +1 -0
  20. package/dist/replication/replication-index.d.ts +1 -0
  21. package/dist/replication/replication-index.js +1 -0
  22. package/dist/replication/replication-index.js.map +1 -1
  23. package/dist/replication/replication-metrics.js +6 -0
  24. package/dist/replication/replication-metrics.js.map +1 -1
  25. package/dist/routes/endpoints/admin.js +2 -0
  26. package/dist/routes/endpoints/admin.js.map +1 -1
  27. package/dist/storage/BucketStorageBatch.d.ts +21 -3
  28. package/dist/storage/BucketStorageBatch.js +2 -1
  29. package/dist/storage/BucketStorageBatch.js.map +1 -1
  30. package/dist/storage/PersistedSyncRulesContent.d.ts +5 -0
  31. package/dist/storage/SourceTable.d.ts +17 -1
  32. package/dist/storage/SourceTable.js +28 -0
  33. package/dist/storage/SourceTable.js.map +1 -1
  34. package/dist/storage/StorageEngine.d.ts +3 -2
  35. package/dist/storage/StorageEngine.js +3 -0
  36. package/dist/storage/StorageEngine.js.map +1 -1
  37. package/dist/storage/StorageProvider.d.ts +2 -0
  38. package/dist/storage/SyncRulesBucketStorage.d.ts +18 -6
  39. package/dist/storage/SyncRulesBucketStorage.js.map +1 -1
  40. package/dist/storage/WriteCheckpointAPI.d.ts +0 -26
  41. package/dist/storage/WriteCheckpointAPI.js.map +1 -1
  42. package/dist/storage/bson.js +4 -1
  43. package/dist/storage/bson.js.map +1 -1
  44. package/dist/streams/BroadcastIterable.d.ts +1 -1
  45. package/dist/streams/streams-index.d.ts +0 -1
  46. package/dist/streams/streams-index.js +0 -1
  47. package/dist/streams/streams-index.js.map +1 -1
  48. package/dist/system/ServiceContext.js +6 -0
  49. package/dist/system/ServiceContext.js.map +1 -1
  50. package/package.json +4 -4
  51. package/src/api/RouteAPI.ts +1 -1
  52. package/src/api/diagnostics.ts +1 -1
  53. package/src/entry/cli-entry.ts +2 -2
  54. package/src/index.ts +2 -0
  55. package/src/metrics/open-telemetry/OpenTelemetryMetricsFactory.ts +3 -3
  56. package/src/replication/AbstractReplicationJob.ts +5 -0
  57. package/src/replication/AbstractReplicator.ts +56 -3
  58. package/src/replication/RelationCache.ts +25 -0
  59. package/src/replication/replication-index.ts +1 -0
  60. package/src/replication/replication-metrics.ts +7 -0
  61. package/src/routes/endpoints/admin.ts +2 -0
  62. package/src/storage/BucketStorageBatch.ts +26 -4
  63. package/src/storage/PersistedSyncRulesContent.ts +6 -0
  64. package/src/storage/SourceTable.ts +44 -1
  65. package/src/storage/StorageEngine.ts +6 -2
  66. package/src/storage/StorageProvider.ts +3 -0
  67. package/src/storage/SyncRulesBucketStorage.ts +22 -6
  68. package/src/storage/WriteCheckpointAPI.ts +0 -30
  69. package/src/storage/bson.ts +4 -1
  70. package/src/streams/BroadcastIterable.ts +1 -1
  71. package/src/streams/streams-index.ts +0 -1
  72. package/src/system/ServiceContext.ts +6 -0
  73. package/tsconfig.tsbuildinfo +1 -1
  74. package/dist/streams/Demultiplexer.d.ts +0 -52
  75. package/dist/streams/Demultiplexer.js +0 -128
  76. package/dist/streams/Demultiplexer.js.map +0 -1
  77. package/src/streams/Demultiplexer.ts +0 -165
  78. package/test/src/demultiplexer.test.ts +0 -205
@@ -33,6 +33,12 @@ export class SourceTable {
33
33
  * Defaults to true for tests.
34
34
  */
35
35
  syncEvent = true;
36
+ /**
37
+ * Always undefined if snapshotComplete = true.
38
+ *
39
+ * May be set if snapshotComplete = false.
40
+ */
41
+ snapshotStatus = undefined;
36
42
  constructor(id, connectionTag, objectId, schema, table, replicaIdColumns, snapshotComplete) {
37
43
  this.id = id;
38
44
  this.connectionTag = connectionTag;
@@ -64,5 +70,27 @@ export class SourceTable {
64
70
  get syncAny() {
65
71
  return this.syncData || this.syncParameters || this.syncEvent;
66
72
  }
73
+ /**
74
+ * In-memory clone of the table status.
75
+ */
76
+ clone() {
77
+ const copy = new SourceTable(this.id, this.connectionTag, this.objectId, this.schema, this.table, this.replicaIdColumns, this.snapshotComplete);
78
+ copy.syncData = this.syncData;
79
+ copy.syncParameters = this.syncParameters;
80
+ copy.snapshotStatus = this.snapshotStatus;
81
+ return copy;
82
+ }
83
+ formatSnapshotProgress() {
84
+ if (this.snapshotComplete || this.snapshotStatus == null) {
85
+ // Should not happen
86
+ return '-';
87
+ }
88
+ else if (this.snapshotStatus.totalEstimatedCount < 0) {
89
+ return `${this.snapshotStatus.replicatedCount}/?`;
90
+ }
91
+ else {
92
+ return `${this.snapshotStatus.replicatedCount}/~${this.snapshotStatus.totalEstimatedCount}`;
93
+ }
94
+ }
67
95
  }
68
96
  //# sourceMappingURL=SourceTable.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SourceTable.js","sourceRoot":"","sources":["../../src/storage/SourceTable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAG9C,MAAM,OAAO,WAAW;IA+BJ;IACA;IACA;IACA;IACA;IAEA;IACA;IArClB,MAAM,CAAU,WAAW,GAAG,WAAW,CAAC;IAE1C;;;;;;OAMG;IACI,QAAQ,GAAG,IAAI,CAAC;IAEvB;;;;;;OAMG;IACI,cAAc,GAAG,IAAI,CAAC;IAE7B;;;;;;OAMG;IACI,SAAS,GAAG,IAAI,CAAC;IAExB,YACkB,EAAO,EACP,aAAqB,EACrB,QAAqC,EACrC,MAAc,EACd,KAAa,EAEb,gBAAoC,EACpC,gBAAyB;QAPzB,OAAE,GAAF,EAAE,CAAK;QACP,kBAAa,GAAb,aAAa,CAAQ;QACrB,aAAQ,GAAR,QAAQ,CAA6B;QACrC,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAQ;QAEb,qBAAgB,GAAhB,gBAAgB,CAAoB;QACpC,qBAAgB,GAAhB,gBAAgB,CAAS;IACxC,CAAC;IAEJ,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACH,IAAI,iBAAiB;QACnB,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IACtF,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,SAAS,CAAC;IAChE,CAAC"}
1
+ {"version":3,"file":"SourceTable.js","sourceRoot":"","sources":["../../src/storage/SourceTable.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,IAAI,MAAM,uBAAuB,CAAC;AAS9C,MAAM,OAAO,WAAW;IAsCJ;IACA;IACA;IACA;IACA;IAEA;IACT;IA5CT,MAAM,CAAU,WAAW,GAAG,WAAW,CAAC;IAE1C;;;;;;OAMG;IACI,QAAQ,GAAG,IAAI,CAAC;IAEvB;;;;;;OAMG;IACI,cAAc,GAAG,IAAI,CAAC;IAE7B;;;;;;OAMG;IACI,SAAS,GAAG,IAAI,CAAC;IAExB;;;;OAIG;IACI,cAAc,GAAoC,SAAS,CAAC;IAEnE,YACkB,EAAO,EACP,aAAqB,EACrB,QAAqC,EACrC,MAAc,EACd,KAAa,EAEb,gBAAoC,EAC7C,gBAAyB;QAPhB,OAAE,GAAF,EAAE,CAAK;QACP,kBAAa,GAAb,aAAa,CAAQ;QACrB,aAAQ,GAAR,QAAQ,CAA6B;QACrC,WAAM,GAAN,MAAM,CAAQ;QACd,UAAK,GAAL,KAAK,CAAQ;QAEb,qBAAgB,GAAhB,gBAAgB,CAAoB;QAC7C,qBAAgB,GAAhB,gBAAgB,CAAS;IAC/B,CAAC;IAEJ,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC;IAC1C,CAAC;IAED;;;;OAIG;IACH,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,iBAAiB,CAAC;IAChC,CAAC;IAED;;;;OAIG;IACH,IAAI,iBAAiB;QACnB,OAAO,GAAG,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;IACtF,CAAC;IAED,IAAI,OAAO;QACT,OAAO,IAAI,CAAC,QAAQ,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,CAAC,SAAS,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,KAAK;QACH,MAAM,IAAI,GAAG,IAAI,WAAW,CAC1B,IAAI,CAAC,EAAE,EACP,IAAI,CAAC,aAAa,EAClB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,MAAM,EACX,IAAI,CAAC,KAAK,EACV,IAAI,CAAC,gBAAgB,EACrB,IAAI,CAAC,gBAAgB,CACtB,CAAC;QACF,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC;QAC9B,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC1C,IAAI,CAAC,cAAc,GAAG,IAAI,CAAC,cAAc,CAAC;QAC1C,OAAO,IAAI,CAAC;IACd,CAAC;IAED,sBAAsB;QACpB,IAAI,IAAI,CAAC,gBAAgB,IAAI,IAAI,CAAC,cAAc,IAAI,IAAI,EAAE,CAAC;YACzD,oBAAoB;YACpB,OAAO,GAAG,CAAC;QACb,CAAC;aAAM,IAAI,IAAI,CAAC,cAAc,CAAC,mBAAmB,GAAG,CAAC,EAAE,CAAC;YACvD,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,IAAI,CAAC;QACpD,CAAC;aAAM,CAAC;YACN,OAAO,GAAG,IAAI,CAAC,cAAc,CAAC,eAAe,KAAK,IAAI,CAAC,cAAc,CAAC,mBAAmB,EAAE,CAAC;QAC9F,CAAC;IACH,CAAC"}
@@ -1,12 +1,13 @@
1
- import { BaseObserver } from '@powersync/lib-services-framework';
1
+ import { BaseObserver, ServiceError } from '@powersync/lib-services-framework';
2
2
  import { ResolvedPowerSyncConfig } from '../util/util-index.js';
3
- import { ActiveStorage, BucketStorageProvider } from './StorageProvider.js';
4
3
  import { BucketStorageFactory } from './BucketStorageFactory.js';
4
+ import { ActiveStorage, BucketStorageProvider } from './StorageProvider.js';
5
5
  export type StorageEngineOptions = {
6
6
  configuration: ResolvedPowerSyncConfig;
7
7
  };
8
8
  export interface StorageEngineListener {
9
9
  storageActivated: (storage: BucketStorageFactory) => void;
10
+ storageFatalError: (error: ServiceError) => void;
10
11
  }
11
12
  export declare class StorageEngine extends BaseObserver<StorageEngineListener> {
12
13
  private options;
@@ -31,6 +31,9 @@ export class StorageEngine extends BaseObserver {
31
31
  resolvedConfig: configuration
32
32
  });
33
33
  this.iterateListeners((cb) => cb.storageActivated?.(this.activeBucketStorage));
34
+ this.currentActiveStorage.onFatalError?.((error) => {
35
+ this.iterateListeners((cb) => cb.storageFatalError?.(error));
36
+ });
34
37
  logger.info(`Successfully activated storage: ${configuration.storage.type}.`);
35
38
  logger.info('Successfully started Storage Engine.');
36
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"StorageEngine.js","sourceRoot":"","sources":["../../src/storage/StorageEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,mCAAmC,CAAC;AAazE,MAAM,OAAO,aAAc,SAAQ,YAAmC;IAKhD;IAJpB,yFAAyF;IACjF,gBAAgB,GAAuC,IAAI,GAAG,EAAE,CAAC;IACjE,oBAAoB,GAAyB,IAAI,CAAC;IAE1D,YAAoB,OAA6B;QAC/C,KAAK,EAAE,CAAC;QADU,YAAO,GAAP,OAAO,CAAsB;IAEjD,CAAC;IAED,IAAI,mBAAmB;QACrB,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;IACpC,CAAC;IAED,IAAI,aAAa;QACf,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,IAAI,CAAC,oBAAoB,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,gBAAgB,CAAC,QAA+B;QAC9C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC1C,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACvC,IAAI,CAAC,oBAAoB,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAE,CAAC,UAAU,CAAC;YAClG,cAAc,EAAE,aAAa;SAC9B,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAC/E,MAAM,CAAC,IAAI,CAAC,mCAAmC,aAAa,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;QAC9E,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,QAAQ;QACnB,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,oBAAoB,EAAE,QAAQ,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACxD,CAAC;CACF"}
1
+ {"version":3,"file":"StorageEngine.js","sourceRoot":"","sources":["../../src/storage/StorageEngine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAgB,MAAM,mCAAmC,CAAC;AAcvF,MAAM,OAAO,aAAc,SAAQ,YAAmC;IAKhD;IAJpB,yFAAyF;IACjF,gBAAgB,GAAuC,IAAI,GAAG,EAAE,CAAC;IACjE,oBAAoB,GAAyB,IAAI,CAAC;IAE1D,YAAoB,OAA6B;QAC/C,KAAK,EAAE,CAAC;QADU,YAAO,GAAP,OAAO,CAAsB;IAEjD,CAAC;IAED,IAAI,mBAAmB;QACrB,OAAO,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC;IACpC,CAAC;IAED,IAAI,aAAa;QACf,IAAI,CAAC,IAAI,CAAC,oBAAoB,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,IAAI,CAAC,oBAAoB,CAAC;IACnC,CAAC;IAED;;;OAGG;IACH,gBAAgB,CAAC,QAA+B;QAC9C,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAEM,KAAK,CAAC,KAAK;QAChB,MAAM,CAAC,IAAI,CAAC,4BAA4B,CAAC,CAAC;QAC1C,MAAM,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC;QACvC,IAAI,CAAC,oBAAoB,GAAG,MAAM,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,aAAa,CAAC,OAAO,CAAC,IAAI,CAAE,CAAC,UAAU,CAAC;YAClG,cAAc,EAAE,aAAa;SAC9B,CAAC,CAAC;QACH,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,gBAAgB,EAAE,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC;QAC/E,IAAI,CAAC,oBAAoB,CAAC,YAAY,EAAE,CAAC,CAAC,KAAK,EAAE,EAAE;YACjD,IAAI,CAAC,gBAAgB,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,iBAAiB,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QACH,MAAM,CAAC,IAAI,CAAC,mCAAmC,aAAa,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC;QAC9E,MAAM,CAAC,IAAI,CAAC,sCAAsC,CAAC,CAAC;IACtD,CAAC;IAED;;OAEG;IACI,KAAK,CAAC,QAAQ;QACnB,MAAM,CAAC,IAAI,CAAC,iCAAiC,CAAC,CAAC;QAC/C,MAAM,IAAI,CAAC,oBAAoB,EAAE,QAAQ,EAAE,CAAC;QAC5C,MAAM,CAAC,IAAI,CAAC,wCAAwC,CAAC,CAAC;IACxD,CAAC;CACF"}
@@ -1,3 +1,4 @@
1
+ import { ServiceError } from '@powersync/lib-services-framework';
1
2
  import * as util from '../util/util-index.js';
2
3
  import { BucketStorageFactory } from './BucketStorageFactory.js';
3
4
  export interface ActiveStorage {
@@ -7,6 +8,7 @@ export interface ActiveStorage {
7
8
  * Tear down / drop the storage permanently
8
9
  */
9
10
  tearDown(): Promise<boolean>;
11
+ onFatalError?(callback: (error: ServiceError) => void): void;
10
12
  }
11
13
  export interface GetStorageOptions {
12
14
  resolvedConfig: util.ResolvedPowerSyncConfig;
@@ -1,7 +1,7 @@
1
- import { ObserverClient } from '@powersync/lib-services-framework';
1
+ import { Logger, ObserverClient } from '@powersync/lib-services-framework';
2
2
  import { ParameterLookup, SqlSyncRules, SqliteJsonRow } from '@powersync/service-sync-rules';
3
3
  import * as util from '../util/util-index.js';
4
- import { BucketStorageBatch, FlushedResult } from './BucketStorageBatch.js';
4
+ import { BucketStorageBatch, FlushedResult, SaveUpdate } from './BucketStorageBatch.js';
5
5
  import { BucketStorageFactory } from './BucketStorageFactory.js';
6
6
  import { ParseSyncRulesOptions } from './PersistedSyncRulesContent.js';
7
7
  import { SourceEntityDescriptor } from './SourceEntity.js';
@@ -35,7 +35,7 @@ export interface SyncRulesBucketStorage extends ObserverClient<SyncRulesBucketSt
35
35
  /**
36
36
  * Clear the storage, without changing state.
37
37
  */
38
- clear(): Promise<void>;
38
+ clear(options?: ClearStorageOptions): Promise<void>;
39
39
  autoActivate(): Promise<void>;
40
40
  /**
41
41
  * Record a replication error.
@@ -95,6 +95,7 @@ export interface SyncRuleStatus {
95
95
  checkpoint_lsn: string | null;
96
96
  active: boolean;
97
97
  snapshot_done: boolean;
98
+ snapshot_lsn: string | null;
98
99
  }
99
100
  export interface ResolveTableOptions {
100
101
  group_id: number;
@@ -125,6 +126,13 @@ export interface StartBatchOptions extends ParseSyncRulesOptions {
125
126
  * This will avoid creating new operations for rows previously replicated.
126
127
  */
127
128
  skipExistingRows?: boolean;
129
+ /**
130
+ * Callback called if we streamed an update to a record that we don't have yet.
131
+ *
132
+ * This is expected to happen in some initial replication edge cases, only if storeCurrentData = true.
133
+ */
134
+ markRecordUnavailable?: BucketStorageMarkRecordUnavailable;
135
+ logger?: Logger;
128
136
  }
129
137
  export interface CompactOptions {
130
138
  /**
@@ -159,7 +167,10 @@ export interface CompactOptions {
159
167
  /** Minimum of 1 */
160
168
  moveBatchQueryLimit?: number;
161
169
  }
162
- export interface TerminateOptions {
170
+ export interface ClearStorageOptions {
171
+ signal?: AbortSignal;
172
+ }
173
+ export interface TerminateOptions extends ClearStorageOptions {
163
174
  /**
164
175
  * If true, also clear the storage before terminating.
165
176
  */
@@ -205,8 +216,8 @@ export interface StorageCheckpointUpdate extends WriteCheckpoint {
205
216
  update: CheckpointChanges;
206
217
  }
207
218
  export interface GetCheckpointChangesOptions {
208
- lastCheckpoint: util.InternalOpId;
209
- nextCheckpoint: util.InternalOpId;
219
+ lastCheckpoint: ReplicationCheckpoint;
220
+ nextCheckpoint: ReplicationCheckpoint;
210
221
  }
211
222
  export interface CheckpointChanges {
212
223
  updatedDataBuckets: Set<string>;
@@ -216,3 +227,4 @@ export interface CheckpointChanges {
216
227
  invalidateParameterBuckets: boolean;
217
228
  }
218
229
  export declare const CHECKPOINT_INVALIDATE_ALL: CheckpointChanges;
230
+ export type BucketStorageMarkRecordUnavailable = (record: SaveUpdate) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"SyncRulesBucketStorage.js","sourceRoot":"","sources":["../../src/storage/SyncRulesBucketStorage.ts"],"names":[],"mappings":"AA8QA,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,kBAAkB,EAAE,IAAI,GAAG,EAAU;IACrC,qBAAqB,EAAE,IAAI;IAC3B,uBAAuB,EAAE,IAAI,GAAG,EAAU;IAC1C,0BAA0B,EAAE,IAAI;CACjC,CAAC"}
1
+ {"version":3,"file":"SyncRulesBucketStorage.js","sourceRoot":"","sources":["../../src/storage/SyncRulesBucketStorage.ts"],"names":[],"mappings":"AA4RA,MAAM,CAAC,MAAM,yBAAyB,GAAsB;IAC1D,kBAAkB,EAAE,IAAI,GAAG,EAAU;IACrC,qBAAqB,EAAE,IAAI;IAC3B,uBAAuB,EAAE,IAAI,GAAG,EAAU;IAC1C,0BAA0B,EAAE,IAAI;CACjC,CAAC"}
@@ -44,32 +44,9 @@ export interface ManagedWriteCheckpointFilters extends BaseWriteCheckpointIdenti
44
44
  */
45
45
  heads: Record<string, string>;
46
46
  }
47
- export interface WriteCheckpointResult {
48
- /**
49
- * Write checkpoint id (also referred to as client_id).
50
- *
51
- * If null, there is no write checkpoint for the client.
52
- */
53
- id: bigint | null;
54
- /**
55
- * LSN for the checkpoint.
56
- *
57
- * This will change when we support multiple connections.
58
- *
59
- * For managed write checkpoints, this LSN must be exceeded by the checkpoint / replication head to be valid.
60
- *
61
- * For custom write checkpoints, this will be null, and the write checkpoint is valid for all LSNs.
62
- */
63
- lsn: string | null;
64
- }
65
47
  export type ManagedWriteCheckpointOptions = ManagedWriteCheckpointFilters;
66
48
  export type SyncStorageLastWriteCheckpointFilters = BaseWriteCheckpointIdentifier | ManagedWriteCheckpointFilters;
67
49
  export type LastWriteCheckpointFilters = CustomWriteCheckpointFilters | ManagedWriteCheckpointFilters;
68
- export interface WatchUserWriteCheckpointOptions {
69
- user_id: string;
70
- sync_rules_id: number;
71
- signal: AbortSignal;
72
- }
73
50
  export interface BaseWriteCheckpointAPI {
74
51
  readonly writeCheckpointMode: WriteCheckpointMode;
75
52
  setWriteCheckpointMode(mode: WriteCheckpointMode): void;
@@ -81,7 +58,6 @@ export interface BaseWriteCheckpointAPI {
81
58
  * sync rules id.
82
59
  */
83
60
  export interface SyncStorageWriteCheckpointAPI extends BaseWriteCheckpointAPI {
84
- batchCreateCustomWriteCheckpoints(checkpoints: BatchedCustomWriteCheckpointOptions[]): Promise<void>;
85
61
  lastWriteCheckpoint(filters: SyncStorageLastWriteCheckpointFilters): Promise<bigint | null>;
86
62
  }
87
63
  /**
@@ -89,8 +65,6 @@ export interface SyncStorageWriteCheckpointAPI extends BaseWriteCheckpointAPI {
89
65
  * sync rules identifiers for custom write checkpoints.
90
66
  */
91
67
  export interface WriteCheckpointAPI extends BaseWriteCheckpointAPI {
92
- batchCreateCustomWriteCheckpoints(checkpoints: CustomWriteCheckpointOptions[]): Promise<void>;
93
68
  lastWriteCheckpoint(filters: LastWriteCheckpointFilters): Promise<bigint | null>;
94
- watchUserWriteCheckpoint(options: WatchUserWriteCheckpointOptions): AsyncIterable<WriteCheckpointResult>;
95
69
  }
96
70
  export declare const DEFAULT_WRITE_CHECKPOINT_MODE = WriteCheckpointMode.MANAGED;
@@ -1 +1 @@
1
- {"version":3,"file":"WriteCheckpointAPI.js","sourceRoot":"","sources":["../../src/storage/WriteCheckpointAPI.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,mBAYX;AAZD,WAAY,mBAAmB;IAC7B;;;OAGG;IACH,wCAAiB,CAAA;IACjB;;;;OAIG;IACH,0CAAmB,CAAA;AACrB,CAAC,EAZW,mBAAmB,KAAnB,mBAAmB,QAY9B;AAkGD,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAC,OAAO,CAAC"}
1
+ {"version":3,"file":"WriteCheckpointAPI.js","sourceRoot":"","sources":["../../src/storage/WriteCheckpointAPI.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,mBAYX;AAZD,WAAY,mBAAmB;IAC7B;;;OAGG;IACH,wCAAiB,CAAA;IACjB;;;;OAIG;IACH,0CAAmB,CAAA;AACrB,CAAC,EAZW,mBAAmB,KAAnB,mBAAmB,QAY9B;AAoED,MAAM,CAAC,MAAM,6BAA6B,GAAG,mBAAmB,CAAC,OAAO,CAAC"}
@@ -4,7 +4,10 @@ import * as bson from 'bson';
4
4
  */
5
5
  export const BSON_DESERIALIZE_INTERNAL_OPTIONS = {
6
6
  // use bigint instead of Long
7
- useBigInt64: true
7
+ useBigInt64: true,
8
+ // We cannot use promoteBuffers: true, since that also converst UUID to Buffer
9
+ // Instead, we need to handle bson.Binary when reading data
10
+ promoteBuffers: false
8
11
  };
9
12
  /**
10
13
  * Use for data from external sources, which could contain arbitrary fields.
@@ -1 +1 @@
1
- {"version":3,"file":"bson.js","sourceRoot":"","sources":["../../src/storage/bson.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"bson.js","sourceRoot":"","sources":["../../src/storage/bson.ts"],"names":[],"mappings":"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"}
@@ -32,6 +32,6 @@ export declare class BroadcastIterable<T> implements AsyncIterable<T> {
32
32
  private loop;
33
33
  private removeSink;
34
34
  private addSink;
35
- [Symbol.asyncIterator](signal?: AbortSignal): AsyncIterator<T>;
35
+ [Symbol.asyncIterator](signal?: AbortSignal): AsyncIterableIterator<T>;
36
36
  get active(): boolean;
37
37
  }
@@ -1,4 +1,3 @@
1
1
  export * from './merge.js';
2
- export * from './Demultiplexer.js';
3
2
  export * from './LastValueSink.js';
4
3
  export * from './BroadcastIterable.js';
@@ -1,5 +1,4 @@
1
1
  export * from './merge.js';
2
- export * from './Demultiplexer.js';
3
2
  export * from './LastValueSink.js';
4
3
  export * from './BroadcastIterable.js';
5
4
  //# sourceMappingURL=streams-index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"streams-index.js","sourceRoot":"","sources":["../../src/streams/streams-index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"streams-index.js","sourceRoot":"","sources":["../../src/streams/streams-index.ts"],"names":[],"mappings":"AAAA,cAAc,YAAY,CAAC;AAC3B,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC"}
@@ -36,6 +36,12 @@ export class ServiceContextContainer {
36
36
  this.storageEngine = new storage.StorageEngine({
37
37
  configuration
38
38
  });
39
+ this.storageEngine.registerListener({
40
+ storageFatalError: (error) => {
41
+ // Propagate the error to the lifecycle engine
42
+ this.lifeCycleEngine.stopWithError(error);
43
+ }
44
+ });
39
45
  this.lifeCycleEngine.withLifecycle(this.storageEngine, {
40
46
  start: (storageEngine) => storageEngine.start(),
41
47
  stop: (storageEngine) => storageEngine.shutDown()
@@ -1 +1 @@
1
- {"version":3,"file":"ServiceContext.js","sourceRoot":"","sources":["../../src/system/ServiceContext.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ServiceContext.js","sourceRoot":"","sources":["../../src/system/ServiceContext.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
8
- "version": "1.12.1",
8
+ "version": "1.13.0",
9
9
  "main": "dist/index.js",
10
10
  "license": "FSL-1.1-Apache-2.0",
11
11
  "type": "module",
@@ -32,11 +32,11 @@
32
32
  "uuid": "^11.1.0",
33
33
  "winston": "^3.13.0",
34
34
  "yaml": "^2.3.2",
35
- "@powersync/lib-services-framework": "0.6.0",
35
+ "@powersync/lib-services-framework": "0.7.0",
36
36
  "@powersync/service-jsonbig": "0.17.10",
37
- "@powersync/service-rsocket-router": "0.1.0",
37
+ "@powersync/service-rsocket-router": "0.1.1",
38
38
  "@powersync/service-sync-rules": "0.27.0",
39
- "@powersync/service-types": "0.11.0"
39
+ "@powersync/service-types": "0.12.0"
40
40
  },
41
41
  "devDependencies": {
42
42
  "@types/async": "^3.2.24",
@@ -47,7 +47,7 @@ export interface RouteAPI {
47
47
  * @returns The replication lag: that is the amount of data which has not been
48
48
  * replicated yet, in bytes.
49
49
  */
50
- getReplicationLag(options: ReplicationLagOptions): Promise<number | undefined>;
50
+ getReplicationLagBytes(options: ReplicationLagOptions): Promise<number | undefined>;
51
51
 
52
52
  /**
53
53
  * Get the current LSN or equivalent replication HEAD position identifier.
@@ -78,7 +78,7 @@ export async function getSyncRulesStatus(
78
78
 
79
79
  if (systemStorage) {
80
80
  try {
81
- replication_lag_bytes = await apiHandler.getReplicationLag({
81
+ replication_lag_bytes = await apiHandler.getReplicationLagBytes({
82
82
  bucketStorage: systemStorage
83
83
  });
84
84
  } catch (e) {
@@ -36,8 +36,8 @@ export function generateEntryProgram(startHandlers?: Record<utils.ServiceRunner,
36
36
  try {
37
37
  await entryProgram.parseAsync();
38
38
  } catch (e) {
39
- logger.error('Fatal error', e);
40
- process.exit(1);
39
+ logger.error('Fatal startup error - exiting with code 150.', e);
40
+ process.exit(150);
41
41
  }
42
42
  }
43
43
  };
package/src/index.ts CHANGED
@@ -41,3 +41,5 @@ export * as utils from './util/util-index.js';
41
41
 
42
42
  export * from './streams/streams-index.js';
43
43
  export * as streams from './streams/streams-index.js';
44
+
45
+ export * as bson from 'bson';
@@ -1,11 +1,11 @@
1
1
  import { Meter, ValueType } from '@opentelemetry/api';
2
2
  import {
3
3
  Counter,
4
- ObservableGauge,
5
- UpDownCounter,
6
4
  MetricMetadata,
7
5
  MetricsFactory,
8
- Precision
6
+ ObservableGauge,
7
+ Precision,
8
+ UpDownCounter
9
9
  } from '../metrics-interfaces.js';
10
10
 
11
11
  export class OpenTelemetryMetricsFactory implements MetricsFactory {
@@ -78,4 +78,9 @@ export abstract class AbstractReplicationJob {
78
78
  public get isStopped(): boolean {
79
79
  return this.abortController.signal.aborted;
80
80
  }
81
+
82
+ /**
83
+ * Get replication lag for this job in ms.
84
+ */
85
+ abstract getReplicationLagMillis(): Promise<number | undefined>;
81
86
  }
@@ -8,6 +8,7 @@ import { AbstractReplicationJob } from './AbstractReplicationJob.js';
8
8
  import { ErrorRateLimiter } from './ErrorRateLimiter.js';
9
9
  import { ConnectionTestResult } from './ReplicationModule.js';
10
10
  import { MetricsEngine } from '../metrics/MetricsEngine.js';
11
+ import { ReplicationMetric } from '@powersync/service-types';
11
12
 
12
13
  // 5 minutes
13
14
  const PING_INTERVAL = 1_000_000_000n * 300n;
@@ -42,11 +43,16 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
42
43
  * @private
43
44
  */
44
45
  private replicationJobs = new Map<number, T>();
45
- private stopped = false;
46
+ /**
47
+ * Used for replication lag computation.
48
+ */
49
+ private activeReplicationJob: T | undefined = undefined;
46
50
 
47
51
  // First ping is only after 5 minutes, not when starting
48
52
  private lastPing = hrtime.bigint();
49
53
 
54
+ private abortController: AbortController | undefined;
55
+
50
56
  protected constructor(private options: AbstractReplicatorOptions) {
51
57
  this.logger = logger.child({ name: `Replicator:${options.id}` });
52
58
  }
@@ -79,7 +85,12 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
79
85
  return this.options.metricsEngine;
80
86
  }
81
87
 
88
+ protected get stopped() {
89
+ return this.abortController?.signal.aborted;
90
+ }
91
+
82
92
  public async start(): Promise<void> {
93
+ this.abortController = new AbortController();
83
94
  this.runLoop().catch((e) => {
84
95
  this.logger.error('Data source fatal replication error', e);
85
96
  container.reporter.captureException(e);
@@ -87,10 +98,21 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
87
98
  process.exit(1);
88
99
  }, 1000);
89
100
  });
101
+ this.metrics.getObservableGauge(ReplicationMetric.REPLICATION_LAG_SECONDS).setValueProvider(async () => {
102
+ const lag = await this.getReplicationLagMillis().catch((e) => {
103
+ this.logger.error('Failed to get replication lag', e);
104
+ return undefined;
105
+ });
106
+ if (lag == null) {
107
+ return undefined;
108
+ }
109
+ // ms to seconds
110
+ return Math.round(lag / 1000);
111
+ });
90
112
  }
91
113
 
92
114
  public async stop(): Promise<void> {
93
- this.stopped = true;
115
+ this.abortController?.abort();
94
116
  let promises: Promise<void>[] = [];
95
117
  for (const job of this.replicationJobs.values()) {
96
118
  promises.push(job.stop());
@@ -161,8 +183,12 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
161
183
  const existingJobs = new Map<number, T>(this.replicationJobs.entries());
162
184
  const replicatingSyncRules = await this.storage.getReplicatingSyncRules();
163
185
  const newJobs = new Map<number, T>();
186
+ let activeJob: T | undefined = undefined;
164
187
  for (let syncRules of replicatingSyncRules) {
165
188
  const existingJob = existingJobs.get(syncRules.id);
189
+ if (syncRules.active && activeJob == null) {
190
+ activeJob = existingJob;
191
+ }
166
192
  if (existingJob && !existingJob.isStopped) {
167
193
  // No change
168
194
  existingJobs.delete(syncRules.id);
@@ -188,6 +214,9 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
188
214
 
189
215
  newJobs.set(syncRules.id, newJob);
190
216
  newJob.start();
217
+ if (syncRules.active) {
218
+ activeJob = newJob;
219
+ }
191
220
  } catch (e) {
192
221
  // Could be a sync rules parse error,
193
222
  // for example from stricter validation that was added.
@@ -199,6 +228,7 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
199
228
  }
200
229
 
201
230
  this.replicationJobs = newJobs;
231
+ this.activeReplicationJob = activeJob;
202
232
 
203
233
  // Stop any orphaned jobs that no longer have sync rules.
204
234
  // Termination happens below
@@ -216,6 +246,7 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
216
246
  const stopped = await this.storage.getStoppedSyncRules();
217
247
  for (let syncRules of stopped) {
218
248
  try {
249
+ // TODO: Do this in the "background", allowing the periodic refresh to continue
219
250
  const syncRuleStorage = this.storage.getInstance(syncRules, { skipLifecycleHooks: true });
220
251
  await this.terminateSyncRules(syncRuleStorage);
221
252
  } catch (e) {
@@ -231,9 +262,31 @@ export abstract class AbstractReplicator<T extends AbstractReplicationJob = Abst
231
262
  protected async terminateSyncRules(syncRuleStorage: storage.SyncRulesBucketStorage) {
232
263
  this.logger.info(`Terminating sync rules: ${syncRuleStorage.group_id}...`);
233
264
  await this.cleanUp(syncRuleStorage);
234
- await syncRuleStorage.terminate();
265
+ await syncRuleStorage.terminate({ signal: this.abortController?.signal, clearStorage: true });
235
266
  this.logger.info(`Successfully terminated sync rules: ${syncRuleStorage.group_id}`);
236
267
  }
237
268
 
238
269
  abstract testConnection(): Promise<ConnectionTestResult>;
270
+
271
+ /**
272
+ * Measure replication lag in milliseconds.
273
+ *
274
+ * In general, this is the difference between now() and the time the oldest record, that we haven't committed yet,
275
+ * has been written (committed) to the source database.
276
+ *
277
+ * This is roughly a measure of the _average_ amount of time we're behind.
278
+ * If we get a new change as soon as each previous one has finished processing, and each change takes 1000ms
279
+ * to process, the average replication lag will be 500ms, not 1000ms.
280
+ *
281
+ * 1. When we are actively replicating, this is the difference between now and when the time the change was
282
+ * written to the source database.
283
+ * 2. When the replication stream is idle, this is either 0, or the delay for keepalive messages to make it to us.
284
+ * 3. When the active replication stream is an error state, this is the time since the last successful commit.
285
+ * 4. If there is no active replication stream, this is undefined.
286
+ *
287
+ * "processing" replication streams are not taken into account for this metric.
288
+ */
289
+ async getReplicationLagMillis(): Promise<number | undefined> {
290
+ return this.activeReplicationJob?.getReplicationLagMillis();
291
+ }
239
292
  }
@@ -0,0 +1,25 @@
1
+ import { SourceTable } from '../storage/SourceTable.js';
2
+
3
+ export class RelationCache<T> {
4
+ private cache = new Map<string | number, SourceTable>();
5
+ private idFunction: (item: T | SourceTable) => string | number;
6
+
7
+ constructor(idFunction: (item: T | SourceTable) => string | number) {
8
+ this.idFunction = idFunction;
9
+ }
10
+
11
+ update(table: SourceTable) {
12
+ const id = this.idFunction(table);
13
+ this.cache.set(id, table);
14
+ }
15
+
16
+ get(source: T | SourceTable): SourceTable | undefined {
17
+ const id = this.idFunction(source);
18
+ return this.cache.get(id);
19
+ }
20
+
21
+ delete(source: T | SourceTable): boolean {
22
+ const id = this.idFunction(source);
23
+ return this.cache.delete(id);
24
+ }
25
+ }
@@ -4,3 +4,4 @@ export * from './ErrorRateLimiter.js';
4
4
  export * from './ReplicationEngine.js';
5
5
  export * from './ReplicationModule.js';
6
6
  export * from './replication-metrics.js';
7
+ export * from './RelationCache.js';
@@ -26,6 +26,11 @@ export function createCoreReplicationMetrics(engine: MetricsEngine): void {
26
26
  name: ReplicationMetric.CHUNKS_REPLICATED,
27
27
  description: 'Total number of replication chunks'
28
28
  });
29
+
30
+ engine.createObservableGauge({
31
+ name: ReplicationMetric.REPLICATION_LAG_SECONDS,
32
+ description: 'Replication lag between the source database and PowerSync instance'
33
+ });
29
34
  }
30
35
 
31
36
  /**
@@ -42,4 +47,6 @@ export function initializeCoreReplicationMetrics(engine: MetricsEngine): void {
42
47
  rows_replicated_total.add(0);
43
48
  transactions_replicated_total.add(0);
44
49
  chunks_replicated_total.add(0);
50
+ // REPLICATION_LAG_SECONDS is not explicitly initialized - the value remains "unknown" until the first value
51
+ // is reported.
45
52
  }
@@ -168,6 +168,8 @@ export const validate = routeDefinition({
168
168
  // Dummy values
169
169
  id: 0,
170
170
  slot_name: '',
171
+ active: false,
172
+ last_checkpoint_lsn: '',
171
173
 
172
174
  parsed() {
173
175
  return {