@mxpicture/tesla-superchargers-api 0.1.3 → 0.1.4

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 (53) hide show
  1. package/dist/api/ChargersApi.d.ts +1 -1
  2. package/dist/api/ChargersApi.d.ts.map +1 -1
  3. package/dist/api/ChargersApi.js +6 -17
  4. package/dist/api/ChargersApi.js.map +1 -1
  5. package/dist/api/InvoicesApi.d.ts +15 -0
  6. package/dist/api/InvoicesApi.d.ts.map +1 -0
  7. package/dist/api/InvoicesApi.js +40 -0
  8. package/dist/api/InvoicesApi.js.map +1 -0
  9. package/dist/api/SlugsApi.d.ts +1 -1
  10. package/dist/api/SlugsApi.d.ts.map +1 -1
  11. package/dist/api/SlugsApi.js +4 -15
  12. package/dist/api/SlugsApi.js.map +1 -1
  13. package/dist/api/index.d.ts +1 -0
  14. package/dist/api/index.d.ts.map +1 -1
  15. package/dist/api/index.js +1 -0
  16. package/dist/api/index.js.map +1 -1
  17. package/dist/common/index.d.ts +1 -0
  18. package/dist/common/index.d.ts.map +1 -1
  19. package/dist/common/index.js +1 -0
  20. package/dist/common/index.js.map +1 -1
  21. package/dist/common/invoicesCsv.common.d.ts +85 -0
  22. package/dist/common/invoicesCsv.common.d.ts.map +1 -0
  23. package/dist/common/invoicesCsv.common.js +185 -0
  24. package/dist/common/invoicesCsv.common.js.map +1 -0
  25. package/dist/common/sync.common.d.ts +1 -48
  26. package/dist/common/sync.common.d.ts.map +1 -1
  27. package/dist/common/sync.common.js +1 -97
  28. package/dist/common/sync.common.js.map +1 -1
  29. package/dist/sync/ChargersSync.d.ts +13 -0
  30. package/dist/sync/ChargersSync.d.ts.map +1 -0
  31. package/dist/sync/ChargersSync.js +25 -0
  32. package/dist/sync/ChargersSync.js.map +1 -0
  33. package/dist/sync/ISyncHandler.d.ts +39 -0
  34. package/dist/sync/ISyncHandler.d.ts.map +1 -0
  35. package/dist/sync/ISyncHandler.js +63 -0
  36. package/dist/sync/ISyncHandler.js.map +1 -0
  37. package/dist/sync/ISyncPlanHandler.d.ts +21 -0
  38. package/dist/sync/ISyncPlanHandler.d.ts.map +1 -0
  39. package/dist/sync/ISyncPlanHandler.js +58 -0
  40. package/dist/sync/ISyncPlanHandler.js.map +1 -0
  41. package/dist/sync/InvoicesSync.d.ts +8 -0
  42. package/dist/sync/InvoicesSync.d.ts.map +1 -0
  43. package/dist/sync/InvoicesSync.js +21 -0
  44. package/dist/sync/InvoicesSync.js.map +1 -0
  45. package/dist/sync/SlugsSync.d.ts +9 -0
  46. package/dist/sync/SlugsSync.d.ts.map +1 -0
  47. package/dist/sync/SlugsSync.js +18 -0
  48. package/dist/sync/SlugsSync.js.map +1 -0
  49. package/dist/sync/index.d.ts +6 -0
  50. package/dist/sync/index.d.ts.map +1 -0
  51. package/dist/sync/index.js +7 -0
  52. package/dist/sync/index.js.map +1 -0
  53. package/package.json +10 -4
@@ -47,7 +47,7 @@ export declare class ChargersApi extends IApi {
47
47
  syncLoad(slug: string, locale: string, slugsId?: PicSlugsId): Promise<PicChargers>;
48
48
  /** Snapshot sync from a full-feed file dump. Does not touch pricebooks. */
49
49
  syncLoadFile(path: string): Promise<SyncSummary>;
50
- protected _syncLoad(clientDocs: TeslaClientCharger[]): Promise<SyncSummary>;
50
+ protected _syncLoad(docs: TeslaClientCharger[]): Promise<SyncSummary>;
51
51
  }
52
52
  export declare const chargersApi: () => ChargersApi;
53
53
  //# sourceMappingURL=ChargersApi.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ChargersApi.d.ts","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"AAOA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,UAAU,EAChB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,4CAA4C,CAAC;AAOpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAQhF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAO1D,qBAAa,WAAY,SAAQ,IAAI;IACnC;;;;;;;;;;OAUG;IACU,IAAI,CACf,IAAI,EAAE,aAAa,EACnB,MAAM,GAAE,MAAgB,GACvB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA8D9B;;;;;;;;;;;;;;;OAeG;IACU,UAAU,CACrB,IAAI,EAAE,aAAa,EACnB,EAAE,EAAE,IAAI,GACP,OAAO,CAAC,aAAa,EAAE,CAAC;IAmBd,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzD;;;;;;;;;OASG;IACU,QAAQ,CACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,WAAW,CAAC;IAgDvB,2EAA2E;IAC9D,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAK7C,SAAS,CACvB,UAAU,EAAE,kBAAkB,EAAE,GAC/B,OAAO,CAAC,WAAW,CAAC;CAkBxB;AAGD,eAAO,MAAM,WAAW,mBAAqC,CAAC"}
