@powersync/lib-services-framework 0.0.0-dev-20241111122558 → 0.0.0-dev-20241219091224

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.
@@ -1,14 +1,17 @@
1
1
  import { ErrorReporter } from './alerts/definitions.js';
2
+ import { MigrationManager } from './migrations/MigrationManager.js';
2
3
  import { ProbeModule, TerminationHandler } from './signals/signals-index.js';
3
4
  export declare enum ContainerImplementation {
4
5
  REPORTER = "reporter",
5
6
  PROBES = "probes",
6
- TERMINATION_HANDLER = "termination-handler"
7
+ TERMINATION_HANDLER = "termination-handler",
8
+ MIGRATION_MANAGER = "migration-manager"
7
9
  }
8
10
  export type ContainerImplementationTypes = {
9
11
  [ContainerImplementation.REPORTER]: ErrorReporter;
10
12
  [ContainerImplementation.PROBES]: ProbeModule;
11
13
  [ContainerImplementation.TERMINATION_HANDLER]: TerminationHandler;
14
+ [ContainerImplementation.MIGRATION_MANAGER]: MigrationManager;
12
15
  };
13
16
  export type RegisterDefaultsOptions = {
14
17
  skip?: ContainerImplementation[];
@@ -52,6 +55,10 @@ export declare class Container {
52
55
  handleTerminationSignalLast: (handler: import("./signals/termination-handler.js").Handler) => void;
53
56
  gracefully: <T>(exec: () => T | Promise<T>, handler: (component: T, signal: import("./signals/termination-handler.js").Signal) => Promise<void> | void) => Promise<T>;
54
57
  };
58
+ /**
59
+ * Manager for system migrations.
60
+ */
61
+ get migrationManager(): MigrationManager<import("./index.js").MigrationAgentGenerics>;
55
62
  constructor();
56
63
  /**
57
64
  * Gets an implementation given an identifier.
package/dist/container.js CHANGED
@@ -1,16 +1,19 @@
1
1
  import _ from 'lodash';
2
2
  import { NoOpReporter } from './alerts/no-op-reporter.js';
3
+ import { MigrationManager } from './migrations/MigrationManager.js';
3
4
  import { createFSProbe, createTerminationHandler } from './signals/signals-index.js';
4
5
  export var ContainerImplementation;
5
6
  (function (ContainerImplementation) {
6
7
  ContainerImplementation["REPORTER"] = "reporter";
7
8
  ContainerImplementation["PROBES"] = "probes";
8
9
  ContainerImplementation["TERMINATION_HANDLER"] = "termination-handler";
10
+ ContainerImplementation["MIGRATION_MANAGER"] = "migration-manager";
9
11
  })(ContainerImplementation || (ContainerImplementation = {}));
10
12
  const DEFAULT_GENERATORS = {
11
13
  [ContainerImplementation.REPORTER]: () => NoOpReporter,
12
14
  [ContainerImplementation.PROBES]: () => createFSProbe(),
13
- [ContainerImplementation.TERMINATION_HANDLER]: () => createTerminationHandler()
15
+ [ContainerImplementation.TERMINATION_HANDLER]: () => createTerminationHandler(),
16
+ [ContainerImplementation.MIGRATION_MANAGER]: () => new MigrationManager()
14
17
  };
15
18
  /**
16
19
  * A container which provides means for registering and getting various
@@ -35,6 +38,12 @@ export class Container {
35
38
  get terminationHandler() {
36
39
  return this.getImplementation(ContainerImplementation.TERMINATION_HANDLER);
37
40
  }
41
+ /**
42
+ * Manager for system migrations.
43
+ */
44
+ get migrationManager() {
45
+ return this.getImplementation(ContainerImplementation.MIGRATION_MANAGER);
46
+ }
38
47
  constructor() {
39
48
  this.implementations = new Map();
40
49
  }
@@ -1 +1 @@
1
- {"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;AAEvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAmC,aAAa,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtH,MAAM,CAAN,IAAY,uBAIX;AAJD,WAAY,uBAAuB;IACjC,gDAAqB,CAAA;IACrB,4CAAiB,CAAA;IACjB,sEAA2C,CAAA;AAC7C,CAAC,EAJW,uBAAuB,KAAvB,uBAAuB,QAIlC;AAgCD,MAAM,kBAAkB,GAA6C;IACnE,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,YAAY;IACtD,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;IACvD,CAAC,uBAAuB,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,CAAC,wBAAwB,EAAE;CAChF,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,SAAS;IAGpB;;OAEG;IACH,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;IAC7E,CAAC;IAED;QACE,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAE,CAAC;IACnC,CAAC;IAWD,iBAAiB,CAAI,UAAgC;QACnD,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAWD,WAAW,CAAI,UAAgC;QAC7C,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,OAAiC;QAChD,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACzF,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,QAAQ,CAAI,UAAgC,EAAE,cAAiB;QAC7D,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACvD,CAAC;CACF;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"container.js","sourceRoot":"","sources":["../src/container.ts"],"names":[],"mappings":"AAAA,OAAO,CAAC,MAAM,QAAQ,CAAC;AAEvB,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAmC,aAAa,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAEtH,MAAM,CAAN,IAAY,uBAKX;AALD,WAAY,uBAAuB;IACjC,gDAAqB,CAAA;IACrB,4CAAiB,CAAA;IACjB,sEAA2C,CAAA;IAC3C,kEAAuC,CAAA;AACzC,CAAC,EALW,uBAAuB,KAAvB,uBAAuB,QAKlC;AAiCD,MAAM,kBAAkB,GAA6C;IACnE,CAAC,uBAAuB,CAAC,QAAQ,CAAC,EAAE,GAAG,EAAE,CAAC,YAAY;IACtD,CAAC,uBAAuB,CAAC,MAAM,CAAC,EAAE,GAAG,EAAE,CAAC,aAAa,EAAE;IACvD,CAAC,uBAAuB,CAAC,mBAAmB,CAAC,EAAE,GAAG,EAAE,CAAC,wBAAwB,EAAE;IAC/E,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,gBAAgB,EAAE;CAC1E,CAAC;AAEF;;;GAGG;AACH,MAAM,OAAO,SAAS;IAGpB;;OAEG;IACH,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,MAAM,CAAC,CAAC;IAChE,CAAC;IAED;;OAEG;IACH,IAAI,QAAQ;QACV,OAAO,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,QAAQ,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACH,IAAI,kBAAkB;QACpB,OAAO,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,mBAAmB,CAAC,CAAC;IAC7E,CAAC;IAED;;OAEG;IACH,IAAI,gBAAgB;QAClB,OAAO,IAAI,CAAC,iBAAiB,CAAC,uBAAuB,CAAC,iBAAiB,CAAC,CAAC;IAC3E,CAAC;IAED;QACE,IAAI,CAAC,eAAe,GAAG,IAAI,GAAG,EAAE,CAAC;IACnC,CAAC;IAWD,iBAAiB,CAAI,UAAgC;QACnD,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,IAAI,KAAK,CAAC,sBAAsB,MAAM,CAAC,UAAU,CAAC,2BAA2B,CAAC,CAAC;QACvF,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAWD,WAAW,CAAI,UAAgC;QAC7C,MAAM,cAAc,GAAG,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;QAC5D,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,cAAc,CAAC;IACxB,CAAC;IAED;;OAEG;IACH,gBAAgB,CAAC,OAAiC;QAChD,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,uBAAuB,CAAC,EAAE,OAAO,EAAE,IAAI,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE;YACzF,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;YAC3C,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QACnC,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,QAAQ,CAAI,UAAgC,EAAE,cAAiB;QAC7D,IAAI,CAAC,eAAe,CAAC,GAAG,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;IACvD,CAAC;CACF;AAED,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,SAAS,EAAE,CAAC"}
package/dist/index.d.ts CHANGED
@@ -6,6 +6,10 @@ export * from './container.js';
6
6
  export * from './errors/errors-index.js';
7
7
  export * as errors from './errors/errors-index.js';
8
8
  export * from './logger/Logger.js';
9
+ export * from './locks/locks-index.js';
10
+ export * as locks from './locks/locks-index.js';
11
+ export * from './migrations/migrations-index.js';
12
+ export * as migrations from './migrations/migrations-index.js';
9
13
  export * from './schema/schema-index.js';
10
14
  export * as schema from './schema/schema-index.js';
11
15
  export * from './signals/signals-index.js';
package/dist/index.js CHANGED
@@ -6,6 +6,10 @@ export * from './container.js';
6
6
  export * from './errors/errors-index.js';
7
7
  export * as errors from './errors/errors-index.js';
8
8
  export * from './logger/Logger.js';
9
+ export * from './locks/locks-index.js';
10
+ export * as locks from './locks/locks-index.js';
11
+ export * from './migrations/migrations-index.js';
12
+ export * as migrations from './migrations/migrations-index.js';
9
13
  export * from './schema/schema-index.js';
10
14
  export * as schema from './schema/schema-index.js';
11
15
  export * from './signals/signals-index.js';
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,wBAAwB,CAAC;AACvC,OAAO,KAAK,MAAM,MAAM,wBAAwB,CAAC;AAEjD,cAAc,gBAAgB,CAAC;AAE/B,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,oBAAoB,CAAC;AAEnC,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,4BAA4B,CAAC;AAC3C,OAAO,KAAK,OAAO,MAAM,4BAA4B,CAAC;AAEtD,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,8BAA8B,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,wBAAwB,CAAC;AACvC,OAAO,KAAK,KAAK,MAAM,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,wBAAwB,CAAC;AACvC,OAAO,KAAK,MAAM,MAAM,wBAAwB,CAAC;AAEjD,cAAc,gBAAgB,CAAC;AAE/B,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,oBAAoB,CAAC;AAEnC,cAAc,wBAAwB,CAAC;AACvC,OAAO,KAAK,KAAK,MAAM,wBAAwB,CAAC;AAEhD,cAAc,kCAAkC,CAAC;AACjD,OAAO,KAAK,UAAU,MAAM,kCAAkC,CAAC;AAE/D,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,4BAA4B,CAAC;AAC3C,OAAO,KAAK,OAAO,MAAM,4BAA4B,CAAC;AAEtD,cAAc,0BAA0B,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,8BAA8B,CAAC;AAC7C,OAAO,KAAK,MAAM,MAAM,0BAA0B,CAAC;AAEnD,cAAc,wBAAwB,CAAC;AACvC,OAAO,KAAK,KAAK,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,16 @@
1
+ export declare class LockActiveError extends Error {
2
+ constructor();
3
+ }
4
+ export type LockAcquireOptions = {
5
+ /**
6
+ * Optionally retry and wait for the lock to be acquired
7
+ */
8
+ max_wait_ms?: number;
9
+ };
10
+ export type LockManager = {
11
+ init?: () => Promise<void>;
12
+ acquire: (options?: LockAcquireOptions) => Promise<string | null>;
13
+ refresh: (lock_id: string) => Promise<void>;
14
+ release: (lock_id: string) => Promise<void>;
15
+ lock: (handler: (refresh: () => Promise<void>) => Promise<void>) => Promise<void>;
16
+ };
@@ -0,0 +1,7 @@
1
+ export class LockActiveError extends Error {
2
+ constructor() {
3
+ super('Lock is already active');
4
+ this.name = this.constructor.name;
5
+ }
6
+ }
7
+ //# sourceMappingURL=LockManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LockManager.js","sourceRoot":"","sources":["../../src/locks/LockManager.ts"],"names":[],"mappings":"AAAA,MAAM,OAAO,eAAgB,SAAQ,KAAK;IACxC;QACE,KAAK,CAAC,wBAAwB,CAAC,CAAC;QAChC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC;IACpC,CAAC;CACF"}
@@ -0,0 +1 @@
1
+ export * from './LockManager.js';
@@ -0,0 +1,2 @@
1
+ export * from './LockManager.js';
2
+ //# sourceMappingURL=locks-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locks-index.js","sourceRoot":"","sources":["../../src/locks/locks-index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,34 @@
1
+ import { LockManager } from '../locks/LockManager.js';
2
+ import * as defs from './migration-definitions.js';
3
+ export type MigrationParams<Generics extends MigrationAgentGenerics = MigrationAgentGenerics> = {
4
+ count?: number;
5
+ direction: defs.Direction;
6
+ migrationContext?: Generics['MIGRATION_CONTEXT'];
7
+ };
8
+ type WriteLogsParams = {
9
+ state?: defs.MigrationState;
10
+ log_stream: Iterable<defs.ExecutedMigration> | AsyncIterable<defs.ExecutedMigration>;
11
+ };
12
+ export type MigrationAgentGenerics = {
13
+ MIGRATION_CONTEXT?: {};
14
+ };
15
+ export type RunMigrationParams<Generics extends MigrationAgentGenerics = MigrationAgentGenerics> = MigrationParams & {
16
+ migrations: defs.Migration<Generics['MIGRATION_CONTEXT']>[];
17
+ maxLockWaitMs?: number;
18
+ };
19
+ type ExecuteParams = RunMigrationParams & {
20
+ state?: defs.MigrationState;
21
+ };
22
+ export declare const DEFAULT_MAX_LOCK_WAIT_MS: number;
23
+ export declare abstract class AbstractMigrationAgent<Generics extends MigrationAgentGenerics = MigrationAgentGenerics> implements AsyncDisposable {
24
+ abstract get store(): defs.MigrationStore;
25
+ abstract get locks(): LockManager;
26
+ abstract loadInternalMigrations(): Promise<defs.Migration<Generics['MIGRATION_CONTEXT']>[]>;
27
+ abstract [Symbol.asyncDispose](): Promise<void>;
28
+ protected init(): Promise<void>;
29
+ run(params: RunMigrationParams): Promise<void>;
30
+ protected execute(params: ExecuteParams): AsyncGenerator<defs.ExecutedMigration>;
31
+ resetStore(): Promise<void>;
32
+ protected writeLogsToStore: (params: WriteLogsParams) => Promise<void>;
33
+ }
34
+ export {};
@@ -0,0 +1,118 @@
1
+ import { logger } from '../logger/Logger.js';
2
+ import * as defs from './migration-definitions.js';
3
+ export const DEFAULT_MAX_LOCK_WAIT_MS = 3 * 60 * 1000; // 3 minutes
4
+ export class AbstractMigrationAgent {
5
+ constructor() {
6
+ this.writeLogsToStore = async (params) => {
7
+ const log = [...(params.state?.log || [])];
8
+ for await (const migration of params.log_stream) {
9
+ log.push(migration);
10
+ await this.store.save({
11
+ last_run: migration.name,
12
+ log: log
13
+ });
14
+ }
15
+ };
16
+ }
17
+ async init() {
18
+ await this.locks.init?.();
19
+ await this.store.init?.();
20
+ }
21
+ async run(params) {
22
+ await this.init();
23
+ const { direction, migrations, migrationContext } = params;
24
+ // Only one process should execute this at a time.
25
+ logger.info('Acquiring lock for migrations');
26
+ const lockId = await this.locks.acquire({ max_wait_ms: params.maxLockWaitMs ?? DEFAULT_MAX_LOCK_WAIT_MS });
27
+ if (!lockId) {
28
+ throw new Error('Could not acquire lock');
29
+ }
30
+ let isReleased = false;
31
+ const releaseLock = async () => {
32
+ if (isReleased) {
33
+ return;
34
+ }
35
+ await this.locks.release(lockId);
36
+ isReleased = true;
37
+ };
38
+ // For the case where the migration is terminated
39
+ process.addListener('beforeExit', releaseLock);
40
+ try {
41
+ const state = await this.store.load();
42
+ logger.info('Running migrations');
43
+ const logStream = this.execute({
44
+ direction,
45
+ migrations,
46
+ state,
47
+ migrationContext
48
+ });
49
+ await this.writeLogsToStore({
50
+ log_stream: logStream,
51
+ state
52
+ });
53
+ }
54
+ finally {
55
+ logger.info('Releasing migration lock');
56
+ await releaseLock();
57
+ process.removeListener('beforeExit', releaseLock);
58
+ logger.info('Done with migrations');
59
+ }
60
+ }
61
+ async *execute(params) {
62
+ const internalMigrations = await this.loadInternalMigrations();
63
+ let migrations = [...internalMigrations, ...params.migrations];
64
+ if (params.direction === defs.Direction.Down) {
65
+ migrations.reverse();
66
+ }
67
+ let index = 0;
68
+ if (params.state) {
69
+ // Find the index of the last run
70
+ index = migrations.findIndex((migration) => {
71
+ return migration.name === params.state.last_run;
72
+ });
73
+ if (index === -1) {
74
+ throw new Error(`The last run migration ${params.state?.last_run} was not found in the given set of migrations`);
75
+ }
76
+ // If we are migrating down then we want to include the last run migration, otherwise we want to start at the next one
77
+ if (params.direction === defs.Direction.Up) {
78
+ index += 1;
79
+ }
80
+ }
81
+ migrations = migrations.slice(index);
82
+ let i = 0;
83
+ const { migrationContext } = params;
84
+ for (const migration of migrations) {
85
+ if (params.count && params.count === i) {
86
+ return;
87
+ }
88
+ logger.info(`Executing ${migration.name} (${params.direction})`);
89
+ try {
90
+ switch (params.direction) {
91
+ case defs.Direction.Up: {
92
+ await migration.up(migrationContext);
93
+ break;
94
+ }
95
+ case defs.Direction.Down: {
96
+ await migration.down(migrationContext);
97
+ break;
98
+ }
99
+ }
100
+ logger.debug(`Success`);
101
+ }
102
+ catch (err) {
103
+ logger.error(`Failed`, err);
104
+ process.exit(1);
105
+ }
106
+ yield {
107
+ name: migration.name,
108
+ direction: params.direction,
109
+ timestamp: new Date()
110
+ };
111
+ i++;
112
+ }
113
+ }
114
+ resetStore() {
115
+ return this.store.clear();
116
+ }
117
+ }
118
+ //# sourceMappingURL=AbstractMigrationAgent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AbstractMigrationAgent.js","sourceRoot":"","sources":["../../src/migrations/AbstractMigrationAgent.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { AbstractMigrationAgent, MigrationAgentGenerics, MigrationParams } from './AbstractMigrationAgent.js';
2
+ import * as defs from './migration-definitions.js';
3
+ export declare class MigrationManager<Generics extends MigrationAgentGenerics = MigrationAgentGenerics> implements AsyncDisposable {
4
+ private migrations;
5
+ private _agent;
6
+ constructor();
7
+ registerMigrationAgent(agent: AbstractMigrationAgent<Generics>): void;
8
+ registerMigrations(migrations: defs.Migration<Generics['MIGRATION_CONTEXT']>[]): void;
9
+ migrate(params: MigrationParams<Generics>): Promise<void>;
10
+ [Symbol.asyncDispose](): Promise<void | undefined>;
11
+ }
@@ -0,0 +1,28 @@
1
+ export class MigrationManager {
2
+ constructor() {
3
+ this.migrations = [];
4
+ this._agent = null;
5
+ }
6
+ registerMigrationAgent(agent) {
7
+ if (this._agent) {
8
+ throw new Error(`A migration agent has already been registered. Only a single agent is supported.`);
9
+ }
10
+ this._agent = agent;
11
+ }
12
+ registerMigrations(migrations) {
13
+ this.migrations.push(...migrations);
14
+ }
15
+ async migrate(params) {
16
+ if (!this._agent) {
17
+ throw new Error(`A migration agent has not been registered yet.`);
18
+ }
19
+ return this._agent.run({
20
+ ...params,
21
+ migrations: this.migrations
22
+ });
23
+ }
24
+ async [Symbol.asyncDispose]() {
25
+ return this._agent?.[Symbol.asyncDispose]();
26
+ }
27
+ }
28
+ //# sourceMappingURL=MigrationManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"MigrationManager.js","sourceRoot":"","sources":["../../src/migrations/MigrationManager.ts"],"names":[],"mappings":"AAGA,MAAM,OAAO,gBAAgB;IAM3B;QACE,IAAI,CAAC,UAAU,GAAG,EAAE,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;IACrB,CAAC;IAED,sBAAsB,CAAC,KAAuC;QAC5D,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,MAAM,IAAI,KAAK,CAAC,kFAAkF,CAAC,CAAC;QACtG,CAAC;QACD,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;IACtB,CAAC;IAED,kBAAkB,CAAC,UAA2D;QAC5E,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;IACtC,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,MAAiC;QAC7C,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;QACpE,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;YACrB,GAAG,MAAM;YACT,UAAU,EAAE,IAAI,CAAC,UAAU;SAC5B,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACzB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC,MAAM,CAAC,YAAY,CAAC,EAAE,CAAC;IAC9C,CAAC;CACF"}
@@ -0,0 +1,28 @@
1
+ export type MigrationFunction<Context extends {} | undefined = undefined> = (context: Context) => Promise<void>;
2
+ export type Migration<Context extends {} | undefined = undefined> = {
3
+ name: string;
4
+ up: MigrationFunction<Context>;
5
+ down: MigrationFunction<Context>;
6
+ };
7
+ export declare enum Direction {
8
+ Up = "up",
9
+ Down = "down"
10
+ }
11
+ export type ExecutedMigration = {
12
+ name: string;
13
+ direction: Direction;
14
+ timestamp: Date;
15
+ };
16
+ export type MigrationState = {
17
+ last_run: string;
18
+ log: ExecutedMigration[];
19
+ };
20
+ export type MigrationStore = {
21
+ init?: () => Promise<void>;
22
+ load: () => Promise<MigrationState | undefined>;
23
+ save: (state: MigrationState) => Promise<void>;
24
+ /**
25
+ * Resets the migration store state. Mostly used for tests.
26
+ */
27
+ clear: () => Promise<void>;
28
+ };
@@ -0,0 +1,6 @@
1
+ export var Direction;
2
+ (function (Direction) {
3
+ Direction["Up"] = "up";
4
+ Direction["Down"] = "down";
5
+ })(Direction || (Direction = {}));
6
+ //# sourceMappingURL=migration-definitions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migration-definitions.js","sourceRoot":"","sources":["../../src/migrations/migration-definitions.ts"],"names":[],"mappings":"AAQA,MAAM,CAAN,IAAY,SAGX;AAHD,WAAY,SAAS;IACnB,sBAAS,CAAA;IACT,0BAAa,CAAA;AACf,CAAC,EAHW,SAAS,KAAT,SAAS,QAGpB"}
@@ -0,0 +1,3 @@
1
+ export * from './AbstractMigrationAgent.js';
2
+ export * from './migration-definitions.js';
3
+ export * from './MigrationManager.js';
@@ -0,0 +1,4 @@
1
+ export * from './AbstractMigrationAgent.js';
2
+ export * from './migration-definitions.js';
3
+ export * from './MigrationManager.js';
4
+ //# sourceMappingURL=migrations-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrations-index.js","sourceRoot":"","sources":["../../src/migrations/migrations-index.ts"],"names":[],"mappings":"AAAA,cAAc,6BAA6B,CAAC;AAC5C,cAAc,4BAA4B,CAAC;AAC3C,cAAc,uBAAuB,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@powersync/lib-services-framework",
3
3
  "repository": "https://github.com/powersync-ja/powersync-service",
4
- "version": "0.0.0-dev-20241111122558",
4
+ "version": "0.0.0-dev-20241219091224",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
7
7
  "types": "dist/index.d.ts",
@@ -19,7 +19,7 @@
19
19
  "bson": "^6.6.0",
20
20
  "dotenv": "^16.4.5",
21
21
  "lodash": "^4.17.21",
22
- "ts-codec": "^1.2.2",
22
+ "ts-codec": "^1.3.0",
23
23
  "uuid": "^9.0.1",
24
24
  "winston": "^3.13.0",
25
25
  "zod": "^3.23.8"