@mxpicture/tesla-superchargers-api 0.1.1

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 (77) hide show
  1. package/dist/api/ChargersApi.d.ts +53 -0
  2. package/dist/api/ChargersApi.d.ts.map +1 -0
  3. package/dist/api/ChargersApi.js +173 -0
  4. package/dist/api/ChargersApi.js.map +1 -0
  5. package/dist/api/ChargingProcessesApi.d.ts +11 -0
  6. package/dist/api/ChargingProcessesApi.d.ts.map +1 -0
  7. package/dist/api/ChargingProcessesApi.js +56 -0
  8. package/dist/api/ChargingProcessesApi.js.map +1 -0
  9. package/dist/api/FailuresApi.d.ts +38 -0
  10. package/dist/api/FailuresApi.d.ts.map +1 -0
  11. package/dist/api/FailuresApi.js +88 -0
  12. package/dist/api/FailuresApi.js.map +1 -0
  13. package/dist/api/IApi.d.ts +6 -0
  14. package/dist/api/IApi.d.ts.map +1 -0
  15. package/dist/api/IApi.js +11 -0
  16. package/dist/api/IApi.js.map +1 -0
  17. package/dist/api/SlugsApi.d.ts +15 -0
  18. package/dist/api/SlugsApi.d.ts.map +1 -0
  19. package/dist/api/SlugsApi.js +68 -0
  20. package/dist/api/SlugsApi.js.map +1 -0
  21. package/dist/api/index.d.ts +6 -0
  22. package/dist/api/index.d.ts.map +1 -0
  23. package/dist/api/index.js +7 -0
  24. package/dist/api/index.js.map +1 -0
  25. package/dist/common/chargers.common.d.ts +11 -0
  26. package/dist/common/chargers.common.d.ts.map +1 -0
  27. package/dist/common/chargers.common.js +11 -0
  28. package/dist/common/chargers.common.js.map +1 -0
  29. package/dist/common/failures.common.d.ts +8 -0
  30. package/dist/common/failures.common.d.ts.map +1 -0
  31. package/dist/common/failures.common.js +33 -0
  32. package/dist/common/failures.common.js.map +1 -0
  33. package/dist/common/index.d.ts +6 -0
  34. package/dist/common/index.d.ts.map +1 -0
  35. package/dist/common/index.js +7 -0
  36. package/dist/common/index.js.map +1 -0
  37. package/dist/common/pricebooks.common.d.ts +47 -0
  38. package/dist/common/pricebooks.common.d.ts.map +1 -0
  39. package/dist/common/pricebooks.common.js +95 -0
  40. package/dist/common/pricebooks.common.js.map +1 -0
  41. package/dist/common/pushover.common.d.ts +23 -0
  42. package/dist/common/pushover.common.d.ts.map +1 -0
  43. package/dist/common/pushover.common.js +52 -0
  44. package/dist/common/pushover.common.js.map +1 -0
  45. package/dist/common/sync.common.d.ts +51 -0
  46. package/dist/common/sync.common.d.ts.map +1 -0
  47. package/dist/common/sync.common.js +106 -0
  48. package/dist/common/sync.common.js.map +1 -0
  49. package/dist/types/chargers.types.d.ts +8 -0
  50. package/dist/types/chargers.types.d.ts.map +1 -0
  51. package/dist/types/chargers.types.js +2 -0
  52. package/dist/types/chargers.types.js.map +1 -0
  53. package/dist/types/charging.types.d.ts +15 -0
  54. package/dist/types/charging.types.d.ts.map +1 -0
  55. package/dist/types/charging.types.js +2 -0
  56. package/dist/types/charging.types.js.map +1 -0
  57. package/dist/types/failures.types.d.ts +19 -0
  58. package/dist/types/failures.types.d.ts.map +1 -0
  59. package/dist/types/failures.types.js +2 -0
  60. package/dist/types/failures.types.js.map +1 -0
  61. package/dist/types/index.d.ts +7 -0
  62. package/dist/types/index.d.ts.map +1 -0
  63. package/dist/types/index.js +8 -0
  64. package/dist/types/index.js.map +1 -0
  65. package/dist/types/pricebooks.types.d.ts +28 -0
  66. package/dist/types/pricebooks.types.d.ts.map +1 -0
  67. package/dist/types/pricebooks.types.js +2 -0
  68. package/dist/types/pricebooks.types.js.map +1 -0
  69. package/dist/types/pushover.types.d.ts +12 -0
  70. package/dist/types/pushover.types.d.ts.map +1 -0
  71. package/dist/types/pushover.types.js +2 -0
  72. package/dist/types/pushover.types.js.map +1 -0
  73. package/dist/types/sync.types.d.ts +22 -0
  74. package/dist/types/sync.types.d.ts.map +1 -0
  75. package/dist/types/sync.types.js +2 -0
  76. package/dist/types/sync.types.js.map +1 -0
  77. package/package.json +52 -0