1
+ {"version":3,"file":"ChargersApi.d.ts","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"AAOA,OAAO,EACL,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,UAAU,EAChB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,4CAA4C,CAAC;AAOpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAOhF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAO1D,qBAAa,WAAY,SAAQ,IAAI;IACnC;;;;;;;;;;OAUG;IACU,IAAI,CACf,IAAI,EAAE,aAAa,EACnB,MAAM,GAAE,MAAgB,GACvB,OAAO,CAAC,WAAW,GAAG,IAAI,CAAC;IA8D9B;;;;;;;;;;;;;;;OAeG;IACU,UAAU,CACrB,IAAI,EAAE,aAAa,EACnB,EAAE,EAAE,IAAI,GACP,OAAO,CAAC,aAAa,EAAE,CAAC;IAmBd,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAUzD;;;;;;;;;OASG;IACU,QAAQ,CACnB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,UAAU,GACnB,OAAO,CAAC,WAAW,CAAC;IAgDvB,2EAA2E;IAC9D,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAK7C,SAAS,CAAC,IAAI,EAAE,kBAAkB,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;CAK5E;AAGD,eAAO,MAAM,WAAW,mBAAqC,CAAC"}
@@ -1,13 +1,13 @@
1
1
  import { createMeta, chargerToInitializer, pricebookToInitializer, } from "@mxpicture/tesla-superchargers-mate/transform";
2
2
  import { readFile } from "node:fs/promises";
3
3
  import json5 from "json5";
4
- import { picChargersInitializerKeys, } from "@mxpicture/tesla-superchargers-generated/public";
4
+ import {} from "@mxpicture/tesla-superchargers-generated/public";
5
5
  import { teslaClient, teslaClientChargersSchema, } from "@mxpicture/tesla-superchargers-mate/client";
6
6
  import { picChargersStore, picPricebooksStore, picSlugsStore, transaction, } from "@mxpicture/tesla-superchargers-mate/store";
7
- import { FAILURE_DEPRIORITIZE_THRESHOLD, isFresh, MAX_CHARGER_FETCHES, withoutFkColumns, } from "../common/chargers.common.js";
7
+ import { FAILURE_DEPRIORITIZE_THRESHOLD, isFresh, MAX_CHARGER_FETCHES, } from "../common/chargers.common.js";
8
8
  import { IApi } from "./IApi.js";
9
- import { syncColumns, syncSnapshot } from "../common/sync.common.js";
10
9
  import { pricebookCoversInstant, samePricebookGroup, } from "../common/pricebooks.common.js";
10
+ import { ChargersSync } from "../sync/ChargersSync.js";
11
11
  export class ChargersApi extends IApi {
12
12
  /**
13
13
  * Find the Supercharger at a coordinate: try the nearby slug rows
@@ -151,21 +151,10 @@ export class ChargersApi extends IApi {
151
151
  const json = json5.parse(await readFile(path, { encoding: "utf8" }));
152
152
  return await this._syncLoad(teslaClientChargersSchema.parse(json));
153
153
  }
154
- async _syncLoad(clientDocs) {
154
+ async _syncLoad(docs) {
155
155
  const meta = createMeta();
156
- const { compareColumns, updateColumns } = syncColumns(picChargersInitializerKeys);
157
- return await syncSnapshot({
158
- store: picChargersStore(),
159
- clientDocs,
160
- meta,
161
- toInitializer: (charger) => chargerToInitializer({ charger, meta }),
162
- keyOfInit: (doc) => doc.location_guid,
163
- keyOfDb: (doc) => doc.location_guid,
164
- deleteAbsent: "soft",
165
- conflictColumn: "location_guid",
166
- compareColumns: withoutFkColumns(compareColumns),
167
- updateColumns: withoutFkColumns(updateColumns),
168
- });
156
+ const sync = new ChargersSync();
157
+ return await sync.snapshot({ docs, meta });
169
158
  }
170
159
  }
171
160
  let _api = null;
@@ -1 +1 @@
1
- {"version":3,"file":"ChargersApi.js","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ChargersApi.js","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type InvoicesCsv } from "../common/invoicesCsv.common.js";
2
+ import { IApi } from "./IApi.js";
3
+ import type { SyncSummary } from "../types/sync.types.js";
4
+ export declare class InvoicesApi extends IApi {
5
+ /**
6
+ * Throws when any row fails validation, before touching the db: the
7
+ * snapshot sync soft-deletes rows absent from the feed, so syncing only
8
+ * the valid rows would delete the invoices behind the bad ones.
9
+ */
10
+ syncCsv(csvText: string): Promise<SyncSummary>;
11
+ syncCsvFile(path: string): Promise<SyncSummary>;
12
+ protected _syncLoad(csvs: InvoicesCsv[]): Promise<SyncSummary>;
13
+ }
14
+ export declare const invoicesApi: () => InvoicesApi;
15
+ //# sourceMappingURL=InvoicesApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InvoicesApi.d.ts","sourceRoot":"","sources":["../../src/api/InvoicesApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAM1D,qBAAa,WAAY,SAAQ,IAAI;IACnC;;;;OAIG;IACU,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAU9C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAI5C,SAAS,CAAC,IAAI,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;CAmBrE;AAGD,eAAO,MAAM,WAAW,mBAAqC,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { formatInvoicesCsvErrors, fromInvoiceCsv, parseInvoicesCsv, } from "../common/invoicesCsv.common.js";
2
+ import { IApi } from "./IApi.js";
3
+ import { createMeta } from "@mxpicture/tesla-superchargers-mate/transform";
4
+ import { readFile } from "node:fs/promises";
5
+ import { InvoicesSync } from "../sync/InvoicesSync.js";
6
+ import { chargingProcessesStore } from "@mxpicture/tesla-superchargers-mate/store";
7
+ export class InvoicesApi extends IApi {
8
+ /**
9
+ * Throws when any row fails validation, before touching the db: the
10
+ * snapshot sync soft-deletes rows absent from the feed, so syncing only
11
+ * the valid rows would delete the invoices behind the bad ones.
12
+ */
13
+ async syncCsv(csvText) {
14
+ const { invoices, errors } = parseInvoicesCsv(csvText);
15
+ if (errors.length > 0)
16
+ throw new Error(`invoices CSV: ${errors.length} invalid row(s)\n` +
17
+ formatInvoicesCsvErrors(errors));
18
+ return await this._syncLoad(invoices);
19
+ }
20
+ async syncCsvFile(path) {
21
+ return await this.syncCsv(await readFile(path, { encoding: "utf8" }));
22
+ }
23
+ async _syncLoad(csvs) {
24
+ const cp = chargingProcessesStore();
25
+ const meta = createMeta();
26
+ const docs = [];
27
+ for (const csv of csvs) {
28
+ const chargingProcessesId = await cp.lookupChargingProcessId(csv.Vin, csv.ChargeStartDateTime);
29
+ docs.push({ ...fromInvoiceCsv({ csv, meta }), chargingProcessesId });
30
+ }
31
+ const sync = new InvoicesSync();
32
+ return await sync.snapshot({
33
+ docs,
34
+ meta,
35
+ });
36
+ }
37
+ }
38
+ let _api = null;
39
+ export const invoicesApi = () => (_api ??= new InvoicesApi());
40
+ //# sourceMappingURL=InvoicesApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InvoicesApi.js","sourceRoot":"","sources":["../../src/api/InvoicesApi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,EACvB,cAAc,EACd,gBAAgB,GAEjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,+CAA+C,CAAC;AAE3E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAGnF,MAAM,OAAO,WAAY,SAAQ,IAAI;IACnC;;;;OAIG;IACI,KAAK,CAAC,OAAO,CAAC,OAAe;QAClC,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;QACvD,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC;YACnB,MAAM,IAAI,KAAK,CACb,iBAAiB,MAAM,CAAC,MAAM,mBAAmB;gBAC/C,uBAAuB,CAAC,MAAM,CAAC,CAClC,CAAC;QACJ,OAAO,MAAM,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAEM,KAAK,CAAC,WAAW,CAAC,IAAY;QACnC,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC;IACxE,CAAC;IAES,KAAK,CAAC,SAAS,CAAC,IAAmB;QAC3C,MAAM,EAAE,GAAG,sBAAsB,EAAE,CAAC;QACpC,MAAM,IAAI,GAAG,UAAU,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAc,EAAE,CAAC;QAE3B,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,mBAAmB,GAAG,MAAM,EAAE,CAAC,uBAAuB,CAC1D,GAAG,CAAC,GAAG,EACP,GAAG,CAAC,mBAAmB,CACxB,CAAC;YACF,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,cAAc,CAAC,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACvE,CAAC;QAED,MAAM,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;QAChC,OAAO,MAAM,IAAI,CAAC,QAAQ,CAAC;YACzB,IAAI;YACJ,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CACF;AAED,IAAI,IAAI,GAAuB,IAAI,CAAC;AACpC,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,WAAW,EAAE,CAAC,CAAC"}
@@ -9,7 +9,7 @@ export declare class SlugsApi extends IApi {
9
9
  initialLoadFile(path: string): Promise<SyncSummary>;
10
10
  syncLoad(): Promise<SyncSummary>;
11
11
  syncLoadFile(path: string): Promise<SyncSummary>;
12
- protected _syncLoad(clientDocs: TeslaClientSlug[]): Promise<SyncSummary>;
12
+ protected _syncLoad(docs: TeslaClientSlug[]): Promise<SyncSummary>;
13
13
  }
14
14
  export declare const slugsApi: () => SlugsApi;
15
15
  //# sourceMappingURL=SlugsApi.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SlugsApi.d.ts","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAY1D,qBAAa,QAAS,SAAQ,IAAI;IACnB,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAItD,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IAgBnC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBnD,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;IAKhC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAI7C,SAAS,CACvB,UAAU,EAAE,eAAe,EAAE,GAC5B,OAAO,CAAC,WAAW,CAAC;CAexB;AAGD,eAAO,MAAM,QAAQ,gBAAkC,CAAC"}
1
+ {"version":3,"file":"SlugsApi.d.ts","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAClF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4CAA4C,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAClF,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAY1D,qBAAa,QAAS,SAAQ,IAAI;IACnB,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAItD,WAAW,IAAI,OAAO,CAAC,WAAW,CAAC;IAgBnC,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;IAgBnD,QAAQ,IAAI,OAAO,CAAC,WAAW,CAAC;IAKhC,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC;cAI7C,SAAS,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC;CAKzE;AAGD,eAAO,MAAM,QAAQ,gBAAkC,CAAC"}
@@ -2,10 +2,9 @@ import { parseTeslaClientSlugs, teslaClient, } from "@mxpicture/tesla-supercharg
2
2
  import { createMeta, slugToInitializer, } from "@mxpicture/tesla-superchargers-mate/transform";
3
3
  import { readFile } from "node:fs/promises";
4
4
  import json5 from "json5";
5
- import { picSlugsInitializerKeys } from "@mxpicture/tesla-superchargers-generated/public";
6
5
  import { picSlugsStore } from "@mxpicture/tesla-superchargers-mate/store";
7
6
  import { IApi } from "./IApi.js";
8
- import { syncSnapshot, syncColumns } from "../common/sync.common.js";
7
+ import { SlugsSync } from "../sync/SlugsSync.js";
9
8
  /** Per-element parse of a slugs file dump; invalid entries are skipped, not fatal. */
10
9
  const readSlugsFile = async (path) => {
11
10
  const json = json5.parse(await readFile(path, { encoding: "utf8" }));
@@ -47,20 +46,10 @@ export class SlugsApi extends IApi {
47
46
  async syncLoadFile(path) {
48
47
  return await this._syncLoad(await readSlugsFile(path));
49
48
  }
50
- async _syncLoad(clientDocs) {
49
+ async _syncLoad(docs) {
51
50
  const meta = createMeta();
52
- return await syncSnapshot({
53
- store: picSlugsStore(),
54
- clientDocs,
55
- meta,
56
- toInitializer: (slug) => slugToInitializer({ slug, meta }),
57
- keyOfInit: (doc) => doc.tesla_uuid ?? null,
58
- keyOfDb: (doc) => doc.tesla_uuid,
59
- // the table mirrors the feed: rows absent from it are hard-deleted
60
- deleteAbsent: "hard",
61
- conflictColumn: "tesla_uuid",
62
- ...syncColumns(picSlugsInitializerKeys),
63
- });
51
+ const sync = new SlugsSync();
52
+ return await sync.snapshot({ docs, meta });
64
53
  }
65
54
  }
66
55
  let _api = null;
@@ -1 +1 @@
1
- {"version":3,"file":"SlugsApi.js","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SlugsApi.js","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"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"}
@@ -2,5 +2,6 @@ export * from "./ChargersApi.js";
2
2
  export * from "./ChargingProcessesApi.js";
3
3
  export * from "./FailuresApi.js";
4
4
  export * from "./IApi.js";
5
+ export * from "./InvoicesApi.js";
5
6
  export * from "./SlugsApi.js";
6
7
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AACA,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC"}
package/dist/api/index.js CHANGED
@@ -3,5 +3,6 @@ export * from "./ChargersApi.js";
3
3
  export * from "./ChargingProcessesApi.js";
4
4
  export * from "./FailuresApi.js";
5
5
  export * from "./IApi.js";
6
+ export * from "./InvoicesApi.js";
6
7
  export * from "./SlugsApi.js";
7
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/api/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,kBAAkB,CAAC;AACjC,cAAc,2BAA2B,CAAC;AAC1C,cAAc,kBAAkB,CAAC;AACjC,cAAc,WAAW,CAAC;AAC1B,cAAc,kBAAkB,CAAC;AACjC,cAAc,eAAe,CAAC"}
@@ -1,5 +1,6 @@
1
1
  export * from "./chargers.common.js";
2
2
  export * from "./failures.common.js";
3
+ export * from "./invoicesCsv.common.js";
3
4
  export * from "./pricebooks.common.js";
4
5
  export * from "./pushover.common.js";
5
6
  export * from "./sync.common.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AACA,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
@@ -1,6 +1,7 @@
1
1
  // This file is auto-generated by build-cli. Do not edit manually.
2
2
  export * from "./chargers.common.js";
3
3
  export * from "./failures.common.js";
4
+ export * from "./invoicesCsv.common.js";
4
5
  export * from "./pricebooks.common.js";
5
6
  export * from "./pushover.common.js";
6
7
  export * from "./sync.common.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/common/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,sBAAsB,CAAC;AACrC,cAAc,sBAAsB,CAAC;AACrC,cAAc,yBAAyB,CAAC;AACxC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Tesla charging-CSV import for pic_invoices.
3
+ *
4
+ * Pipeline: raw CSV string
5
+ * → csv-parse (structure: delimiters, quoting, headers)
6
+ * → zod row schema (semantics: "N/A" → null, "22.1285 kwh" → value+unit,
7
+ * "0.51/kwh" → value+unit, NUMERIC precision checks, ISO dates)
8
+ * → PicInvoicesInitializer
9
+ * → parameterized INSERT (numerics stay strings; pg casts to NUMERIC losslessly)
10
+ *
11
+ * deps: npm i csv-parse postgres zod
12
+ */
13
+ import type { Invoice, Meta } from "@mxpicture/tesla-superchargers-mate/types";
14
+ import { z } from "zod";
15
+ export declare const invoicesCsvSchema: z.ZodObject<{
16
+ ChargeStartDateTime: z.ZodPipe<z.ZodString, z.ZodTransform<Date, string>>;
17
+ Name: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
18
+ Vin: z.ZodString;
19
+ Model: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
20
+ Country: z.ZodString;
21
+ SiteLocationName: z.ZodString;
22
+ Description: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
23
+ QuantityBase: z.ZodPipe<z.ZodString, z.ZodTransform<{
24
+ value: number;
25
+ unit: string;
26
+ }, string>>;
27
+ QuantityTier1: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
28
+ value: number;
29
+ unit: string;
30
+ }, string>>>>;
31
+ QuantityTier2: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
32
+ value: number;
33
+ unit: string;
34
+ }, string>>>>;
35
+ QuantityTier3: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
36
+ value: number;
37
+ unit: string;
38
+ }, string>>>>;
39
+ QuantityTier4: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
40
+ value: number;
41
+ unit: string;
42
+ }, string>>>>;
43
+ InvoiceNumber: z.ZodString;
44
+ UnitCostBase: z.ZodPipe<z.ZodString, z.ZodTransform<{
45
+ value: number;
46
+ unit: string;
47
+ }, string>>;
48
+ UnitCostTier1: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
49
+ value: number;
50
+ unit: string;
51
+ }, string>>>>;
52
+ UnitCostTier2: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
53
+ value: number;
54
+ unit: string;
55
+ }, string>>>>;
56
+ UnitCostTier3: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
57
+ value: number;
58
+ unit: string;
59
+ }, string>>>>;
60
+ UnitCostTier4: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
61
+ value: number;
62
+ unit: string;
63
+ }, string>>>>;
64
+ VAT: z.ZodString;
65
+ "Total Exc. VAT": z.ZodString;
66
+ "Total Inc. VAT": z.ZodString;
67
+ Status: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
68
+ Invoice: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
69
+ }, z.core.$strip>;
70
+ export type InvoicesCsv = z.infer<typeof invoicesCsvSchema>;
71
+ export interface InvoicesCsvError {
72
+ line: number;
73
+ issues: z.core.$ZodIssue[];
74
+ }
75
+ /** One line per invalid row: `line 3: QuantityBase: invalid quantity: "x"`. */
76
+ export declare const formatInvoicesCsvErrors: (errors: InvoicesCsvError[]) => string;
77
+ export declare const parseInvoicesCsv: (csvText: string) => {
78
+ invoices: InvoicesCsv[];
79
+ errors: InvoicesCsvError[];
80
+ };
81
+ export declare const fromInvoiceCsv: ({ csv, meta, }: {
82
+ csv: InvoicesCsv;
83
+ meta: Meta;
84
+ }) => Invoice;
85
+ //# sourceMappingURL=invoicesCsv.common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoicesCsv.common.d.ts","sourceRoot":"","sources":["../../src/common/invoicesCsv.common.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EACV,OAAO,EAEP,IAAI,EACL,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAmGxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwB5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAM5D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;CAC5B;AAED,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,GAAI,QAAQ,gBAAgB,EAAE,KAAG,MAQtD,CAAC;AAEhB,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,KACd;IACD,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAoB5B,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,gBAG5B;IACD,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;CACZ,KAAG,OAgCH,CAAC"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Tesla charging-CSV import for pic_invoices.
3
+ *
4
+ * Pipeline: raw CSV string
5
+ * → csv-parse (structure: delimiters, quoting, headers)
6
+ * → zod row schema (semantics: "N/A" → null, "22.1285 kwh" → value+unit,
7
+ * "0.51/kwh" → value+unit, NUMERIC precision checks, ISO dates)
8
+ * → PicInvoicesInitializer
9
+ * → parameterized INSERT (numerics stay strings; pg casts to NUMERIC losslessly)
10
+ *
11
+ * deps: npm i csv-parse postgres zod
12
+ */
13
+ import { removeUndefined } from "@mxpicture/tesla-superchargers-mate/transform";
14
+ import { parse } from "csv-parse/sync";
15
+ import { z } from "zod";
16
+ /* ------------------------------------------------------------------ */
17
+ /* helpers */
18
+ /* ------------------------------------------------------------------ */
19
+ const castNum = (name, str) => {
20
+ const value = str === null ? str : Number(str);
21
+ if (value === null || !Number.isFinite(value))
22
+ throw new Error(`invalid ${name}: "${str}"`);
23
+ return value;
24
+ };
25
+ /** "N/A" / "" / whitespace → null, everything else → trimmed string. */
26
+ const naToNull = (v) => {
27
+ if (typeof v !== "string")
28
+ return v;
29
+ const t = v.trim();
30
+ return t === "" || t.toUpperCase() === "N/A" ? null : t;
31
+ };
32
+ /**
33
+ * Decimal kept as *string* (matches Kanel's typing of pg NUMERIC) with a
34
+ * precision/scale check mirroring the column definition, so bad values fail
35
+ * in validation instead of as a pg error mid-insert.
36
+ */
37
+ const numericString = (precision, scale) => z
38
+ .string()
39
+ .trim()
40
+ .regex(/^-?\d+(\.\d+)?$/, "not a decimal number")
41
+ .refine((s) => {
42
+ const [int = "", frac = ""] = s.replace("-", "").split(".");
43
+ return frac.length <= scale && int.length <= precision - scale;
44
+ }, `exceeds NUMERIC(${precision}, ${scale})`);
45
+ /** "22.1285 kwh" → { value: 22.1285, unit: "kwh" } (unit optional). */
46
+ const quantity = z
47
+ .string()
48
+ .trim()
49
+ .transform((s, ctx) => {
50
+ const m = s.match(/^(-?\d+(?:\.\d+)?)(?:\s+(\S+))?$/);
51
+ if (!m) {
52
+ ctx.addIssue({ code: "custom", message: `invalid quantity: "${s}"` });
53
+ return z.NEVER;
54
+ }
55
+ const value = m[1] === null ? m[1] : Number(m[1]);
56
+ if (value === null || !Number.isFinite(value)) {
57
+ ctx.addIssue({ code: "custom", message: `invalid quantity: "${s}"` });
58
+ return z.NEVER;
59
+ }
60
+ return { value, unit: m[2]?.toLowerCase() ?? null };
61
+ })
62
+ .refine((q) => numericString(8, 4).safeParse(String(q.value)).success, {
63
+ message: "quantity exceeds NUMERIC(8, 4)",
64
+ });
65
+ /** "0.51/kwh" → { value: 0.51, unit: "kwh" }. */
66
+ const unitCost = z
67
+ .string()
68
+ .trim()
69
+ .transform((s, ctx) => {
70
+ const m = s.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(\S+)$/);
71
+ if (!m) {
72
+ ctx.addIssue({ code: "custom", message: `invalid unit cost: "${s}"` });
73
+ return z.NEVER;
74
+ }
75
+ const value = m[1] === null ? m[1] : Number(m[1]);
76
+ if (value === null || !Number.isFinite(value)) {
77
+ ctx.addIssue({ code: "custom", message: `invalid unit cost: "${s}"` });
78
+ return z.NEVER;
79
+ }
80
+ return { value, unit: m[2].toLowerCase() };
81
+ })
82
+ .refine((c) => numericString(4, 2).safeParse(String(c.value)).success, {
83
+ message: "unit cost exceeds NUMERIC(4, 2)",
84
+ });
85
+ /** ISO-8601 with offset ("2026-03-31T14:56:00+02:00") → Date. */
86
+ const isoDate = z
87
+ .string()
88
+ .trim()
89
+ .transform((s, ctx) => {
90
+ const d = new Date(s);
91
+ if (Number.isNaN(d.getTime())) {
92
+ ctx.addIssue({ code: "custom", message: `invalid date: "${s}"` });
93
+ return z.NEVER;
94
+ }
95
+ return d;
96
+ });
97
+ const nullable = (schema) => z.preprocess(naToNull, schema.nullable());
98
+ const nonEmpty = z.string().trim().min(1);
99
+ /* ------------------------------------------------------------------ */
100
+ /* CSV row schema (keys = exact CSV headers) */
101
+ /* ------------------------------------------------------------------ */
102
+ export const invoicesCsvSchema = z.object({
103
+ ChargeStartDateTime: isoDate,
104
+ Name: nullable(nonEmpty),
105
+ Vin: nonEmpty,
106
+ Model: nullable(nonEmpty),
107
+ Country: nonEmpty,
108
+ SiteLocationName: nonEmpty,
109
+ Description: nullable(nonEmpty),
110
+ QuantityBase: quantity,
111
+ QuantityTier1: nullable(quantity),
112
+ QuantityTier2: nullable(quantity),
113
+ QuantityTier3: nullable(quantity),
114
+ QuantityTier4: nullable(quantity),
115
+ InvoiceNumber: nonEmpty,
116
+ UnitCostBase: unitCost,
117
+ UnitCostTier1: nullable(unitCost),
118
+ UnitCostTier2: nullable(unitCost),
119
+ UnitCostTier3: nullable(unitCost),
120
+ UnitCostTier4: nullable(unitCost),
121
+ VAT: numericString(5, 2),
122
+ "Total Exc. VAT": numericString(5, 2),
123
+ "Total Inc. VAT": numericString(5, 2),
124
+ Status: nullable(nonEmpty),
125
+ Invoice: nullable(z.string().trim().url()),
126
+ });
127
+ /** One line per invalid row: `line 3: QuantityBase: invalid quantity: "x"`. */
128
+ export const formatInvoicesCsvErrors = (errors) => errors
129
+ .map(({ line, issues }) => `line ${line}: ${issues
130
+ .map((issue) => `${issue.path.join(".")}: ${issue.message}`)
131
+ .join("; ")}`)
132
+ .join("\n");
133
+ export const parseInvoicesCsv = (csvText) => {
134
+ // csv-parse handles quoting ("Windischeschenbach, Germany"), BOM, CRLF.
135
+ const records = parse(csvText, {
136
+ columns: true, // first line = header, rows become objects
137
+ bom: true,
138
+ skip_empty_lines: true,
139
+ trim: true,
140
+ });
141
+ const invoices = [];
142
+ const errors = [];
143
+ records.forEach((record, i) => {
144
+ const result = invoicesCsvSchema.safeParse(record);
145
+ if (result.success)
146
+ invoices.push(result.data);
147
+ else
148
+ errors.push({ line: i + 2, issues: result.error.issues });
149
+ });
150
+ return { invoices, errors };
151
+ };
152
+ export const fromInvoiceCsv = ({ csv, meta, }) => {
153
+ const result = {
154
+ id: undefined,
155
+ chargingProcessesId: null,
156
+ fetched_at: meta.fetched_at,
157
+ last_fetch_uuid: meta.last_fetch_uuid,
158
+ chargeStartDateTime: csv.ChargeStartDateTime,
159
+ name: csv.Name,
160
+ vin: csv.Vin,
161
+ model: csv.Model,
162
+ country: csv.Country,
163
+ siteLocationName: csv.SiteLocationName,
164
+ description: csv.Description,
165
+ ucom: csv.QuantityBase.unit,
166
+ quantityBase: csv.QuantityBase.value,
167
+ quantityTier1: csv.QuantityTier1?.value,
168
+ quantityTier2: csv.QuantityTier2?.value,
169
+ quantityTier3: csv.QuantityTier3?.value,
170
+ quantityTier4: csv.QuantityTier4?.value,
171
+ invoiceNumber: csv.InvoiceNumber,
172
+ unitCostBase: csv.UnitCostBase.value,
173
+ unitCostTier1: csv.UnitCostTier1?.value,
174
+ unitCostTier2: csv.UnitCostTier2?.value,
175
+ unitCostTier3: csv.UnitCostTier3?.value,
176
+ unitCostTier4: csv.UnitCostTier4?.value,
177
+ vat: castNum("VAT", csv.VAT),
178
+ totalExcVat: castNum("Total Exc. VAT", csv["Total Exc. VAT"]),
179
+ totalIncVat: castNum("Total Inc. VAT", csv["Total Inc. VAT"]),
180
+ status: csv.Status,
181
+ invoice: csv.Invoice,
182
+ };
183
+ return removeUndefined(result);
184
+ };
185
+ //# sourceMappingURL=invoicesCsv.common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"invoicesCsv.common.js","sourceRoot":"","sources":["../../src/common/invoicesCsv.common.ts"],"names":[],"mappings":"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"}
@@ -1,51 +1,4 @@
1
- import type { KeyParams } from "@mxpicture/tesla-superchargers-generated/public";
2
- import type { Meta } from "@mxpicture/tesla-superchargers-mate/types";
3
- import type { SyncDbRow, SyncPlan, SyncSummary } from "../types/sync.types.js";
4
- import { type IMateStore } from "@mxpicture/tesla-superchargers-mate/store";
5
1
  /** Abort the sync when the feed shrinks below this share of the active rows. */
