@furvester/upstream-sync 1.1.0 → 2.0.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.
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2024 Furvester
3
+ Copyright (c) 2026 Furvester
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/dist/index.d.ts CHANGED
@@ -1,9 +1,8 @@
1
- /// <reference types="node" resolution-mode="require"/>
2
1
  import type { EntityClass, EntityManager, MikroORM } from "@mikro-orm/postgresql";
3
- import { type CollectionPageParams, type Selector } from "jsonapi-zod-query";
4
2
  import type { Logger } from "logforth";
5
3
  import { type ConnectionOptions } from "rabbitmq-client";
6
4
  import type { z } from "zod";
5
+ import { PaginationPageParams } from "@jsonapi-serde/client";
7
6
  export type SyncManagerConfig = {
8
7
  rabbitmq: ConnectionOptions;
9
8
  orm: MikroORM;
@@ -16,13 +15,13 @@ export type SyncableEntityClass = EntityClass<{
16
15
  id: string;
17
16
  upstreamVersion: number;
18
17
  }>;
19
- export type PreSyncResource = {
18
+ export type ResyncResource = {
20
19
  id: string;
21
20
  version: number;
22
21
  };
23
- export type PreSyncDocument<T extends PreSyncResource> = {
22
+ export type ResyncDocument<T extends ResyncResource> = {
24
23
  data: T[];
25
- pageParams: CollectionPageParams;
24
+ pageParams: PaginationPageParams<string>;
26
25
  };
27
26
  export type MessageEventHandler<T = unknown> = (em: EntityManager, data: T) => Promise<void> | void;
28
27
  export type MessageEvent<T extends z.ZodTypeAny> = {
@@ -30,19 +29,19 @@ export type MessageEvent<T extends z.ZodTypeAny> = {
30
29
  schema: T;
31
30
  handler: MessageEventHandler<ReturnType<T["parse"]>>;
32
31
  };
33
- export type PreSyncHandler<T> = (em: EntityManager, resource: T) => Promise<void> | void;
34
- export type PreSync<TSelector extends Selector<PreSyncDocument<PreSyncResource>>> = {
32
+ export type ResyncHandler<T> = (em: EntityManager, resource: T) => Promise<void> | void;
33
+ export type ResyncDeserializer<T extends ResyncResource> = (data: unknown) => ResyncDocument<T>;
34
+ export type Resync<TResource extends ResyncResource, TDeserializer extends ResyncDeserializer<TResource>> = {
35
35
  basePath: string;
36
36
  searchParams?: URLSearchParams;
37
- selector: TSelector;
37
+ deserializer: TDeserializer;
38
38
  entityClass: SyncableEntityClass;
39
- create: PreSyncHandler<ReturnType<TSelector>["data"][number]>;
40
- update: PreSyncHandler<ReturnType<TSelector>["data"][number]>;
39
+ upsert: ResyncHandler<TResource>;
41
40
  };
42
41
  export type UpstreamEntity = {
43
42
  routingKeyPrefix: string;
44
43
  events: MessageEvent<z.ZodTypeAny>[];
45
- preSync?: PreSync<Selector<PreSyncDocument<PreSyncResource>>>;
44
+ resync?: Resync<ResyncResource, ResyncDeserializer<ResyncResource>>;
46
45
  };
47
46
  export type UpstreamService = {
48
47
  serviceName: string;
@@ -50,7 +49,7 @@ export type UpstreamService = {
50
49
  disableWaitReady?: boolean;
51
50
  };
52
51
  export declare const createMessageEvent: <T extends z.ZodTypeAny>(event: MessageEvent<T>) => MessageEvent<T>;
53
- export declare const createPreSync: <T extends Selector<PreSyncDocument<PreSyncResource>>>(preSync: PreSync<T>) => PreSync<T>;
52
+ export declare const createResync: <TResource extends ResyncResource, TDeserializer extends ResyncDeserializer<TResource>>(preSync: Resync<TResource, TDeserializer>) => Resync<TResource, TDeserializer>;
54
53
  export declare const createUpstreamEntity: (entity: UpstreamEntity) => UpstreamEntity;
55
54
  export declare const createUpstreamService: (service: UpstreamService) => UpstreamService;
56
55
  export declare class SyncManager {
@@ -62,7 +61,7 @@ export declare class SyncManager {
62
61
  addUpstreamService(service: UpstreamService): this;
63
62
  run(): Promise<void>;
64
63
  private createConsumer;
65
- private runPreSync;
66
- private preSyncEntity;
64
+ private runResync;
65
+ private resyncEntity;
67
66
  private waitReady;
68
67
  }
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { Mutex } from "async-mutex";
2
- import { handleJsonApiError, injectPageParams, } from "jsonapi-zod-query";
3
2
  import { Connection, } from "rabbitmq-client";
3
+ import { handleJsonApiError, injectPageParams } from "@jsonapi-serde/client";
4
4
  export const createMessageEvent = (event) => event;
5
- export const createPreSync = (preSync) => preSync;
5
+ export const createResync = (preSync) => preSync;
6
6
  export const createUpstreamEntity = (entity) => entity;
7
7
  export const createUpstreamService = (service) => service;
8
8
  export class SyncManager {
@@ -34,7 +34,7 @@ export class SyncManager {
34
34
  };
35
35
  process.on("SIGINT", handleShutdown);
36
36
  process.on("SIGTERM", handleShutdown);
37
- await this.runPreSync();
37
+ await this.runResync();
38
38
  this.initialSyncMutex.release();
39
39
  }
40
40
  createConsumer() {
@@ -83,30 +83,26 @@ export class SyncManager {
83
83
  });
84
84
  });
85
85
  }
86
- async runPreSync() {
86
+ async runResync() {
87
87
  for (const service of this.upstreamServices) {
88
88
  if (!service.disableWaitReady) {
89
89
  await this.waitReady(`/${service.serviceName}/health`, service.serviceName);
90
90
  }
91
91
  for (const entity of service.entities) {
92
92
  await this.config.orm.em.fork().transactional(async (em) => {
93
- await this.preSyncEntity(em, service, entity);
93
+ await this.resyncEntity(em, service, entity);
94
94
  });
95
- this.config.logger.info(`Entity with routing key ${entity.routingKeyPrefix} pre-synced`);
95
+ this.config.logger.info(`Entity with routing key ${entity.routingKeyPrefix} resynced`);
96
96
  }
97
97
  }
98
98
  }
99
- async preSyncEntity(em, service, entity) {
100
- if (!entity.preSync) {
99
+ async resyncEntity(em, service, entity) {
100
+ if (!entity.resync) {
101
101
  return;
102
102
  }
103
- const versions = new Map((await em
104
- .createQueryBuilder(entity.preSync.entityClass)
105
- .select(["id", "upstreamVersion"])
106
- .execute("all", false)).map(({ id, upstream_version }) => [id, upstream_version]));
107
- const baseUrl = new URL(`/${service.serviceName}${entity.preSync.basePath}`, this.config.apiGatewayUrl);
108
- if (entity.preSync.searchParams) {
109
- baseUrl.search = entity.preSync.searchParams.toString();
103
+ const baseUrl = new URL(`/${service.serviceName}${entity.resync.basePath}`, this.config.apiGatewayUrl);
104
+ if (entity.resync.searchParams) {
105
+ baseUrl.search = entity.resync.searchParams.toString();
110
106
  }
111
107
  let url = baseUrl;
112
108
  do {
@@ -117,18 +113,9 @@ export class SyncManager {
117
113
  },
118
114
  });
119
115
  await handleJsonApiError(response);
120
- const document = entity.preSync.selector(await response.json());
116
+ const document = entity.resync.deserializer(await response.json());
121
117
  for (const resource of document.data) {
122
- const version = versions.get(resource.id);
123
- if (version === undefined) {
124
- await entity.preSync.create(em, resource);
125
- continue;
126
- }
127
- versions.delete(resource.id);
128
- if (version === resource.version) {
129
- continue;
130
- }
131
- await entity.preSync.update(em, resource);
118
+ await entity.resync.upsert(em, resource);
132
119
  }
133
120
  if (document.pageParams.next) {
134
121
  url = new URL(baseUrl);
@@ -137,11 +124,6 @@ export class SyncManager {
137
124
  }
138
125
  url = null;
139
126
  } while (url !== null);
140
- if (versions.size > 0) {
141
- await em.nativeDelete(entity.preSync.entityClass, {
142
- id: { $in: [...versions.keys()] },
143
- });
144
- }
145
127
  }
146
128
  async waitReady(path, serviceName) {
147
129
  const healthUrl = new URL(path, this.config.apiGatewayUrl);
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@furvester/upstream-sync",
3
- "version": "1.1.0",
3
+ "version": "2.0.0",
4
4
  "description": "Sync from upstream via RabbitMQ",
5
5
  "type": "module",
6
6
  "author": "Ben Scholzen 'DASPRiD'",
7
7
  "license": "MIT",
8
8
  "repository": {
9
9
  "type": "git",
10
- "url": "git+https://github.com/furvester/upstream-sync.git"
10
+ "url": "git+https://github.com/Furvester/upstream-sync.git"
11
11
  },
12
12
  "publishConfig": {
13
13
  "access": "public"
@@ -32,28 +32,27 @@
32
32
  "check": "biome check . --apply"
33
33
  },
34
34
  "devDependencies": {
35
- "@biomejs/biome": "1.7.1",
36
- "@commitlint/cli": "^19.3.0",
37
- "@commitlint/config-conventional": "^19.2.2",
38
- "@mikro-orm/postgresql": "^6.3.13",
39
- "@tsconfig/node20": "^20.1.4",
40
- "@types/node": "^20.12.7",
41
- "jsonapi-zod-query": "^2.1.1",
42
- "lefthook": "^1.6.10",
43
- "logforth": "^1.2.2",
44
- "rabbitmq-client": "^5.0.0",
45
- "typescript": "^5.4.5",
46
- "zod": "^3.23.4"
35
+ "@biomejs/biome": "2.3.14",
36
+ "@commitlint/cli": "^20.4.1",
37
+ "@commitlint/config-conventional": "^20.4.1",
38
+ "@mikro-orm/postgresql": "^6.6.6",
39
+ "@tsconfig/node24": "^24.0.4",
40
+ "@types/node": "^25.2.2",
41
+ "lefthook": "^2.1.0",
42
+ "logforth": "^1.3.0",
43
+ "rabbitmq-client": "^5.0.8",
44
+ "typescript": "^5.9.3",
45
+ "zod": "^4.3.6"
47
46
  },
48
47
  "peerDependencies": {
49
48
  "@mikro-orm/postgresql": "^6.3.13",
50
- "jsonapi-zod-query": "^2.1.1",
51
49
  "logforth": "^1.2.2",
52
50
  "rabbitmq-client": "^5.0.0",
53
51
  "zod": "^3.22.4"
54
52
  },
55
- "packageManager": "pnpm@9.9.0+sha512.60c18acd138bff695d339be6ad13f7e936eea6745660d4cc4a776d5247c540d0edee1a563695c183a66eb917ef88f2b4feb1fc25f32a7adcadc7aaf3438e99c1",
56
53
  "dependencies": {
54
+ "@jsonapi-serde/client": "^1.2.1",
57
55
  "async-mutex": "^0.5.0"
58
- }
56
+ },
57
+ "packageManager": "pnpm@10.29.1+sha512.48dae233635a645768a3028d19545cacc1688639eeb1f3734e42d6d6b971afbf22aa1ac9af52a173d9c3a20c15857cfa400f19994d79a2f626fcc73fccda9bbc"
59
58
  }