@@ -0,0 +1,53 @@
1
+ import { type PicChargers, type PicPricebooks, type PicSlugsId } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { type TeslaClientCharger } from "@mxpicture/tesla-superchargers-mate/client";
3
+ import type { CoordinateAny } from "@mxpicture/tesla-superchargers-mate/common";
4
+ import { IApi } from "./IApi.js";
5
+ import type { SyncSummary } from "../types/sync.types.js";
6
+ export declare class ChargersApi extends IApi {
7
+ /**
8
+ * Find the Supercharger at a coordinate: try the nearby slug rows
9
+ * (slugs first — their location_url_slug is the canonical details slug),
10
+ * answer from the db when the cached charger is fresh, otherwise fetch and
11
+ * store it via the chargers sync. Candidates whose failure_count reached
12
+ * {@link FAILURE_DEPRIORITIZE_THRESHOLD} are tried last (still by
13
+ * distance within each bucket). Returns the first confirmed charger; a
14
+ * failed fetch bumps the source row's failure_count and moves on. A stale
15
+ * cached charger is returned rather than nothing when its refresh fails or
16
+ * the fetch budget is spent.
17
+ */
18
+ find(item: CoordinateAny, locale?: string): Promise<PicChargers | null>;
19
+ /**
20
+ * The pricebook rows valid at `at` for the Supercharger at a coordinate.
21
+ * The charger is resolved from the stored rows first — soft-deleted
22
+ * included, since a site Tesla removed from the feed has no slug left to
23
+ * resolve but its price history stays valid for past dates. Stored history
24
+ * fully answers any `at` up to the row's last fetch; only when there is no
25
+ * stored charger, or `at` lies after a stale row's last fetch, does the
26
+ * slug-based lookup (which may fetch and store the site on demand) run,
27
+ * falling back to the stored row when it finds nothing. From the resolved
28
+ * charger the pricebook group valid at `at` is taken and filtered to the
29
+ * rows whose time-of-use window covers `at` in the charger's time zone.
30
+ * All variants (member/non-member × vehicle make × fee type) are returned.
31
+ * When `at` predates the first recorded group (always the case right after
32
+ * a fetch-on-demand stored the charger's first group), that earliest group
33
+ * is used as the best available estimate.
34
+ */
35
+ findPrices(item: CoordinateAny, at: Date): Promise<PicPricebooks[]>;
36
+ initialLoadFile(path: string): Promise<void>;
37
+ /**
38
+ * Fetch one charger by its details slug and upsert it on `location_guid`,
39
+ * recording its pricebooks as history in the same transaction: when no
40
+ * price changed, the current group is only re-stamped with the fetch's
41
+ * uuid; when one did, a new group is inserted and the old rows stay as
42
+ * history. A successful fetch resurrects the row and resets
43
+ * `failure_count`; `ids` links it to the slug rows it was found through
44
+ * (existing links are kept when `ids` is omitted). Throws when the
45
+ * endpoint returns no charger.
46
+ */
47
+ syncLoad(slug: string, locale: string, slugsId?: PicSlugsId): Promise<PicChargers>;
48
+ /** Snapshot sync from a full-feed file dump. Does not touch pricebooks. */
49
+ syncLoadFile(path: string): Promise<SyncSummary>;
50
+ protected _syncLoad(clientDocs: TeslaClientCharger[]): Promise<SyncSummary>;
51
+ }
52
+ export declare const chargersApi: () => ChargersApi;
53
+ //# sourceMappingURL=ChargersApi.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,173 @@
1
+ import { createMeta, chargerToInitializer, pricebookToInitializer, } from "@mxpicture/tesla-superchargers-mate/transform";
2
+ import { readFile } from "node:fs/promises";
3
+ import json5 from "json5";
4
+ import { picChargersInitializerKeys, } from "@mxpicture/tesla-superchargers-generated/public";
5
+ import { teslaClient, teslaClientChargersSchema, } from "@mxpicture/tesla-superchargers-mate/client";
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";
8
+ import { IApi } from "./IApi.js";
9
+ import { syncColumns, syncSnapshot } from "../common/sync.common.js";
10
+ import { pricebookCoversInstant, samePricebookGroup, } from "../common/pricebooks.common.js";
11
+ export class ChargersApi extends IApi {
12
+ /**
13
+ * Find the Supercharger at a coordinate: try the nearby slug rows
14
+ * (slugs first — their location_url_slug is the canonical details slug),
15
+ * answer from the db when the cached charger is fresh, otherwise fetch and
16
+ * store it via the chargers sync. Candidates whose failure_count reached
17
+ * {@link FAILURE_DEPRIORITIZE_THRESHOLD} are tried last (still by
18
+ * distance within each bucket). Returns the first confirmed charger; a
19
+ * failed fetch bumps the source row's failure_count and moves on. A stale
20
+ * cached charger is returned rather than nothing when its refresh fails or
21
+ * the fetch budget is spent.
22
+ */
23
+ async find(item, locale = "de-DE") {
24
+ const founds = await picSlugsStore().findByCoordinate(item);
25
+ const candidates = founds.map((found) => ({
26
+ slug: found.location_url_slug,
27
+ slugsId: found.id,
28
+ failureCount: found.failure_count,
29
+ }));
30
+ // deprioritize (not skip) repeat failers; the sort is stable, so the
31
+ // nearest-first order is kept within each bucket
32
+ candidates.sort((a, b) => Number(a.failureCount >= FAILURE_DEPRIORITIZE_THRESHOLD) -
33
+ Number(b.failureCount >= FAILURE_DEPRIORITIZE_THRESHOLD));
34
+ const seen = new Set();
35
+ let fetches = 0;
36
+ const chargersStore = picChargersStore();
37
+ const slugsStore = picSlugsStore();
38
+ for (const candidate of candidates) {
39
+ if (seen.has(candidate.slug))
40
+ continue;
41
+ seen.add(candidate.slug);
42
+ const cached = await chargersStore.getBySlug(candidate.slugsId);
43
+ if (cached && isFresh(cached))
44
+ return cached;
45
+ if (fetches >= MAX_CHARGER_FETCHES) {
46
+ if (cached)
47
+ return cached; // stale beats nothing
48
+ continue;
49
+ }
50
+ fetches++;
51
+ try {
52
+ const charger = await this.syncLoad(candidate.slug, locale, candidate.slugsId);
53
+ if (charger.failure_count > 0)
54
+ await chargersStore.resetFailed(charger.id);
55
+ await slugsStore.resetFailed(candidate.slugsId);
56
+ return charger;
57
+ }
58
+ catch {
59
+ // record the failure where it happened: a failed refresh on the
60
+ // charger row, a failed first fetch on the slug row
61
+ if (cached) {
62
+ cached.failure_count = await chargersStore.incrementFailed(cached.id);
63
+ return cached; // stale beats nothing
64
+ }
65
+ candidate.failureCount = await slugsStore.incrementFailed(candidate.slugsId);
66
+ }
67
+ }
68
+ return null;
69
+ }
70
+ /**
71
+ * The pricebook rows valid at `at` for the Supercharger at a coordinate.
72
+ * The charger is resolved from the stored rows first — soft-deleted
73
+ * included, since a site Tesla removed from the feed has no slug left to
74
+ * resolve but its price history stays valid for past dates. Stored history
75
+ * fully answers any `at` up to the row's last fetch; only when there is no
76
+ * stored charger, or `at` lies after a stale row's last fetch, does the
77
+ * slug-based lookup (which may fetch and store the site on demand) run,
78
+ * falling back to the stored row when it finds nothing. From the resolved
79
+ * charger the pricebook group valid at `at` is taken and filtered to the
80
+ * rows whose time-of-use window covers `at` in the charger's time zone.
81
+ * All variants (member/non-member × vehicle make × fee type) are returned.
82
+ * When `at` predates the first recorded group (always the case right after
83
+ * a fetch-on-demand stored the charger's first group), that earliest group
84
+ * is used as the best available estimate.
85
+ */
86
+ async findPrices(item, at) {
87
+ const stored = (await picChargersStore().findByCoordinate(item))[0] ?? null;
88
+ let charger = stored;
89
+ if (!stored || (at > stored.fetched_at && !isFresh(stored)))
90
+ charger = (await this.find(item)) ?? stored;
91
+ if (!charger)
92
+ return [];
93
+ const pricebooksStore = picPricebooksStore();
94
+ const group = await pricebooksStore.getGroupAt(charger.id, at);
95
+ const rows = group.length > 0
96
+ ? group
97
+ : await pricebooksStore.getEarliestGroup(charger.id);
98
+ return rows.filter((row) => pricebookCoversInstant(row, at, charger.time_zone));
99
+ }
100
+ async initialLoadFile(path) {
101
+ const json = json5.parse(await readFile(path, { encoding: "utf8" }));
102
+ const meta = createMeta();
103
+ await this.initialInserts(picChargersStore(), teslaClientChargersSchema.parse(json), (charger) => chargerToInitializer({ charger, meta }));
104
+ }
105
+ /**
106
+ * Fetch one charger by its details slug and upsert it on `location_guid`,
107
+ * recording its pricebooks as history in the same transaction: when no
108
+ * price changed, the current group is only re-stamped with the fetch's
109
+ * uuid; when one did, a new group is inserted and the old rows stay as
110
+ * history. A successful fetch resurrects the row and resets
111
+ * `failure_count`; `ids` links it to the slug rows it was found through
112
+ * (existing links are kept when `ids` is omitted). Throws when the
113
+ * endpoint returns no charger.
114
+ */
115
+ async syncLoad(slug, locale, slugsId) {
116
+ const clientDoc = await teslaClient().fetchCharger(slug, locale);
117
+ if (!clientDoc.charger)
118
+ throw new Error(`charger fetch for slug "${slug}" returned no charger` +
119
+ (clientDoc.reason ? `: ${clientDoc.reason}` : "") +
120
+ ` (${clientDoc.attempts} attempts)`);
121
+ const charger = clientDoc.charger;
122
+ const meta = createMeta();
123
+ const init = chargerToInitializer({ charger, meta, slugsId });
124
+ const chargersStore = picChargersStore();
125
+ const pricebooksStore = picPricebooksStore();
126
+ return await transaction(chargersStore.table, async (tx) => {
127
+ const row = await chargersStore.upsertOne(init,
128
+ // update only the columns present in the initializer, so omitted ids
129
+ // don't overwrite existing FK links with NULL
130
+ { conflictColumn: "location_guid", updateColumns: Object.keys(init) }, tx);
131
+ const current = await pricebooksStore.getCurrentGroup(row.id, tx);
132
+ const next = charger.effectivePricebooks.map((pricebook) => pricebookToInitializer({ pricebook, meta, chargersId: row.id }));
133
+ if (next.length === 0) {
134
+ // an empty group cannot be represented by rows — keep the last
135
+ // known prices instead of pretending they vanished
136
+ if (current.length > 0)
137
+ console.warn(`charger ${row.id} (slug "${slug}"): fetch returned no pricebooks — keeping last known prices`);
138
+ }
139
+ else if (samePricebookGroup(current, next)) {
140
+ // current is non-empty here: next is non-empty and the groups match
141
+ await pricebooksStore.updateGroupFetchUuid(row.id, current[0].last_fetch_uuid, meta.last_fetch_uuid, tx);
142
+ }
143
+ else {
144
+ await pricebooksStore.insertMany(next, tx);
145
+ }
146
+ return row;
147
+ });
148
+ }
149
+ /** Snapshot sync from a full-feed file dump. Does not touch pricebooks. */
150
+ async syncLoadFile(path) {
151
+ const json = json5.parse(await readFile(path, { encoding: "utf8" }));
152
+ return await this._syncLoad(teslaClientChargersSchema.parse(json));
153
+ }
154
+ async _syncLoad(clientDocs) {
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
+ });
169
+ }
170
+ }
171
+ let _api = null;
172
+ export const chargersApi = () => (_api ??= new ChargersApi());
173
+ //# sourceMappingURL=ChargersApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChargersApi.js","sourceRoot":"","sources":["../../src/api/ChargersApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { type ChargingProcesses, type ChargingProcessesId } from "@mxpicture/tesla-superchargers-generated/public";
2
+ import type { UnpricedChargingProcess } from "@mxpicture/tesla-superchargers-mate/types";
3
+ import type { PricingSummary } from "../types/charging.types.js";
4
+ import { IApi } from "./IApi.js";
5
+ export declare class ChargingProcessesApi extends IApi {
6
+ runPricing(): Promise<PricingSummary>;
7
+ getUnpricedCharges(): Promise<UnpricedChargingProcess[]>;
8
+ updatePrice(processId: ChargingProcessesId, cost: number | null): Promise<ChargingProcesses>;
9
+ }
10
+ export declare const chargingProcessesApi: () => ChargingProcessesApi;
11
+ //# sourceMappingURL=ChargingProcessesApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChargingProcessesApi.d.ts","sourceRoot":"","sources":["../../src/api/ChargingProcessesApi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACzB,MAAM,iDAAiD,CAAC;AAEzD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,2CAA2C,CAAC;AAEzF,OAAO,KAAK,EACV,cAAc,EAEf,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAIjC,qBAAa,oBAAqB,SAAQ,IAAI;IAC/B,UAAU,IAAI,OAAO,CAAC,cAAc,CAAC;IAoDrC,kBAAkB,IAAI,OAAO,CAAC,uBAAuB,EAAE,CAAC;IAIxD,WAAW,CACtB,SAAS,EAAE,mBAAmB,EAC9B,IAAI,EAAE,MAAM,GAAG,IAAI,GAClB,OAAO,CAAC,iBAAiB,CAAC;CAG9B;AAGD,eAAO,MAAM,oBAAoB,4BAA8C,CAAC"}
@@ -0,0 +1,56 @@
1
+ import {} from "@mxpicture/tesla-superchargers-generated/public";
2
+ import { chargingProcessesStore } from "@mxpicture/tesla-superchargers-mate/store";
3
+ import { chargersApi } from "./ChargersApi.js";
4
+ import { IApi } from "./IApi.js";
5
+ import { teslaChargingRate } from "../common/pricebooks.common.js";
6
+ import { FAILURE_DEPRIORITIZE_THRESHOLD } from "../common/chargers.common.js";
7
+ export class ChargingProcessesApi extends IApi {
8
+ async runPricing() {
9
+ const store = chargingProcessesStore();
10
+ const charges = await this.getUnpricedCharges();
11
+ const summary = {
12
+ unpricedCharges: charges.length,
13
+ items: [],
14
+ };
15
+ for (const charge of charges) {
16
+ const item = { charge, topic: "unknown" };
17
+ summary.items.push(item);
18
+ if (charge.failure_count &&
19
+ charge.failure_count >= FAILURE_DEPRIORITIZE_THRESHOLD) {
20
+ item.topic = "failureLimitReached";
21
+ continue;
22
+ }
23
+ const pricebooks = await chargersApi().findPrices({ latitude: charge.latitude, longitude: charge.longitude }, charge.start_date);
24
+ const rate = teslaChargingRate(pricebooks);
25
+ item.rate = rate;
26
+ if (!rate) {
27
+ item.topic = "noRate";
28
+ item.failure_count = await store.incrementStateFailed(item.charge.id);
29
+ continue;
30
+ }
31
+ const energy = charge.charge_energy_used ?? charge.charge_energy_added;
32
+ item.energy = energy;
33
+ if (energy === null || !Number.isFinite(Number(energy))) {
34
+ item.topic = "noEnergyValue";
35
+ item.failure_count = await store.incrementStateFailed(item.charge.id);
36
+ continue;
37
+ }
38
+ const cost = Number((rate.rate * Number(energy)).toFixed(2));
39
+ item.cost = cost;
40
+ await chargingProcessesApi().updatePrice(charge.id, cost);
41
+ item.topic = "chargeUpdated";
42
+ item.failure_count = 0;
43
+ await store.resetState(item.charge.id);
44
+ }
45
+ return summary;
46
+ }
47
+ async getUnpricedCharges() {
48
+ return await chargingProcessesStore().getUnpricedCharges();
49
+ }
50
+ async updatePrice(processId, cost) {
51
+ return await chargingProcessesStore().updatePrice(processId, cost);
52
+ }
53
+ }
54
+ let _api = null;
55
+ export const chargingProcessesApi = () => (_api ??= new ChargingProcessesApi());
56
+ //# sourceMappingURL=ChargingProcessesApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ChargingProcessesApi.js","sourceRoot":"","sources":["../../src/api/ChargingProcessesApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,MAAM,iDAAiD,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,2CAA2C,CAAC;AAEnF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAK/C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,8BAA8B,EAAE,MAAM,8BAA8B,CAAC;AAE9E,MAAM,OAAO,oBAAqB,SAAQ,IAAI;IACrC,KAAK,CAAC,UAAU;QACrB,MAAM,KAAK,GAAG,sBAAsB,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,kBAAkB,EAAE,CAAC;QAEhD,MAAM,OAAO,GAAmB;YAC9B,eAAe,EAAE,OAAO,CAAC,MAAM;YAC/B,KAAK,EAAE,EAAE;SACV,CAAC;QAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,MAAM,IAAI,GAAuB,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,CAAC;YAC9D,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAEzB,IACE,MAAM,CAAC,aAAa;gBACpB,MAAM,CAAC,aAAa,IAAI,8BAA8B,EACtD,CAAC;gBACD,IAAI,CAAC,KAAK,GAAG,qBAAqB,CAAC;gBACnC,SAAS;YACX,CAAC;YAED,MAAM,UAAU,GAAG,MAAM,WAAW,EAAE,CAAC,UAAU,CAC/C,EAAE,QAAQ,EAAE,MAAM,CAAC,QAAQ,EAAE,SAAS,EAAE,MAAM,CAAC,SAAS,EAAE,EAC1D,MAAM,CAAC,UAAU,CAClB,CAAC;YACF,MAAM,IAAI,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;YAC3C,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,IAAI,CAAC,KAAK,GAAG,QAAQ,CAAC;gBACtB,IAAI,CAAC,aAAa,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACtE,SAAS;YACX,CAAC;YAED,MAAM,MAAM,GAAG,MAAM,CAAC,kBAAkB,IAAI,MAAM,CAAC,mBAAmB,CAAC;YACvE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;YACrB,IAAI,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;gBACxD,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC;gBAC7B,IAAI,CAAC,aAAa,GAAG,MAAM,KAAK,CAAC,oBAAoB,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;gBACtE,SAAS;YACX,CAAC;YAED,MAAM,IAAI,GAAG,MAAM,CAAC,CAAC,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7D,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;YACjB,MAAM,oBAAoB,EAAE,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;YAC1D,IAAI,CAAC,KAAK,GAAG,eAAe,CAAC;YAC7B,IAAI,CAAC,aAAa,GAAG,CAAC,CAAC;YACvB,MAAM,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACzC,CAAC;QAED,OAAO,OAAO,CAAC;IACjB,CAAC;IAEM,KAAK,CAAC,kBAAkB;QAC7B,OAAO,MAAM,sBAAsB,EAAE,CAAC,kBAAkB,EAAE,CAAC;IAC7D,CAAC;IAEM,KAAK,CAAC,WAAW,CACtB,SAA8B,EAC9B,IAAmB;QAEnB,OAAO,MAAM,sBAAsB,EAAE,CAAC,WAAW,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IACrE,CAAC;CACF;AAED,IAAI,IAAI,GAAgC,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,oBAAoB,GAAG,GAAG,EAAE,CAAC,CAAC,IAAI,KAAK,IAAI,oBAAoB,EAAE,CAAC,CAAC"}
@@ -0,0 +1,38 @@
1
+ import { IApi } from "./IApi.js";
2
+ import type { FailedSources, FailureNotifySummary, FailureSource } from "../types/failures.types.js";
3
+ /**
4
+ * Inspect, reset and page about the failing rows across the three
5
+ * failure-tracked sources (charges, chargers, slugs). Notification semantics:
6
+ * a row is paged once when it crosses the threshold; a growing count never
7
+ * re-pages, only a reset (successful fetch/pricing or a manual reset) re-arms.
8
+ */
9
+ export declare class FailuresApi extends IApi {
10
+ /**
11
+ * Failing rows for one source or all three, at or above `threshold`. With
12
+ * `onlyUnnotified` only rows not yet paged are returned; non-requested
13
+ * sources stay empty.
14
+ */
15
+ getFailed(source: FailureSource | "all", threshold?: number, onlyUnnotified?: boolean): Promise<FailedSources>;
16
+ /**
17
+ * Reset one row's failure state. For charges the id is the
18
+ * `charging_processes_id` and the reset deletes the state row; for
19
+ * chargers/slugs the id is the row id.
20
+ */
21
+ resetFailed(source: FailureSource, id: string): Promise<void>;
22
+ /** Reset every failing row for one source or all three; returns per-source counts. */
23
+ resetAllFailed(source: FailureSource | "all"): Promise<{
24
+ charges: number;
25
+ chargers: number;
26
+ slugs: number;
27
+ }>;
28
+ /**
29
+ * Page (Pushover) about not-yet-notified failures at or above `threshold`,
30
+ * each failure exactly once: on a successful send the included rows get their
31
+ * `failure_notified_at` stamped so a growing count never re-pages. A no-op
32
+ * (nothing sent, nothing marked) when there is nothing to report or Pushover
33
+ * is unconfigured; the per-source counts are reported either way.
34
+ */
35
+ notifyFailures(threshold?: number, logger?: (m: string) => void): Promise<FailureNotifySummary>;
36
+ }
37
+ export declare const failuresApi: () => FailuresApi;
38
+ //# sourceMappingURL=FailuresApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FailuresApi.d.ts","sourceRoot":"","sources":["../../src/api/FailuresApi.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,KAAK,EACV,aAAa,EACb,oBAAoB,EACpB,aAAa,EACd,MAAM,4BAA4B,CAAC;AAEpC;;;;;GAKG;AACH,qBAAa,WAAY,SAAQ,IAAI;IACnC;;;;OAIG;IACU,SAAS,CACpB,MAAM,EAAE,aAAa,GAAG,KAAK,EAC7B,SAAS,GAAE,MAAuC,EAClD,cAAc,UAAQ,GACrB,OAAO,CAAC,aAAa,CAAC;IAmBzB;;;;OAIG;IACU,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAc1E,sFAAsF;IACzE,cAAc,CACzB,MAAM,EAAE,aAAa,GAAG,KAAK,GAC5B,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC;IAahE;;;;;;OAMG;IACU,cAAc,CACzB,SAAS,GAAE,MAAuC,EAClD,MAAM,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAe,GACrC,OAAO,CAAC,oBAAoB,CAAC;CAwBjC;AAGD,eAAO,MAAM,WAAW,mBAAqC,CAAC"}
@@ -0,0 +1,88 @@
1
+ import { chargingProcessesStore, picChargersStore, picSlugsStore, } from "@mxpicture/tesla-superchargers-mate/store";
2
+ import { FAILURE_DEPRIORITIZE_THRESHOLD } from "../common/chargers.common.js";
3
+ import { buildFailureMessage } from "../common/failures.common.js";
4
+ import { pushoverConfigFromEnv, sendPushover, } from "../common/pushover.common.js";
5
+ import { IApi } from "./IApi.js";
6
+ /**
7
+ * Inspect, reset and page about the failing rows across the three
8
+ * failure-tracked sources (charges, chargers, slugs). Notification semantics:
9
+ * a row is paged once when it crosses the threshold; a growing count never
10
+ * re-pages, only a reset (successful fetch/pricing or a manual reset) re-arms.
11
+ */
12
+ export class FailuresApi extends IApi {
13
+ /**
14
+ * Failing rows for one source or all three, at or above `threshold`. With
15
+ * `onlyUnnotified` only rows not yet paged are returned; non-requested
16
+ * sources stay empty.
17
+ */
18
+ async getFailed(source, threshold = FAILURE_DEPRIORITIZE_THRESHOLD, onlyUnnotified = false) {
19
+ const result = { charges: [], chargers: [], slugs: [] };
20
+ if (source === "all" || source === "charges")
21
+ result.charges = await chargingProcessesStore().getFailedStates(threshold, onlyUnnotified);
22
+ if (source === "all" || source === "chargers")
23
+ result.chargers = await picChargersStore().getFailed(threshold, onlyUnnotified);
24
+ if (source === "all" || source === "slugs")
25
+ result.slugs = await picSlugsStore().getFailed(threshold, onlyUnnotified);
26
+ return result;
27
+ }
28
+ /**
29
+ * Reset one row's failure state. For charges the id is the
30
+ * `charging_processes_id` and the reset deletes the state row; for
31
+ * chargers/slugs the id is the row id.
32
+ */
33
+ async resetFailed(source, id) {
34
+ switch (source) {
35
+ case "charges":
36
+ await chargingProcessesStore().resetState(Number(id));
37
+ return;
38
+ case "chargers":
39
+ await picChargersStore().resetFailed(id);
40
+ return;
41
+ case "slugs":
42
+ await picSlugsStore().resetFailed(id);
43
+ return;
44
+ }
45
+ }
46
+ /** Reset every failing row for one source or all three; returns per-source counts. */
47
+ async resetAllFailed(source) {
48
+ const counts = { charges: 0, chargers: 0, slugs: 0 };
49
+ if (source === "all" || source === "charges")
50
+ counts.charges = await chargingProcessesStore().resetAllStates();
51
+ if (source === "all" || source === "chargers")
52
+ counts.chargers = await picChargersStore().resetAllFailed();
53
+ if (source === "all" || source === "slugs")
54
+ counts.slugs = await picSlugsStore().resetAllFailed();
55
+ return counts;
56
+ }
57
+ /**
58
+ * Page (Pushover) about not-yet-notified failures at or above `threshold`,
59
+ * each failure exactly once: on a successful send the included rows get their
60
+ * `failure_notified_at` stamped so a growing count never re-pages. A no-op
61
+ * (nothing sent, nothing marked) when there is nothing to report or Pushover
62
+ * is unconfigured; the per-source counts are reported either way.
63
+ */
64
+ async notifyFailures(threshold = FAILURE_DEPRIORITIZE_THRESHOLD, logger = () => { }) {
65
+ const cfg = pushoverConfigFromEnv();
66
+ const failed = await this.getFailed("all", threshold, true);
67
+ const summary = {
68
+ configured: cfg != null,
69
+ sent: false,
70
+ charges: failed.charges.length,
71
+ chargers: failed.chargers.length,
72
+ slugs: failed.slugs.length,
73
+ };
74
+ const message = buildFailureMessage(failed);
75
+ if (!message || !cfg)
76
+ return summary;
77
+ if (!(await sendPushover(cfg, message, logger)))
78
+ return summary;
79
+ summary.sent = true;
80
+ await chargingProcessesStore().markStatesNotified(failed.charges.map((c) => c.id));
81
+ await picChargersStore().markNotified(failed.chargers.map((c) => c.id));
82
+ await picSlugsStore().markNotified(failed.slugs.map((s) => s.id));
83
+ return summary;
84
+ }
85
+ }
86
+ let _api = null;
87
+ export const failuresApi = () => (_api ??= new FailuresApi());
88
+ //# sourceMappingURL=FailuresApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"FailuresApi.js","sourceRoot":"","sources":["../../src/api/FailuresApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import { type IMateStore } from "@mxpicture/tesla-superchargers-mate/store";
2
+ export declare abstract class IApi {
3
+ constructor();
4
+ protected initialInserts<T extends object, INITIALZER extends object, STORE extends IMateStore<any, any, INITIALZER, any>>(store: STORE, rows: T[], transform: (row: T) => INITIALZER): Promise<number>;
5
+ }
6
+ //# sourceMappingURL=IApi.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IApi.d.ts","sourceRoot":"","sources":["../../src/api/IApi.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,UAAU,EAChB,MAAM,2CAA2C,CAAC;AAEnD,8BAAsB,IAAI;;cAGR,cAAc,CAC5B,CAAC,SAAS,MAAM,EAChB,UAAU,SAAS,MAAM,EAEzB,KAAK,SAAS,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,UAAU,EAAE,GAAG,CAAC,EAEnD,KAAK,EAAE,KAAK,EACZ,IAAI,EAAE,CAAC,EAAE,EACT,SAAS,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,UAAU,GAChC,OAAO,CAAC,MAAM,CAAC;CAMnB"}
@@ -0,0 +1,11 @@
1
+ import { transaction, } from "@mxpicture/tesla-superchargers-mate/store";
2
+ export class IApi {
3
+ constructor() { }
4
+ async initialInserts(store, rows, transform) {
5
+ return await transaction(store.table, async (tx) => {
6
+ await store.deleteAll(tx);
7
+ return await store.insertMany(rows.map(transform), tx);
8
+ });
9
+ }
10
+ }
11
+ //# sourceMappingURL=IApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"IApi.js","sourceRoot":"","sources":["../../src/api/IApi.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,WAAW,GAEZ,MAAM,2CAA2C,CAAC;AAEnD,MAAM,OAAgB,IAAI;IACxB,gBAAsB,CAAC;IAEb,KAAK,CAAC,cAAc,CAM5B,KAAY,EACZ,IAAS,EACT,SAAiC;QAEjC,OAAO,MAAM,WAAW,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE;YACjD,MAAM,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;YAC1B,OAAO,MAAM,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACL,CAAC;CACF"}
@@ -0,0 +1,15 @@
1
+ import type { TeslaClientSlug } from "@mxpicture/tesla-superchargers-mate/client";
2
+ import type { CoordinateAny } from "@mxpicture/tesla-superchargers-mate/common";
3
+ import type { PicSlugsDistance } from "@mxpicture/tesla-superchargers-mate/types";
4
+ import { IApi } from "./IApi.js";
5
+ import type { SyncSummary } from "../types/sync.types.js";
6
+ export declare class SlugsApi extends IApi {
7
+ find(item: CoordinateAny): Promise<PicSlugsDistance[]>;
8
+ initialLoad(): Promise<SyncSummary>;
9
+ initialLoadFile(path: string): Promise<SyncSummary>;
10
+ syncLoad(): Promise<SyncSummary>;
11
+ syncLoadFile(path: string): Promise<SyncSummary>;
12
+ protected _syncLoad(clientDocs: TeslaClientSlug[]): Promise<SyncSummary>;
13
+ }
14
+ export declare const slugsApi: () => SlugsApi;
15
+ //# sourceMappingURL=SlugsApi.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,68 @@
1
+ import { parseTeslaClientSlugs, teslaClient, } from "@mxpicture/tesla-superchargers-mate/client";
2
+ import { createMeta, slugToInitializer, } from "@mxpicture/tesla-superchargers-mate/transform";
3
+ import { readFile } from "node:fs/promises";
4
+ import json5 from "json5";
5
+ import { picSlugsInitializerKeys } from "@mxpicture/tesla-superchargers-generated/public";
6
+ import { picSlugsStore } from "@mxpicture/tesla-superchargers-mate/store";
7
+ import { IApi } from "./IApi.js";
8
+ import { syncSnapshot, syncColumns } from "../common/sync.common.js";
9
+ /** Per-element parse of a slugs file dump; invalid entries are skipped, not fatal. */
10
+ const readSlugsFile = async (path) => {
11
+ const json = json5.parse(await readFile(path, { encoding: "utf8" }));
12
+ const { slugs, invalid } = parseTeslaClientSlugs(json);
13
+ if (invalid > 0)
14
+ console.warn(`slugs file "${path}": skipped ${invalid} invalid entries`);
15
+ return slugs;
16
+ };
17
+ export class SlugsApi extends IApi {
18
+ async find(item) {
19
+ return await picSlugsStore().findByCoordinate(item);
20
+ }
21
+ async initialLoad() {
22
+ const meta = createMeta();
23
+ const count = await this.initialInserts(picSlugsStore(), await teslaClient().fetchSlugs(), (slug) => slugToInitializer({ slug, meta }));
24
+ return {
25
+ feedCount: count,
26
+ feedDuplicates: 0,
27
+ feedNullKeys: 0,
28
+ upserted: count,
29
+ deleted: 0,
30
+ };
31
+ }
32
+ async initialLoadFile(path) {
33
+ const meta = createMeta();
34
+ const count = await this.initialInserts(picSlugsStore(), await readSlugsFile(path), (slug) => slugToInitializer({ slug, meta }));
35
+ return {
36
+ feedCount: count,
37
+ feedDuplicates: 0,
38
+ feedNullKeys: 0,
39
+ upserted: count,
40
+ deleted: 0,
41
+ };
42
+ }
43
+ async syncLoad() {
44
+ const clientDocs = await teslaClient().fetchSlugs();
45
+ return await this._syncLoad(clientDocs);
46
+ }
47
+ async syncLoadFile(path) {
48
+ return await this._syncLoad(await readSlugsFile(path));
49
+ }
50
+ async _syncLoad(clientDocs) {
51
+ 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
+ });
64
+ }
65
+ }
66
+ let _api = null;
67
+ export const slugsApi = () => (_api ??= new SlugsApi());
68
+ //# sourceMappingURL=SlugsApi.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SlugsApi.js","sourceRoot":"","sources":["../../src/api/SlugsApi.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export * from "./ChargersApi.js";
2
+ export * from "./ChargingProcessesApi.js";
3
+ export * from "./FailuresApi.js";
4
+ export * from "./IApi.js";
5
+ export * from "./SlugsApi.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,7 @@
1
+ // This file is auto-generated by build-cli. Do not edit manually.
2
+ export * from "./ChargersApi.js";
3
+ export * from "./ChargingProcessesApi.js";
4
+ export * from "./FailuresApi.js";
5
+ export * from "./IApi.js";
6
+ export * from "./SlugsApi.js";
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"}
@@ -0,0 +1,11 @@
1
+ import type { PicChargers } from "@mxpicture/tesla-superchargers-generated/public";
2
+ /** Refetch a cached charger whose last fetch is older than this. */
3
+ export declare const CHARGER_STALE_AFTER_DAYS = 5;
4
+ /** Detail fetches per findByCoordinate call — the endpoint is slow and guarded. */
5
+ export declare const MAX_CHARGER_FETCHES = 3;
6
+ /** Candidates that failed this often are tried after the rest, so dead slugs stop burning the fetch budget first. */
7
+ export declare const FAILURE_DEPRIORITIZE_THRESHOLD = 3;
8
+ export declare const isFresh: (row: PicChargers) => boolean;
9
+ /** FK links are not part of the feed; a snapshot re-sync must not wipe them. */
10
+ export declare const withoutFkColumns: (columns: string[]) => string[];
11
+ //# sourceMappingURL=chargers.common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"chargers.common.d.ts","sourceRoot":"","sources":["../../src/common/chargers.common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iDAAiD,CAAC;AAEnF,oEAAoE;AACpE,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAErC,qHAAqH;AACrH,eAAO,MAAM,8BAA8B,IAAI,CAAC;AAEhD,eAAO,MAAM,OAAO,GAAI,KAAK,WAAW,KAAG,OAEkB,CAAC;AAE9D,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,GAAI,SAAS,MAAM,EAAE,KAAG,MAAM,EACJ,CAAC"}