6
2
  export declare const CIRCUIT_BREAKER_MIN_RATIO = 0.5;
7
- /**
8
- * Pure planning step of a snapshot sync: match feed docs to db rows by the
9
- * semantic key (deduplicating the feed, first wins) and track which db ids
10
- * were seen so the caller can delete the absent rest.
11
- * Throws (before anything is written) when the feed looks truncated.
12
- */
13
- export declare const planSync: <CLIENT, DB extends SyncDbRow, INITIALZER>(p: {
14
- clientDocs: CLIENT[];
15
- dbDocs: DB[];
16
- toInitializer: (clientDoc: CLIENT) => INITIALZER;
17
- keyOfInit: (doc: INITIALZER) => string | null;
18
- keyOfDb: (doc: DB) => string | null;
19
- }) => SyncPlan<INITIALZER>;
20
- /**
21
- * Upsert column lists from the generated initializer keys: compared columns
22
- * are the feed content plus — on soft-delete tables — `deleted_at` (so
23
- * returning sites resurrect even when unchanged); updated columns add the
24
- * fetch meta. `failure_count`/`failure_notified_at` stay out of both — the
25
- * chargers pipeline owns them after the initial insert.
26
- */
27
- export declare const syncColumns: <T extends object>(initializerKeys: KeyParams<T>[]) => {
28
- updateColumns: string[];
29
- compareColumns: string[];
30
- };
31
- /**
32
- * Snapshot sync: plan in memory, then — in one advisory-locked transaction —
33
- * delete the rows absent from the feed (`deleteAbsent`: "soft" keeps them
34
- * with `deleted_at` set, "hard" removes them — the table mirrors the feed)
35
- * and upsert the rest (value-compared via IS DISTINCT FROM). The delete runs
36
- * first so rows the upsert is about to insert cannot be caught by the
37
- * absence check.
38
- */
39
- export declare const syncSnapshot: <CLIENT, DB extends SyncDbRow, INITIALZER extends object>(p: {
40
- store: IMateStore<string, DB, INITIALZER, any>;
41
- clientDocs: CLIENT[];
42
- meta: Meta;
43
- toInitializer: (clientDoc: CLIENT) => INITIALZER;
44
- keyOfInit: (doc: INITIALZER) => string | null;
45
- keyOfDb: (doc: DB) => string | null;
46
- deleteAbsent: "hard" | "soft";
47
- conflictColumn: string;
48
- updateColumns: string[];
49
- compareColumns: string[];
50
- }) => Promise<SyncSummary>;
3
+ export declare const SYNC_META_COLUMNS: string[];
51
4
  //# sourceMappingURL=sync.common.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync.common.d.ts","sourceRoot":"","sources":["../../src/common/sync.common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iDAAiD,CAAC;AACjF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2CAA2C,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC/E,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,2CAA2C,CAAC;AAEnD,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,MAAM,EAAE,EAAE,SAAS,SAAS,EAAE,UAAU,EAAE,GAAG;IACpE,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,MAAM,EAAE,EAAE,EAAE,CAAC;IACb,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,UAAU,CAAC;IACjD,SAAS,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,MAAM,GAAG,IAAI,CAAC;CACrC,KAAG,QAAQ,CAAC,UAAU,CA6CtB,CAAC;AAUF;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAI,CAAC,SAAS,MAAM,EAC1C,iBAAiB,SAAS,CAAC,CAAC,CAAC,EAAE,KAC9B;IAAE,aAAa,EAAE,MAAM,EAAE,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAUrD,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,YAAY,GACvB,MAAM,EACN,EAAE,SAAS,SAAS,EACpB,UAAU,SAAS,MAAM,EACzB,GAAG;IAEH,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC/C,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,IAAI,EAAE,IAAI,CAAC;IACX,aAAa,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,UAAU,CAAC;IACjD,SAAS,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,MAAM,GAAG,IAAI,CAAC;IAC9C,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,KAAK,MAAM,GAAG,IAAI,CAAC;IACpC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,KAAG,OAAO,CAAC,WAAW,CAiCnB,CAAC"}
