@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.
- package/dist/api/ChargersApi.d.ts +53 -0
- package/dist/api/ChargersApi.d.ts.map +1 -0
- package/dist/api/ChargersApi.js +173 -0
- package/dist/api/ChargersApi.js.map +1 -0
- package/dist/api/ChargingProcessesApi.d.ts +11 -0
- package/dist/api/ChargingProcessesApi.d.ts.map +1 -0
- package/dist/api/ChargingProcessesApi.js +56 -0
- package/dist/api/ChargingProcessesApi.js.map +1 -0
- package/dist/api/FailuresApi.d.ts +38 -0
- package/dist/api/FailuresApi.d.ts.map +1 -0
- package/dist/api/FailuresApi.js +88 -0
- package/dist/api/FailuresApi.js.map +1 -0
- package/dist/api/IApi.d.ts +6 -0
- package/dist/api/IApi.d.ts.map +1 -0
- package/dist/api/IApi.js +11 -0
- package/dist/api/IApi.js.map +1 -0
- package/dist/api/SlugsApi.d.ts +15 -0
- package/dist/api/SlugsApi.d.ts.map +1 -0
- package/dist/api/SlugsApi.js +68 -0
- package/dist/api/SlugsApi.js.map +1 -0
- package/dist/api/index.d.ts +6 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +7 -0
- package/dist/api/index.js.map +1 -0
- package/dist/common/chargers.common.d.ts +11 -0
- package/dist/common/chargers.common.d.ts.map +1 -0
- package/dist/common/chargers.common.js +11 -0
- package/dist/common/chargers.common.js.map +1 -0
- package/dist/common/failures.common.d.ts +8 -0
- package/dist/common/failures.common.d.ts.map +1 -0
- package/dist/common/failures.common.js +33 -0
- package/dist/common/failures.common.js.map +1 -0
- package/dist/common/index.d.ts +6 -0
- package/dist/common/index.d.ts.map +1 -0
- package/dist/common/index.js +7 -0
- package/dist/common/index.js.map +1 -0
- package/dist/common/pricebooks.common.d.ts +47 -0
- package/dist/common/pricebooks.common.d.ts.map +1 -0
- package/dist/common/pricebooks.common.js +95 -0
- package/dist/common/pricebooks.common.js.map +1 -0
- package/dist/common/pushover.common.d.ts +23 -0
- package/dist/common/pushover.common.d.ts.map +1 -0
- package/dist/common/pushover.common.js +52 -0
- package/dist/common/pushover.common.js.map +1 -0
- package/dist/common/sync.common.d.ts +51 -0
- package/dist/common/sync.common.d.ts.map +1 -0
- package/dist/common/sync.common.js +106 -0
- package/dist/common/sync.common.js.map +1 -0
- package/dist/types/chargers.types.d.ts +8 -0
- package/dist/types/chargers.types.d.ts.map +1 -0
- package/dist/types/chargers.types.js +2 -0
- package/dist/types/chargers.types.js.map +1 -0
- package/dist/types/charging.types.d.ts +15 -0
- package/dist/types/charging.types.d.ts.map +1 -0
- package/dist/types/charging.types.js +2 -0
- package/dist/types/charging.types.js.map +1 -0
- package/dist/types/failures.types.d.ts +19 -0
- package/dist/types/failures.types.d.ts.map +1 -0
- package/dist/types/failures.types.js +2 -0
- package/dist/types/failures.types.js.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/pricebooks.types.d.ts +28 -0
- package/dist/types/pricebooks.types.d.ts.map +1 -0
- package/dist/types/pricebooks.types.js +2 -0
- package/dist/types/pricebooks.types.js.map +1 -0
- package/dist/types/pushover.types.d.ts +12 -0
- package/dist/types/pushover.types.d.ts.map +1 -0
- package/dist/types/pushover.types.js +2 -0
- package/dist/types/pushover.types.js.map +1 -0
- package/dist/types/sync.types.d.ts +22 -0
- package/dist/types/sync.types.d.ts.map +1 -0
- package/dist/types/sync.types.js +2 -0
- package/dist/types/sync.types.js.map +1 -0
- 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":"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"}
|
|
@@ -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"}
|
package/dist/api/IApi.js
ADDED
|
@@ -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 @@
|
|
|
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"}
|