1
+ {"version":3,"file":"sync.common.d.ts","sourceRoot":"","sources":["../../src/common/sync.common.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,eAAO,MAAM,iBAAiB,UAM7B,CAAC"}
@@ -1,106 +1,10 @@
1
- import { transaction, } from "@mxpicture/tesla-superchargers-mate/store";
2
1
  /** Abort the sync when the feed shrinks below this share of the active rows. */
3
2
  export const CIRCUIT_BREAKER_MIN_RATIO = 0.5;
4
- /**
5
- * Pure planning step of a snapshot sync: match feed docs to db rows by the
6
- * semantic key (deduplicating the feed, first wins) and track which db ids
7
- * were seen so the caller can delete the absent rest.
8
- * Throws (before anything is written) when the feed looks truncated.
9
- */
10
- export const planSync = (p) => {
11
- const activeCount = p.dbDocs.filter((doc) => doc.deleted_at == null).length;
12
- if (activeCount > 0 &&
13
- p.clientDocs.length < activeCount * CIRCUIT_BREAKER_MIN_RATIO)
14
- throw new Error(`sync aborted: feed has ${p.clientDocs.length} docs for ${activeCount} active rows` +
15
- ` (circuit breaker ratio ${CIRCUIT_BREAKER_MIN_RATIO}) — refusing to mass soft-delete`);
16
- const dbByKey = new Map();
17
- for (const dbDoc of p.dbDocs) {
18
- const key = p.keyOfDb(dbDoc);
19
- if (key !== null)
20
- dbByKey.set(key, dbDoc);
21
- }
22
- const plan = {
23
- upserts: [],
24
- seenIds: [],
25
- feedDuplicates: 0,
26
- feedNullKeys: 0,
27
- };
28
- const seenKeys = new Set();
29
- for (const clientDoc of p.clientDocs) {
30
- const newDoc = p.toInitializer(clientDoc);
31
- const key = p.keyOfInit(newDoc);
32
- if (key === null) {
33
- plan.feedNullKeys++;
34
- continue;
35
- }
36
- if (seenKeys.has(key)) {
37
- plan.feedDuplicates++;
38
- continue;
39
- }
40
- seenKeys.add(key);
41
- const dbDoc = dbByKey.get(key);
42
- if (dbDoc !== undefined)
43
- plan.seenIds.push(dbDoc.id);
44
- plan.upserts.push(newDoc);
45
- }
46
- return plan;
47
- };
48
- const SYNC_META_COLUMNS = [
3
+ export const SYNC_META_COLUMNS = [
49
4
  "fetched_at",
50
5
  "last_fetch_uuid",
51
6
  "failure_count",
52
7
  "failure_notified_at",
53
8
  "deleted_at",
54
9
  ];
55
- /**
56
- * Upsert column lists from the generated initializer keys: compared columns
57
- * are the feed content plus — on soft-delete tables — `deleted_at` (so
58
- * returning sites resurrect even when unchanged); updated columns add the
59
- * fetch meta. `failure_count`/`failure_notified_at` stay out of both — the
60
- * chargers pipeline owns them after the initial insert.
61
- */
62
- export const syncColumns = (initializerKeys) => {
63
- const names = initializerKeys.map((key) => key.name);
64
- const content = names.filter((name) => !SYNC_META_COLUMNS.includes(name));
65
- const compareColumns = names.includes("deleted_at")
66
- ? [...content, "deleted_at"]
67
- : content;
68
- return {
69
- compareColumns,
70
- updateColumns: [...compareColumns, "fetched_at", "last_fetch_uuid"],
71
- };
72
- };
73
- /**
74
- * Snapshot sync: plan in memory, then — in one advisory-locked transaction —
75
- * delete the rows absent from the feed (`deleteAbsent`: "soft" keeps them
76
- * with `deleted_at` set, "hard" removes them — the table mirrors the feed)
77
- * and upsert the rest (value-compared via IS DISTINCT FROM). The delete runs
78
- * first so rows the upsert is about to insert cannot be caught by the
79
- * absence check.
80
- */
81
- export const syncSnapshot = async (p) => await transaction(p.store.table, async (tx) => {
82
- const dbDocs = await p.store.query(undefined, tx);
83
- const plan = planSync({
84
- clientDocs: p.clientDocs,
85
- dbDocs,
86
- toInitializer: p.toInitializer,
87
- keyOfInit: p.keyOfInit,
88
- keyOfDb: p.keyOfDb,
89
- });
90
- const deleted = p.deleteAbsent === "hard"
91
- ? await p.store.deleteWhereIdNotIn(plan.seenIds, tx)
92
- : await p.store.softDeleteWhereIdNotIn(plan.seenIds, p.meta, tx);
93
- const upserted = await p.store.upsertMany(plan.upserts, {
94
- conflictColumn: p.conflictColumn,
95
- updateColumns: p.updateColumns,
96
- compareColumns: p.compareColumns,
97
- }, tx);
98
- return {
99
- feedCount: p.clientDocs.length,
100
- feedDuplicates: plan.feedDuplicates,
101
- feedNullKeys: plan.feedNullKeys,
102
- upserted,
103
- deleted,
104
- };
105
- });
106
10
  //# sourceMappingURL=sync.common.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"sync.common.js","sourceRoot":"","sources":["../../src/common/sync.common.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sync.common.js","sourceRoot":"","sources":["../../src/common/sync.common.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAE7C,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,YAAY;IACZ,iBAAiB;IACjB,eAAe;IACf,qBAAqB;IACrB,YAAY;CACb,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { type PicChargers, type PicChargersInitializer } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { ISyncHandler } from "./ISyncHandler.js";
3
+ import type { TeslaClientCharger } from "@mxpicture/tesla-superchargers-mate/client";
4
+ import type { Meta } from "@mxpicture/tesla-superchargers-mate/types";
5
+ export declare class ChargersSync extends ISyncHandler<TeslaClientCharger, PicChargers, PicChargersInitializer> {
6
+ constructor();
7
+ columns(): {
8
+ updateColumns: string[];
9
+ compareColumns: string[];
10
+ };
11
+ protected toInitializer(charger: TeslaClientCharger, meta: Meta): PicChargersInitializer;
12
+ }
13
+ //# sourceMappingURL=ChargersSync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChargersSync.d.ts","sourceRoot":"","sources":["../../src/sync/ChargersSync.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC5B,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,4CAA4C,CAAC;AAErF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2CAA2C,CAAC;AAItE,qBAAa,YAAa,SAAQ,YAAY,CAC5C,kBAAkB,EAClB,WAAW,EACX,sBAAsB,CACvB;;IAUiB,OAAO,IAAI;QACzB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,cAAc,EAAE,MAAM,EAAE,CAAC;KAC1B;cAOkB,aAAa,CAC9B,OAAO,EAAE,kBAAkB,EAC3B,IAAI,EAAE,IAAI,GACT,sBAAsB;CAG1B"}
@@ -0,0 +1,25 @@
1
+ import { picChargersInitializerKeys, } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { ISyncHandler } from "./ISyncHandler.js";
3
+ import { chargerToInitializer } from "@mxpicture/tesla-superchargers-mate/transform";
4
+ import { picChargersStore } from "@mxpicture/tesla-superchargers-mate/store";
5
+ import { withoutFkColumns } from "../common/chargers.common.js";
6
+ export class ChargersSync extends ISyncHandler {
7
+ constructor() {
8
+ super({
9
+ store: picChargersStore(),
10
+ conflictColumn: "location_guid",
11
+ deleteAbsent: "soft",
12
+ initializerKeys: picChargersInitializerKeys,
13
+ });
14
+ }
15
+ columns() {
16
+ const cols = super.columns();
17
+ cols.compareColumns = withoutFkColumns(cols.compareColumns);
18
+ cols.updateColumns = withoutFkColumns(cols.updateColumns);
19
+ return cols;
20
+ }
21
+ toInitializer(charger, meta) {
22
+ return chargerToInitializer({ charger, meta });
23
+ }
24
+ }
25
+ //# sourceMappingURL=ChargersSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChargersSync.js","sourceRoot":"","sources":["../../src/sync/ChargersSync.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,GAG3B,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+CAA+C,CAAC;AAErF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;AAEhE,MAAM,OAAO,YAAa,SAAQ,YAIjC;IACC;QACE,KAAK,CAAC;YACJ,KAAK,EAAE,gBAAgB,EAAE;YACzB,cAAc,EAAE,eAAe;YAC/B,YAAY,EAAE,MAAM;YACpB,eAAe,EAAE,0BAA0B;SAC5C,CAAC,CAAC;IACL,CAAC;IAEe,OAAO;QAIrB,MAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,cAAc,GAAG,gBAAgB,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QAC5D,IAAI,CAAC,aAAa,GAAG,gBAAgB,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAC1D,OAAO,IAAI,CAAC;IACd,CAAC;IAEkB,aAAa,CAC9B,OAA2B,EAC3B,IAAU;QAEV,OAAO,oBAAoB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;CACF"}
@@ -0,0 +1,39 @@
1
+ import { type IMateStore } from "@mxpicture/tesla-superchargers-mate/store";
2
+ import type { SyncDbRow, SyncSummary } from "../types/sync.types.js";
3
+ import type { Meta } from "@mxpicture/tesla-superchargers-mate/types";
4
+ import type { KeyParams } from "@mxpicture/tesla-superchargers-generated/public";
5
+ import { ISyncPlanHandler } from "./ISyncPlanHandler.js";
6
+ export interface SyncHandlerParams<DB extends SyncDbRow, INITIALZER extends object> {
7
+ store: IMateStore<string, DB, INITIALZER, any>;
8
+ initializerKeys: KeyParams<INITIALZER>[];
9
+ deleteAbsent: "hard" | "soft";
10
+ conflictColumn: keyof DB & keyof INITIALZER;
11
+ }
12
+ export declare abstract class ISyncHandler<DOC, DB extends SyncDbRow, INITIALZER extends object> extends ISyncPlanHandler<DOC, DB, INITIALZER> {
13
+ protected readonly params: SyncHandlerParams<DB, INITIALZER>;
14
+ constructor(p: SyncHandlerParams<DB, INITIALZER>);
15
+ /**
16
+ * Snapshot sync: plan in memory, then — in one advisory-locked transaction —
17
+ * delete the rows absent from the feed (`deleteAbsent`: "soft" keeps them
18
+ * with `deleted_at` set, "hard" removes them — the table mirrors the feed)
19
+ * and upsert the rest (value-compared via IS DISTINCT FROM). The delete runs
20
+ * first so rows the upsert is about to insert cannot be caught by the
21
+ * absence check.
22
+ */
23
+ snapshot(p: {
24
+ docs: DOC[];
25
+ meta: Meta;
26
+ }): Promise<SyncSummary>;
27
+ /**
28
+ * Upsert column lists from the generated initializer keys: compared columns
29
+ * are the feed content plus — on soft-delete tables — `deleted_at` (so
30
+ * returning sites resurrect even when unchanged); updated columns add the
31
+ * fetch meta. `failure_count`/`failure_notified_at` stay out of both — the
32
+ * chargers pipeline owns them after the initial insert.
33
+ */
34
+ columns(): {
35
+ updateColumns: string[];
36
+ compareColumns: string[];
37
+ };
38
+ }
39
+ //# sourceMappingURL=ISyncHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISyncHandler.d.ts","sourceRoot":"","sources":["../../src/sync/ISyncHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,2CAA2C,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2CAA2C,CAAC;AACtE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iDAAiD,CAAC;AACjF,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,MAAM,WAAW,iBAAiB,CAChC,EAAE,SAAS,SAAS,EACpB,UAAU,SAAS,MAAM;IAGzB,KAAK,EAAE,UAAU,CAAC,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,CAAC,CAAC;IAC/C,eAAe,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,CAAC;IACzC,YAAY,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU,CAAC;CAC7C;AAED,8BAAsB,YAAY,CAChC,GAAG,EACH,EAAE,SAAS,SAAS,EACpB,UAAU,SAAS,MAAM,CACzB,SAAQ,gBAAgB,CAAC,GAAG,EAAE,EAAE,EAAE,UAAU,CAAC;IAC7C,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;gBAE1C,CAAC,EAAE,iBAAiB,CAAC,EAAE,EAAE,UAAU,CAAC;IAKvD;;;;;;;OAOG;IACU,QAAQ,CAAC,CAAC,EAAE;QAAE,IAAI,EAAE,GAAG,EAAE,CAAC;QAAC,IAAI,EAAE,IAAI,CAAA;KAAE,GAAG,OAAO,CAAC,WAAW,CAAC;IAwC3E;;;;;;OAMG;IACI,OAAO,IAAI;QAChB,aAAa,EAAE,MAAM,EAAE,CAAC;QACxB,cAAc,EAAE,MAAM,EAAE,CAAC;KAC1B;CAWF"}
@@ -0,0 +1,63 @@
1
+ import { transaction, } from "@mxpicture/tesla-superchargers-mate/store";
2
+ import { ISyncPlanHandler } from "./ISyncPlanHandler.js";
3
+ import { SYNC_META_COLUMNS } from "../common/sync.common.js";
4
+ export class ISyncHandler extends ISyncPlanHandler {
5
+ params;
6
+ constructor(p) {
7
+ super(p.conflictColumn);
8
+ this.params = { ...p };
9
+ }
10
+ /**
11
+ * Snapshot sync: plan in memory, then — in one advisory-locked transaction —
12
+ * delete the rows absent from the feed (`deleteAbsent`: "soft" keeps them
13
+ * with `deleted_at` set, "hard" removes them — the table mirrors the feed)
14
+ * and upsert the rest (value-compared via IS DISTINCT FROM). The delete runs
15
+ * first so rows the upsert is about to insert cannot be caught by the
16
+ * absence check.
17
+ */
18
+ async snapshot(p) {
19
+ return await transaction(this.params.store.table, async (tx) => {
20
+ const dbDocs = await this.params.store.query(undefined, tx);
21
+ const plan = this.plan({
22
+ docs: p.docs,
23
+ dbDocs,
24
+ meta: p.meta,
25
+ });
26
+ const deleted = this.params.deleteAbsent === "hard"
27
+ ? await this.params.store.deleteWhereIdNotIn(plan.seenIds, tx)
28
+ : await this.params.store.softDeleteWhereIdNotIn(plan.seenIds, p.meta, tx);
29
+ const { compareColumns, updateColumns } = this.columns();
30
+ const upserted = await this.params.store.upsertMany(plan.upserts, {
31
+ conflictColumn: this.params.conflictColumn.toString(),
32
+ updateColumns: updateColumns,
33
+ compareColumns: compareColumns,
34
+ }, tx);
35
+ return {
36
+ feedCount: p.docs.length,
37
+ feedDuplicates: plan.feedDuplicates,
38
+ feedNullKeys: plan.feedNullKeys,
39
+ upserted,
40
+ deleted,
41
+ };
42
+ });
43
+ }
44
+ /**
45
+ * Upsert column lists from the generated initializer keys: compared columns
46
+ * are the feed content plus — on soft-delete tables — `deleted_at` (so
47
+ * returning sites resurrect even when unchanged); updated columns add the
48
+ * fetch meta. `failure_count`/`failure_notified_at` stay out of both — the
49
+ * chargers pipeline owns them after the initial insert.
50
+ */
51
+ columns() {
52
+ const names = this.params.initializerKeys.map((key) => key.name);
53
+ const content = names.filter((name) => !SYNC_META_COLUMNS.includes(name));
54
+ const compareColumns = names.includes("deleted_at")
55
+ ? [...content, "deleted_at"]
56
+ : content;
57
+ return {
58
+ compareColumns,
59
+ updateColumns: [...compareColumns, "fetched_at", "last_fetch_uuid"],
60
+ };
61
+ }
62
+ }
63
+ //# sourceMappingURL=ISyncHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISyncHandler.js","sourceRoot":"","sources":["../../src/sync/ISyncHandler.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,GAEZ,MAAM,2CAA2C,CAAC;AAInD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAa7D,MAAM,OAAgB,YAIpB,SAAQ,gBAAqC;IAC1B,MAAM,CAAoC;IAE7D,YAAmB,CAAoC;QACrD,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC;QACxB,IAAI,CAAC,MAAM,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC;IACzB,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,QAAQ,CAAC,CAA8B;QAClD,OAAO,MAAM,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YAC7D,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;YAE5D,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;gBACrB,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM;gBACN,IAAI,EAAE,CAAC,CAAC,IAAI;aACb,CAAC,CAAC;YAEH,MAAM,OAAO,GACX,IAAI,CAAC,MAAM,CAAC,YAAY,KAAK,MAAM;gBACjC,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;gBAC9D,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAC5C,IAAI,CAAC,OAAO,EACZ,CAAC,CAAC,IAAI,EACN,EAAE,CACH,CAAC;YAER,MAAM,EAAE,cAAc,EAAE,aAAa,EAAE,GAAG,IAAI,CAAC,OAAO,EAAE,CAAC;YACzD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CACjD,IAAI,CAAC,OAAO,EACZ;gBACE,cAAc,EAAE,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,QAAQ,EAAE;gBACrD,aAAa,EAAE,aAAa;gBAC5B,cAAc,EAAE,cAAc;aAC/B,EACD,EAAE,CACH,CAAC;YAEF,OAAO;gBACL,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM;gBACxB,cAAc,EAAE,IAAI,CAAC,cAAc;gBACnC,YAAY,EAAE,IAAI,CAAC,YAAY;gBAC/B,QAAQ;gBACR,OAAO;aACR,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAED;;;;;;OAMG;IACI,OAAO;QAIZ,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,IAAc,CAAC,CAAC;QAC3E,MAAM,OAAO,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC;QAC1E,MAAM,cAAc,GAAG,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;YACjD,CAAC,CAAC,CAAC,GAAG,OAAO,EAAE,YAAY,CAAC;YAC5B,CAAC,CAAC,OAAO,CAAC;QACZ,OAAO;YACL,cAAc;YACd,aAAa,EAAE,CAAC,GAAG,cAAc,EAAE,YAAY,EAAE,iBAAiB,CAAC;SACpE,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,21 @@
1
+ import type { SyncDbRow, SyncPlan } from "../types/sync.types.js";
2
+ import type { Meta } from "@mxpicture/tesla-superchargers-mate/types";
3
+ export declare abstract class ISyncPlanHandler<DOC, DB extends SyncDbRow, INITIALZER extends object> {
4
+ readonly conflictColumn: keyof DB & keyof INITIALZER;
5
+ constructor(conflictColumn: keyof DB & keyof INITIALZER);
6
+ protected abstract toInitializer(doc: DOC, meta: Meta): INITIALZER;
7
+ protected keyOfInit(doc: INITIALZER): string | null;
8
+ protected keyOfDb(doc: DB): string | null;
9
+ /**
10
+ * Pure planning step of a snapshot sync: match feed docs to db rows by the
11
+ * semantic key (deduplicating the feed, first wins) and track which db ids
12
+ * were seen so the caller can delete the absent rest.
13
+ * Throws (before anything is written) when the feed looks truncated.
14
+ */
15
+ plan(p: {
16
+ docs: DOC[];
17
+ dbDocs: DB[];
18
+ meta: Meta;
19
+ }): SyncPlan<INITIALZER>;
20
+ }
21
+ //# sourceMappingURL=ISyncPlanHandler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISyncPlanHandler.d.ts","sourceRoot":"","sources":["../../src/sync/ISyncPlanHandler.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2CAA2C,CAAC;AAGtE,8BAAsB,gBAAgB,CACpC,GAAG,EACH,EAAE,SAAS,SAAS,EACpB,UAAU,SAAS,MAAM;aAGP,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU;gBAA3C,cAAc,EAAE,MAAM,EAAE,GAAG,MAAM,UAAU;IAG7D,SAAS,CAAC,QAAQ,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,GAAG,UAAU;IAElE,SAAS,CAAC,SAAS,CAAC,GAAG,EAAE,UAAU,GAAG,MAAM,GAAG,IAAI;IAGnD,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,GAAG,MAAM,GAAG,IAAI;IAIzC;;;;;OAKG;IACI,IAAI,CAAC,CAAC,EAAE;QACb,IAAI,EAAE,GAAG,EAAE,CAAC;QACZ,MAAM,EAAE,EAAE,EAAE,CAAC;QACb,IAAI,EAAE,IAAI,CAAC;KACZ,GAAG,QAAQ,CAAC,UAAU,CAAC;CA8CzB"}
@@ -0,0 +1,58 @@
1
+ import { CIRCUIT_BREAKER_MIN_RATIO } from "../common/sync.common.js";
2
+ export class ISyncPlanHandler {
3
+ conflictColumn;
4
+ constructor(conflictColumn) {
5
+ this.conflictColumn = conflictColumn;
6
+ }
7
+ keyOfInit(doc) {
8
+ return (doc[this.conflictColumn] ?? null);
9
+ }
10
+ keyOfDb(doc) {
11
+ return doc[this.conflictColumn];
12
+ }
13
+ /**
14
+ * Pure planning step of a snapshot sync: match feed docs to db rows by the
15
+ * semantic key (deduplicating the feed, first wins) and track which db ids
16
+ * were seen so the caller can delete the absent rest.
17
+ * Throws (before anything is written) when the feed looks truncated.
18
+ */
19
+ plan(p) {
20
+ const activeCount = p.dbDocs.filter((doc) => doc.deleted_at == null).length;
21
+ if (activeCount > 0 &&
22
+ p.docs.length < activeCount * CIRCUIT_BREAKER_MIN_RATIO)
23
+ throw new Error(`sync aborted: feed has ${p.docs.length} docs for ${activeCount} active rows` +
24
+ ` (circuit breaker ratio ${CIRCUIT_BREAKER_MIN_RATIO}) — refusing to mass soft-delete`);
25
+ const dbByKey = new Map();
26
+ for (const dbDoc of p.dbDocs) {
27
+ const key = this.keyOfDb(dbDoc);
28
+ if (key !== null)
29
+ dbByKey.set(key, dbDoc);
30
+ }
31
+ const plan = {
32
+ upserts: [],
33
+ seenIds: [],
34
+ feedDuplicates: 0,
35
+ feedNullKeys: 0,
36
+ };
37
+ const seenKeys = new Set();
38
+ for (const clientDoc of p.docs) {
39
+ const newDoc = this.toInitializer(clientDoc, p.meta);
40
+ const key = this.keyOfInit(newDoc);
41
+ if (key === null) {
42
+ plan.feedNullKeys++;
43
+ continue;
44
+ }
45
+ if (seenKeys.has(key)) {
46
+ plan.feedDuplicates++;
47
+ continue;
48
+ }
49
+ seenKeys.add(key);
50
+ const dbDoc = dbByKey.get(key);
51
+ if (dbDoc !== undefined)
52
+ plan.seenIds.push(dbDoc.id);
53
+ plan.upserts.push(newDoc);
54
+ }
55
+ return plan;
56
+ }
57
+ }
58
+ //# sourceMappingURL=ISyncPlanHandler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ISyncPlanHandler.js","sourceRoot":"","sources":["../../src/sync/ISyncPlanHandler.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,yBAAyB,EAAE,MAAM,0BAA0B,CAAC;AAErE,MAAM,OAAgB,gBAAgB;IAMlB;IADlB,YACkB,cAA2C;QAA3C,mBAAc,GAAd,cAAc,CAA6B;IAC1D,CAAC;IAIM,SAAS,CAAC,GAAe;QACjC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,cAAc,CAAC,IAAI,IAAI,CAAkB,CAAC;IAC7D,CAAC;IACS,OAAO,CAAC,GAAO;QACvB,OAAO,GAAG,CAAC,IAAI,CAAC,cAAc,CAAkB,CAAC;IACnD,CAAC;IAED;;;;;OAKG;IACI,IAAI,CAAC,CAIX;QACC,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,CAAC,MAAM,CAAC;QAC5E,IACE,WAAW,GAAG,CAAC;YACf,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,WAAW,GAAG,yBAAyB;YAEvD,MAAM,IAAI,KAAK,CACb,0BAA0B,CAAC,CAAC,IAAI,CAAC,MAAM,aAAa,WAAW,cAAc;gBAC3E,2BAA2B,yBAAyB,kCAAkC,CACzF,CAAC;QAEJ,MAAM,OAAO,GAAG,IAAI,GAAG,EAAc,CAAC;QACtC,KAAK,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;YAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;YAChC,IAAI,GAAG,KAAK,IAAI;gBAAE,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC5C,CAAC;QAED,MAAM,IAAI,GAAyB;YACjC,OAAO,EAAE,EAAE;YACX,OAAO,EAAE,EAAE;YACX,cAAc,EAAE,CAAC;YACjB,YAAY,EAAE,CAAC;SAChB,CAAC;QACF,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;QAEnC,KAAK,MAAM,SAAS,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;YAC/B,MAAM,MAAM,GAAG,IAAI,CAAC,aAAa,CAAC,SAAS,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;YACrD,MAAM,GAAG,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAEnC,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;gBACjB,IAAI,CAAC,YAAY,EAAE,CAAC;gBACpB,SAAS;YACX,CAAC;YACD,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACtB,IAAI,CAAC,cAAc,EAAE,CAAC;gBACtB,SAAS;YACX,CAAC;YACD,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAElB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC/B,IAAI,KAAK,KAAK,SAAS;gBAAE,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACrD,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAC5B,CAAC;QAED,OAAO,IAAI,CAAC;IACd,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { type PicInvoices, type PicInvoicesInitializer } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { ISyncHandler } from "./ISyncHandler.js";
3
+ import type { Invoice, Meta } from "@mxpicture/tesla-superchargers-mate/types";
4
+ export declare class InvoicesSync extends ISyncHandler<Invoice, PicInvoices, PicInvoicesInitializer> {
5
+ constructor();
6
+ protected toInitializer(invoice: Invoice, meta: Meta): PicInvoicesInitializer;
7
+ }
8
+ //# sourceMappingURL=InvoicesSync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InvoicesSync.d.ts","sourceRoot":"","sources":["../../src/sync/InvoicesSync.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC5B,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,2CAA2C,CAAC;AAG/E,qBAAa,YAAa,SAAQ,YAAY,CAC5C,OAAO,EACP,WAAW,EACX,sBAAsB,CACvB;;cAUoB,aAAa,CAC9B,OAAO,EAAE,OAAO,EAChB,IAAI,EAAE,IAAI,GACT,sBAAsB;CAM1B"}
@@ -0,0 +1,21 @@
1
+ import { picInvoicesInitializerKeys, } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { ISyncHandler } from "./ISyncHandler.js";
3
+ import { invoiceToInitializer } from "@mxpicture/tesla-superchargers-mate/transform";
4
+ import { picInvoicesStore } from "@mxpicture/tesla-superchargers-mate/store";
5
+ export class InvoicesSync extends ISyncHandler {
6
+ constructor() {
7
+ super({
8
+ store: picInvoicesStore(),
9
+ conflictColumn: "invoice_number",
10
+ deleteAbsent: "soft",
11
+ initializerKeys: picInvoicesInitializerKeys,
12
+ });
13
+ }
14
+ toInitializer(invoice, meta) {
15
+ return invoiceToInitializer({
16
+ invoice,
17
+ meta,
18
+ });
19
+ }
20
+ }
21
+ //# sourceMappingURL=InvoicesSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"InvoicesSync.js","sourceRoot":"","sources":["../../src/sync/InvoicesSync.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,0BAA0B,GAG3B,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,oBAAoB,EAAE,MAAM,+CAA+C,CAAC;AAErF,OAAO,EAAE,gBAAgB,EAAE,MAAM,2CAA2C,CAAC;AAE7E,MAAM,OAAO,YAAa,SAAQ,YAIjC;IACC;QACE,KAAK,CAAC;YACJ,KAAK,EAAE,gBAAgB,EAAE;YACzB,cAAc,EAAE,gBAAgB;YAChC,YAAY,EAAE,MAAM;YACpB,eAAe,EAAE,0BAA0B;SAC5C,CAAC,CAAC;IACL,CAAC;IAEkB,aAAa,CAC9B,OAAgB,EAChB,IAAU;QAEV,OAAO,oBAAoB,CAAC;YAC1B,OAAO;YACP,IAAI;SACL,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,9 @@
1
+ import { type PicSlugs, type PicSlugsInitializer } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { ISyncHandler } from "./ISyncHandler.js";
3
+ import type { TeslaClientSlug } from "@mxpicture/tesla-superchargers-mate/client";
4
+ import type { Meta } from "@mxpicture/tesla-superchargers-mate/types";
5
+ export declare class SlugsSync extends ISyncHandler<TeslaClientSlug, PicSlugs, PicSlugsInitializer> {
6
+ constructor();
7
+ protected toInitializer(slug: TeslaClientSlug, meta: Meta): PicSlugsInitializer;
8
+ }
9
+ //# sourceMappingURL=SlugsSync.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlugsSync.d.ts","sourceRoot":"","sources":["../../src/sync/SlugsSync.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,QAAQ,EACb,KAAK,mBAAmB,EACzB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4CAA4C,CAAC;AAElF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,2CAA2C,CAAC;AAGtE,qBAAa,SAAU,SAAQ,YAAY,CACzC,eAAe,EACf,QAAQ,EACR,mBAAmB,CACpB;;cAUoB,aAAa,CAC9B,IAAI,EAAE,eAAe,EACrB,IAAI,EAAE,IAAI,GACT,mBAAmB;CAGvB"}
@@ -0,0 +1,18 @@
1
+ import { picSlugsInitializerKeys, } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { ISyncHandler } from "./ISyncHandler.js";
3
+ import { slugToInitializer } from "@mxpicture/tesla-superchargers-mate/transform";
4
+ import { picSlugsStore } from "@mxpicture/tesla-superchargers-mate/store";
5
+ export class SlugsSync extends ISyncHandler {
6
+ constructor() {
7
+ super({
8
+ store: picSlugsStore(),
9
+ conflictColumn: "tesla_uuid",
10
+ deleteAbsent: "hard",
11
+ initializerKeys: picSlugsInitializerKeys,
12
+ });
13
+ }
14
+ toInitializer(slug, meta) {
15
+ return slugToInitializer({ slug, meta });
16
+ }
17
+ }
18
+ //# sourceMappingURL=SlugsSync.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlugsSync.js","sourceRoot":"","sources":["../../src/sync/SlugsSync.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,uBAAuB,GAGxB,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,+CAA+C,CAAC;AAElF,OAAO,EAAE,aAAa,EAAE,MAAM,2CAA2C,CAAC;AAE1E,MAAM,OAAO,SAAU,SAAQ,YAI9B;IACC;QACE,KAAK,CAAC;YACJ,KAAK,EAAE,aAAa,EAAE;YACtB,cAAc,EAAE,YAAY;YAC5B,YAAY,EAAE,MAAM;YACpB,eAAe,EAAE,uBAAuB;SACzC,CAAC,CAAC;IACL,CAAC;IAEkB,aAAa,CAC9B,IAAqB,EACrB,IAAU;QAEV,OAAO,iBAAiB,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3C,CAAC;CACF"}
@@ -0,0 +1,6 @@
1
+ export * from "./ChargersSync.js";
2
+ export * from "./ISyncHandler.js";
3
+ export * from "./ISyncPlanHandler.js";
4
+ export * from "./InvoicesSync.js";
5
+ export * from "./SlugsSync.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AACA,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
@@ -0,0 +1,7 @@
1
+ // This file is auto-generated by build-cli. Do not edit manually.
2
+ export * from "./ChargersSync.js";
3
+ export * from "./ISyncHandler.js";
4
+ export * from "./ISyncPlanHandler.js";
5
+ export * from "./InvoicesSync.js";
6
+ export * from "./SlugsSync.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/sync/index.ts"],"names":[],"mappings":"AAAA,kEAAkE;AAClE,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,uBAAuB,CAAC;AACtC,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mxpicture/tesla-superchargers-api",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Fetch + store Tesla Supercharger locations and pricing",
5
5
  "type": "module",
6
6
  "author": "MXPicture",
@@ -19,6 +19,10 @@
19
19
  "types": "./src/common/index.ts",
20
20
  "default": "./dist/common/index.js"
21
21
  },
22
+ "./sync": {
23
+ "types": "./src/sync/index.ts",
24
+ "default": "./dist/sync/index.js"
25
+ },
22
26
  "./types": {
23
27
  "types": "./src/types/index.ts",
24
28
  "default": "./dist/types/index.js"
@@ -40,9 +44,11 @@
40
44
  "access": "public"
41
45
  },
42
46
  "dependencies": {
43
- "@mxpicture/tesla-superchargers-generated": "^0.1.3",
44
- "@mxpicture/tesla-superchargers-mate": "^0.1.3",
45
- "json5": "^2.2.3"
47
+ "@mxpicture/tesla-superchargers-generated": "^0.1.4",
48
+ "@mxpicture/tesla-superchargers-mate": "^0.1.4",
49
+ "csv-parse": "^7.0.1",
50
+ "json5": "^2.2.3",
51
+ "zod": "^4.4.3"
46
52
  },
47
53
  "devDependencies": {
48
54
  "@types/node": "^25.2.3",