@mxpicture/tesla-superchargers-cli 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.
@@ -0,0 +1,3 @@
1
+ /** Reads the CLI package version from its package.json. */
2
+ export declare const readVersion: () => string;
3
+ //# sourceMappingURL=cli.common.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.common.d.ts","sourceRoot":"","sources":["../src/cli.common.ts"],"names":[],"mappings":"AAMA,2DAA2D;AAC3D,eAAO,MAAM,WAAW,QAAO,MAET,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ /** Reads the CLI package version from its package.json. */
6
+ export const readVersion = () => JSON.parse(readFileSync(resolve(__dirname, "../package.json"), "utf8"))
7
+ .version;
8
+ //# sourceMappingURL=cli.common.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.common.js","sourceRoot":"","sources":["../src/cli.common.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE1D,2DAA2D;AAC3D,MAAM,CAAC,MAAM,WAAW,GAAG,GAAW,EAAE,CACtC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,SAAS,EAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC,CAAC;KACpE,OAAiB,CAAC"}
package/dist/cli.d.ts ADDED
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * teslamate-superchargers
4
+ * =======================
5
+ * Maintain a Tesla Supercharger price history in a TeslaMate Postgres
6
+ * database (the `pic_*` tables, see `setup.sql`), fed from the public
7
+ * tesla.com endpoints via `@mxpicture/tesla-superchargers-api`.
8
+ *
9
+ * init-load wipe + refill pic_slugs from the live map feed
10
+ * init-load-file wipe + refill pic_slugs from a json dump
11
+ * sync-load snapshot-sync pic_slugs against the live map feed
12
+ * sync-load-file snapshot-sync pic_slugs against a json dump
13
+ * find-slugs list the slug rows near a coordinate
14
+ * find-charger resolve the charger at a coordinate (fetches on demand)
15
+ * find-prices the prices valid at a coordinate + timestamp
16
+ * find-unpriced-charges list TeslaMate charges without a cost
17
+ * process-unpriced-charges backfill costs from the stored price history
18
+ * find-failures list failing rows across the failure-tracked sources
19
+ * reset-failures clear failure state for a row or a whole source
20
+ * notify-failures Pushover-alert about not-yet-notified failures
21
+ * schedule daemon: daily pricing + notify (optional slug sync)
22
+ *
23
+ * The database connection comes from the standard `PG*` environment
24
+ * variables (`PGHOST`, `PGPORT`, `PGDATABASE`, `PGUSER`, `PGPASSWORD`).
25
+ * Alerts need `PUSHOVER_API_TOKEN` / `PUSHOVER_USER_KEY` (off when unset).
26
+ */
27
+ export {};
28
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG"}
package/dist/cli.js ADDED
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * teslamate-superchargers
4
+ * =======================
5
+ * Maintain a Tesla Supercharger price history in a TeslaMate Postgres
6
+ * database (the `pic_*` tables, see `setup.sql`), fed from the public
7
+ * tesla.com endpoints via `@mxpicture/tesla-superchargers-api`.
8
+ *
9
+ * init-load wipe + refill pic_slugs from the live map feed
10
+ * init-load-file wipe + refill pic_slugs from a json dump
11
+ * sync-load snapshot-sync pic_slugs against the live map feed
12
+ * sync-load-file snapshot-sync pic_slugs against a json dump
13
+ * find-slugs list the slug rows near a coordinate
14
+ * find-charger resolve the charger at a coordinate (fetches on demand)
15
+ * find-prices the prices valid at a coordinate + timestamp
16
+ * find-unpriced-charges list TeslaMate charges without a cost
17
+ * process-unpriced-charges backfill costs from the stored price history
18
+ * find-failures list failing rows across the failure-tracked sources
19
+ * reset-failures clear failure state for a row or a whole source
20
+ * notify-failures Pushover-alert about not-yet-notified failures
21
+ * schedule daemon: daily pricing + notify (optional slug sync)
22
+ *
23
+ * The database connection comes from the standard `PG*` environment
24
+ * variables (`PGHOST`, `PGPORT`, `PGDATABASE`, `PGUSER`, `PGPASSWORD`).
25
+ * Alerts need `PUSHOVER_API_TOKEN` / `PUSHOVER_USER_KEY` (off when unset).
26
+ */
27
+ import { program } from "@commander-js/extra-typings";
28
+ import { argv, exit } from "node:process";
29
+ import { endSql } from "@mxpicture/tesla-superchargers-mate/store";
30
+ import { readVersion } from "./cli.common.js";
31
+ import { runInitLoad, runInitLoadByFile, runSyncLoad, runSyncLoadByFile, runFindSlugs, runFindCharger, runFindPrices, runFindUnpricedCharges, runProcessUnpricedCharges, runFindFailures, runResetFailures, runNotifyFailures, runSchedule, } from "./cli.run.js";
32
+ import { slugsJsonOption, latitudeOption, longitudeOption, timestampOption, sourceOption, thresholdOption, idOption, allOption, cronOption, syncCronOption, runOnStartOption, } from "./cli.option.js";
33
+ program
34
+ .name("teslamate-superchargers")
35
+ .version(readVersion())
36
+ .description("Fetch + store Tesla Supercharger locations and pricing");
37
+ program
38
+ .command("init-load")
39
+ .description("Delete slugs before fetching it again")
40
+ .action(runInitLoad);
41
+ program
42
+ .command("init-load-file")
43
+ .description("Delete slugs before loading file again")
44
+ .addOption(slugsJsonOption())
45
+ .action((o) => runInitLoadByFile(o));
46
+ program
47
+ .command("sync-load")
48
+ .description("Sync fetched slugs")
49
+ .action(runSyncLoad);
50
+ program
51
+ .command("sync-load-file")
52
+ .description("Sync loaded slugs from file")
53
+ .addOption(slugsJsonOption())
54
+ .action((o) => runSyncLoadByFile(o));
55
+ program
56
+ .command("find-slugs")
57
+ .description("Find slugs by coordinates")
58
+ .addOption(latitudeOption())
59
+ .addOption(longitudeOption())
60
+ .action((o) => runFindSlugs(o));
61
+ program
62
+ .command("find-charger")
63
+ .description("Find charger by coordinates")
64
+ .addOption(latitudeOption())
65
+ .addOption(longitudeOption())
66
+ .action((o) => runFindCharger(o));
67
+ program
68
+ .command("find-prices")
69
+ .description("Find charger by coordinates and date/time")
70
+ .addOption(latitudeOption())
71
+ .addOption(longitudeOption())
72
+ .addOption(timestampOption())
73
+ .action((o) => runFindPrices(o));
74
+ program
75
+ .command("find-unpriced-charges")
76
+ .description("Find unpriced charges")
77
+ .action(runFindUnpricedCharges);
78
+ program
79
+ .command("process-unpriced-charges")
80
+ .description("Process unpriced charges")
81
+ .action(runProcessUnpricedCharges);
82
+ program
83
+ .command("find-failures")
84
+ .description("List failing rows across the failure-tracked sources")
85
+ .addOption(sourceOption())
86
+ .addOption(thresholdOption())
87
+ .action((o) => runFindFailures(o));
88
+ program
89
+ .command("reset-failures")
90
+ .description("Reset failure state for a row (--id) or a whole source (--all)")
91
+ .addOption(sourceOption())
92
+ .addOption(idOption())
93
+ .addOption(allOption())
94
+ .action((o) => runResetFailures(o));
95
+ program
96
+ .command("notify-failures")
97
+ .description("Send a Pushover alert for not-yet-notified failures")
98
+ .addOption(thresholdOption())
99
+ .action((o) => runNotifyFailures(o));
100
+ program
101
+ .command("schedule")
102
+ .description("Run the daily pricing + notify daemon (optional slug sync)")
103
+ .addOption(cronOption())
104
+ .addOption(syncCronOption())
105
+ .addOption(runOnStartOption())
106
+ .action((o) => runSchedule(o));
107
+ program
108
+ .parseAsync(argv)
109
+ // close the shared postgres pool (if one was opened) so the process exits
110
+ // instead of waiting out the idle_timeout
111
+ .then(() => endSql())
112
+ .catch((e) => {
113
+ console.error(e);
114
+ exit(1);
115
+ });
116
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ import { Option } from "@commander-js/extra-typings";
2
+ /** Commander option: path to a slugs json dump (as served by get-locations). */
3
+ export declare const slugsJsonOption: () => Option<"-s, --slugs [slugs]", undefined, undefined, string, true, undefined>;
4
+ export declare const latitudeOption: () => Option<"--lat <latitude>", undefined, undefined, undefined, true, undefined>;
5
+ export declare const longitudeOption: () => Option<"--lon <longitude>", undefined, undefined, undefined, true, undefined>;
6
+ /** Commander option: ISO 8601 timestamp to price at (default: now). */
7
+ export declare const timestampOption: () => Option<"--at <timestamp>", undefined, undefined, Date, false, undefined>;
8
+ /** Which failure-tracked source(s) to act on (default: all). */
9
+ export declare const sourceOption: () => Option<"--source <source>", undefined, "all", undefined, false, "charges" | "chargers" | "slugs" | "all">;
10
+ /** Minimum failure_count to include (default: the deprioritize threshold). */
11
+ export declare const thresholdOption: () => Option<"--threshold <count>", undefined, 3, number, false, undefined>;
12
+ /** Row id to reset (charges: the charging_processes_id). */
13
+ export declare const idOption: () => Option<"--id <id>", undefined, undefined, undefined, false, undefined>;
14
+ /** Reset every failing row of the source instead of a single id. */
15
+ export declare const allOption: () => Option<"--all", undefined, undefined, undefined, false, undefined>;
16
+ /** Cron expression for the pricing + notify tick (default: daily at 03:00). */
17
+ export declare const cronOption: () => Option<"--cron <expression>", undefined, "0 3 * * *", undefined, false, undefined>;
18
+ /** Cron expression for an optional slug sync job (disabled unless set). */
19
+ export declare const syncCronOption: () => Option<"--sync-cron <expression>", undefined, undefined, undefined, false, undefined>;
20
+ /** Run one tick immediately on startup, before waiting for the first cron fire. */
21
+ export declare const runOnStartOption: () => Option<"--run-on-start", undefined, undefined, undefined, false, undefined>;
22
+ //# sourceMappingURL=cli.option.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.option.d.ts","sourceRoot":"","sources":["../src/cli.option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AAMrD,gFAAgF;AAChF,eAAO,MAAM,eAAe,oFAGH,CAAC;AAE1B,eAAO,MAAM,cAAc,oFACuC,CAAC;AAEnE,eAAO,MAAM,eAAe,qFACwC,CAAC;AAErE,uEAAuE;AACvE,eAAO,MAAM,eAAe,gFAIC,CAAC;AAE9B,gEAAgE;AAChE,eAAO,MAAM,YAAY,iHAGG,CAAC;AAE7B,8EAA8E;AAC9E,eAAO,MAAM,eAAe,6EAGgB,CAAC;AAE7C,4DAA4D;AAC5D,eAAO,MAAM,QAAQ,8EAAmD,CAAC;AAEzE,oEAAoE;AACpE,eAAO,MAAM,SAAS,0EACuC,CAAC;AAE9D,+EAA+E;AAC/E,eAAO,MAAM,UAAU,0FAIC,CAAC;AAEzB,2EAA2E;AAC3E,eAAO,MAAM,cAAc,6FAIxB,CAAC;AAEJ,mFAAmF;AACnF,eAAO,MAAM,gBAAgB,mFACwC,CAAC"}
@@ -0,0 +1,31 @@
1
+ import { Option } from "@commander-js/extra-typings";
2
+ import { FAILURE_DEPRIORITIZE_THRESHOLD } from "@mxpicture/tesla-superchargers-api/common";
3
+ import { parseIntArg, parsePath, parseTimestamp } from "./cli.parse.js";
4
+ // ---------- commander options ----------
5
+ /** Commander option: path to a slugs json dump (as served by get-locations). */
6
+ export const slugsJsonOption = () => new Option("-s, --slugs [slugs]", "Path to slugs json file")
7
+ .makeOptionMandatory()
8
+ .argParser(parsePath);
9
+ export const latitudeOption = () => new Option("--lat <latitude>", "latitude").makeOptionMandatory();
10
+ export const longitudeOption = () => new Option("--lon <longitude>", "longitude").makeOptionMandatory();
11
+ /** Commander option: ISO 8601 timestamp to price at (default: now). */
12
+ export const timestampOption = () => new Option("--at <timestamp>", "ISO 8601 timestamp to find prices at (default: now)").argParser(parseTimestamp);
13
+ /** Which failure-tracked source(s) to act on (default: all). */
14
+ export const sourceOption = () => new Option("--source <source>", "Failure source")
15
+ .choices(["charges", "chargers", "slugs", "all"])
16
+ .default("all");
17
+ /** Minimum failure_count to include (default: the deprioritize threshold). */
18
+ export const thresholdOption = () => new Option("--threshold <count>", "Minimum failure count")
19
+ .argParser(parseIntArg)
20
+ .default(FAILURE_DEPRIORITIZE_THRESHOLD);
21
+ /** Row id to reset (charges: the charging_processes_id). */
22
+ export const idOption = () => new Option("--id <id>", "Row id to reset");
23
+ /** Reset every failing row of the source instead of a single id. */
24
+ export const allOption = () => new Option("--all", "Reset all failing rows of the source");
25
+ /** Cron expression for the pricing + notify tick (default: daily at 03:00). */
26
+ export const cronOption = () => new Option("--cron <expression>", "Cron expression for the pricing + notify tick").default("0 3 * * *");
27
+ /** Cron expression for an optional slug sync job (disabled unless set). */
28
+ export const syncCronOption = () => new Option("--sync-cron <expression>", "Cron expression for the slug sync (disabled unless set)");
29
+ /** Run one tick immediately on startup, before waiting for the first cron fire. */
30
+ export const runOnStartOption = () => new Option("--run-on-start", "Run one tick immediately on startup");
31
+ //# sourceMappingURL=cli.option.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.option.js","sourceRoot":"","sources":["../src/cli.option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,6BAA6B,CAAC;AACrD,OAAO,EAAE,8BAA8B,EAAE,MAAM,2CAA2C,CAAC;AAC3F,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAExE,0CAA0C;AAE1C,gFAAgF;AAChF,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE,CAClC,IAAI,MAAM,CAAC,qBAAqB,EAAE,yBAAyB,CAAC;KACzD,mBAAmB,EAAE;KACrB,SAAS,CAAC,SAAS,CAAC,CAAC;AAE1B,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CACjC,IAAI,MAAM,CAAC,kBAAkB,EAAE,UAAU,CAAC,CAAC,mBAAmB,EAAE,CAAC;AAEnE,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE,CAClC,IAAI,MAAM,CAAC,mBAAmB,EAAE,WAAW,CAAC,CAAC,mBAAmB,EAAE,CAAC;AAErE,uEAAuE;AACvE,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE,CAClC,IAAI,MAAM,CACR,kBAAkB,EAClB,qDAAqD,CACtD,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AAE9B,gEAAgE;AAChE,MAAM,CAAC,MAAM,YAAY,GAAG,GAAG,EAAE,CAC/B,IAAI,MAAM,CAAC,mBAAmB,EAAE,gBAAgB,CAAC;KAC9C,OAAO,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,KAAK,CAAU,CAAC;KACzD,OAAO,CAAC,KAAc,CAAC,CAAC;AAE7B,8EAA8E;AAC9E,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,EAAE,CAClC,IAAI,MAAM,CAAC,qBAAqB,EAAE,uBAAuB,CAAC;KACvD,SAAS,CAAC,WAAW,CAAC;KACtB,OAAO,CAAC,8BAA8B,CAAC,CAAC;AAE7C,4DAA4D;AAC5D,MAAM,CAAC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,IAAI,MAAM,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;AAEzE,oEAAoE;AACpE,MAAM,CAAC,MAAM,SAAS,GAAG,GAAG,EAAE,CAC5B,IAAI,MAAM,CAAC,OAAO,EAAE,sCAAsC,CAAC,CAAC;AAE9D,+EAA+E;AAC/E,MAAM,CAAC,MAAM,UAAU,GAAG,GAAG,EAAE,CAC7B,IAAI,MAAM,CACR,qBAAqB,EACrB,+CAA+C,CAChD,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;AAEzB,2EAA2E;AAC3E,MAAM,CAAC,MAAM,cAAc,GAAG,GAAG,EAAE,CACjC,IAAI,MAAM,CACR,0BAA0B,EAC1B,yDAAyD,CAC1D,CAAC;AAEJ,mFAAmF;AACnF,MAAM,CAAC,MAAM,gBAAgB,GAAG,GAAG,EAAE,CACnC,IAAI,MAAM,CAAC,gBAAgB,EAAE,qCAAqC,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ /** Parses a non-negative float (e.g. --delay, --radius). */
2
+ export declare const parseFloatArg: (v: string) => number;
3
+ /** Parses a non-negative integer (e.g. --limit). */
4
+ export declare const parseIntArg: (v: string) => number;
5
+ /** Parses a positive integer number of days (e.g. --*-every, --outdated-age). */
6
+ export declare const parseDaysArg: (v: string) => number;
7
+ /** Validates an HH:MM (24h) time string (e.g. --at). */
8
+ export declare const parseTime: (v: string) => string;
9
+ /** Parses an ISO 8601 timestamp (e.g. --at on find-prices). */
10
+ export declare const parseTimestamp: (v: string) => Date;
11
+ export declare const parsePath: (path: string) => string;
12
+ //# sourceMappingURL=cli.parse.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.parse.d.ts","sourceRoot":"","sources":["../src/cli.parse.ts"],"names":[],"mappings":"AAMA,4DAA4D;AAC5D,eAAO,MAAM,aAAa,GAAI,GAAG,MAAM,KAAG,MAKzC,CAAC;AAEF,oDAAoD;AACpD,eAAO,MAAM,WAAW,GAAI,GAAG,MAAM,KAAG,MAKvC,CAAC;AAEF,iFAAiF;AACjF,eAAO,MAAM,YAAY,GAAI,GAAG,MAAM,KAAG,MAKxC,CAAC;AAEF,wDAAwD;AACxD,eAAO,MAAM,SAAS,GAAI,GAAG,MAAM,KAAG,MAIrC,CAAC;AAEF,+DAA+D;AAC/D,eAAO,MAAM,cAAc,GAAI,GAAG,MAAM,KAAG,IAK1C,CAAC;AAEF,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,KAAG,MACO,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { InvalidArgumentError } from "@commander-js/extra-typings";
2
+ import { isAbsolute, resolve } from "node:path";
3
+ import { cwd } from "node:process";
4
+ // ---------- argument parsers ----------
5
+ /** Parses a non-negative float (e.g. --delay, --radius). */
6
+ export const parseFloatArg = (v) => {
7
+ const n = Number(v);
8
+ if (!Number.isFinite(n) || n < 0)
9
+ throw new InvalidArgumentError("must be a non-negative number");
10
+ return n;
11
+ };
12
+ /** Parses a non-negative integer (e.g. --limit). */
13
+ export const parseIntArg = (v) => {
14
+ const n = parseInt(v, 10);
15
+ if (isNaN(n) || n < 0)
16
+ throw new InvalidArgumentError("must be a non-negative integer");
17
+ return n;
18
+ };
19
+ /** Parses a positive integer number of days (e.g. --*-every, --outdated-age). */
20
+ export const parseDaysArg = (v) => {
21
+ const n = parseInt(v, 10);
22
+ if (!Number.isInteger(n) || n < 1)
23
+ throw new InvalidArgumentError("must be a positive integer (>= 1)");
24
+ return n;
25
+ };
26
+ /** Validates an HH:MM (24h) time string (e.g. --at). */
27
+ export const parseTime = (v) => {
28
+ if (!/^([01]\d|2[0-3]):[0-5]\d$/.test(v))
29
+ throw new InvalidArgumentError("expected HH:MM (24h)");
30
+ return v;
31
+ };
32
+ /** Parses an ISO 8601 timestamp (e.g. --at on find-prices). */
33
+ export const parseTimestamp = (v) => {
34
+ const d = new Date(v);
35
+ if (isNaN(d.getTime()))
36
+ throw new InvalidArgumentError("expected an ISO 8601 timestamp");
37
+ return d;
38
+ };
39
+ export const parsePath = (path) => isAbsolute(path) ? path : resolve(cwd(), path);
40
+ //# sourceMappingURL=cli.parse.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.parse.js","sourceRoot":"","sources":["../src/cli.parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAChD,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,yCAAyC;AAEzC,4DAA4D;AAC5D,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAS,EAAU,EAAE;IACjD,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IACpB,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAC9B,MAAM,IAAI,oBAAoB,CAAC,+BAA+B,CAAC,CAAC;IAClE,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,oDAAoD;AACpD,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAS,EAAU,EAAE;IAC/C,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1B,IAAI,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QACnB,MAAM,IAAI,oBAAoB,CAAC,gCAAgC,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,iFAAiF;AACjF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAS,EAAU,EAAE;IAChD,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC1B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC;QAC/B,MAAM,IAAI,oBAAoB,CAAC,mCAAmC,CAAC,CAAC;IACtE,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,wDAAwD;AACxD,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAS,EAAU,EAAE;IAC7C,IAAI,CAAC,2BAA2B,CAAC,IAAI,CAAC,CAAC,CAAC;QACtC,MAAM,IAAI,oBAAoB,CAAC,sBAAsB,CAAC,CAAC;IACzD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAS,EAAQ,EAAE;IAChD,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,oBAAoB,CAAC,gCAAgC,CAAC,CAAC;IACnE,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,IAAY,EAAU,EAAE,CAChD,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,CAAC"}
@@ -0,0 +1,60 @@
1
+ type FailureSourceArg = "charges" | "chargers" | "slugs" | "all";
2
+ export declare const runInitLoad: () => Promise<void>;
3
+ export declare const runInitLoadByFile: (o: {
4
+ slugs: string | true;
5
+ }) => Promise<void>;
6
+ export declare const runSyncLoad: () => Promise<void>;
7
+ export declare const runSyncLoadByFile: (o: {
8
+ slugs: string | true;
9
+ }) => Promise<void>;
10
+ export declare const runFindSlugs: (o: {
11
+ lat: string;
12
+ lon: string;
13
+ }) => Promise<void>;
14
+ export declare const runFindCharger: (o: {
15
+ lat: string;
16
+ lon: string;
17
+ }) => Promise<void>;
18
+ export declare const runFindPrices: (o: {
19
+ lat: string;
20
+ lon: string;
21
+ at?: Date;
22
+ }) => Promise<void>;
23
+ export declare const runFindUnpricedCharges: () => Promise<void>;
24
+ /**
25
+ * Backfill `cost` on unpriced charges: for each charge the Supercharger
26
+ * prices valid at the charge's start are looked up by coordinate, and the
27
+ * Tesla per-kWh charging rate × the charge's energy (metered
28
+ * `charge_energy_used`, falling back to `charge_energy_added`) is written
29
+ * back. Charges not at a known Supercharger, without a kWh-based Tesla
30
+ * charging rate, or without a usable energy value are skipped and stay
31
+ * unpriced. Time-of-use is resolved at the charge's start instant; a charge
32
+ * spanning into the next window keeps the starting rate.
33
+ */
34
+ export declare const runProcessUnpricedCharges: () => Promise<void>;
35
+ export declare const runFindFailures: (o: {
36
+ source: FailureSourceArg;
37
+ threshold: number;
38
+ }) => Promise<void>;
39
+ export declare const runResetFailures: (o: {
40
+ source: FailureSourceArg;
41
+ id?: string;
42
+ all?: boolean;
43
+ }) => Promise<void>;
44
+ export declare const runNotifyFailures: (o: {
45
+ threshold: number;
46
+ }) => Promise<void>;
47
+ /**
48
+ * Long-running daemon: a croner job runs the pricing backfill + failure
49
+ * notification on `--cron` (daily at 03:00 by default), and — only when
50
+ * `--sync-cron` is given — a second job runs the slug sync. A tick that throws
51
+ * is logged and paged but never stops the daemon. Never resolves; the shared
52
+ * pool stays open until SIGINT/SIGTERM closes it and exits.
53
+ */
54
+ export declare const runSchedule: (o: {
55
+ cron: string;
56
+ syncCron?: string;
57
+ runOnStart?: boolean;
58
+ }) => Promise<never>;
59
+ export {};
60
+ //# sourceMappingURL=cli.run.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.run.d.ts","sourceRoot":"","sources":["../src/cli.run.ts"],"names":[],"mappings":"AAkBA,KAAK,gBAAgB,GAAG,SAAS,GAAG,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;AAEjE,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,IAAI,CAIhD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,GAAG;IACzC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,KAAG,OAAO,CAAC,IAAI,CAQf,CAAC;AAEF,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,IAAI,CAIhD,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,GAAG;IACzC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;CACtB,KAAG,OAAO,CAAC,IAAI,CAQf,CAAC;AAEF,eAAO,MAAM,YAAY,GAAU,GAAG;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,KAAG,OAAO,CAAC,IAAI,CAWf,CAAC;AAEF,eAAO,MAAM,cAAc,GAAU,GAAG;IACtC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb,KAAG,OAAO,CAAC,IAAI,CAaf,CAAC;AAEF,eAAO,MAAM,aAAa,GAAU,GAAG;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,CAAC,EAAE,IAAI,CAAC;CACX,KAAG,OAAO,CAAC,IAAI,CAcf,CAAC;AAEF,eAAO,MAAM,sBAAsB,QAAa,OAAO,CAAC,IAAI,CAI3D,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,QAAa,OAAO,CAAC,IAAI,CA+B9D,CAAC;AAEF,eAAO,MAAM,eAAe,GAAU,GAAG;IACvC,MAAM,EAAE,gBAAgB,CAAC;IACzB,SAAS,EAAE,MAAM,CAAC;CACnB,KAAG,OAAO,CAAC,IAAI,CAef,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,GAAG;IACxC,MAAM,EAAE,gBAAgB,CAAC;IACzB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,OAAO,CAAC;CACf,KAAG,OAAO,CAAC,IAAI,CAkBf,CAAC;AAEF,eAAO,MAAM,iBAAiB,GAAU,GAAG;IACzC,SAAS,EAAE,MAAM,CAAC;CACnB,KAAG,OAAO,CAAC,IAAI,CAOf,CAAC;AAuBF;;;;;;GAMG;AACH,eAAO,MAAM,WAAW,GAAU,GAAG;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB,KAAG,OAAO,CAAC,KAAK,CA4BhB,CAAC"}
@@ -0,0 +1,179 @@
1
+ import { slugsApi, chargersApi, chargingProcessesApi, failuresApi, } from "@mxpicture/tesla-superchargers-api/api";
2
+ import { pushoverConfigFromEnv, sendPushover, } from "@mxpicture/tesla-superchargers-api/common";
3
+ import { endSql } from "@mxpicture/tesla-superchargers-mate/store";
4
+ import { Cron } from "croner";
5
+ import { dirname, resolve } from "node:path";
6
+ import { exit } from "node:process";
7
+ import { fileURLToPath } from "node:url";
8
+ const __dirname = dirname(fileURLToPath(import.meta.url));
9
+ export const runInitLoad = async () => {
10
+ console.log("----- init load slugs ------------------");
11
+ const summary = await slugsApi().initialLoad();
12
+ console.log(summary);
13
+ };
14
+ export const runInitLoadByFile = async (o) => {
15
+ console.log("----- init load slugs by file ------------------");
16
+ const summary = await slugsApi().initialLoadFile(o.slugs !== true
17
+ ? o.slugs
18
+ : resolve(__dirname, "../../../compare/data/slugs.json"));
19
+ console.log(summary);
20
+ };
21
+ export const runSyncLoad = async () => {
22
+ console.log("----- sync slugs ------------------");
23
+ const summary = await slugsApi().syncLoad();
24
+ console.log(summary);
25
+ };
26
+ export const runSyncLoadByFile = async (o) => {
27
+ console.log("----- sync slugs by file ------------------");
28
+ const summary = await slugsApi().syncLoadFile(o.slugs !== true
29
+ ? o.slugs
30
+ : resolve(__dirname, "../../../compare/data/slugs.json"));
31
+ console.log(summary);
32
+ };
33
+ export const runFindSlugs = async (o) => {
34
+ const slugs = await slugsApi().find({
35
+ latitude: o.lat,
36
+ longitude: o.lon,
37
+ });
38
+ console.log(`${slugs.length} slugs (tesla_uuid) found:`);
39
+ for (const slug of slugs)
40
+ console.log(`- ${slug.location_url_slug} (${slug.tesla_uuid}): ${Math.round(slug.distance_km * 1000)} m`);
41
+ };
42
+ export const runFindCharger = async (o) => {
43
+ const charger = await chargersApi().find({
44
+ latitude: o.lat,
45
+ longitude: o.lon,
46
+ });
47
+ if (!charger) {
48
+ console.log(`no charger found for ${o.lat} ${o.lon}`);
49
+ return;
50
+ }
51
+ console.log(`charger found:`);
52
+ console.log(charger);
53
+ };
54
+ export const runFindPrices = async (o) => {
55
+ const at = o.at ?? new Date();
56
+ const pricebooks = await chargersApi().findPrices({ latitude: o.lat, longitude: o.lon }, at);
57
+ if (!pricebooks.length) {
58
+ console.log(`no prices found for ${o.lat} ${o.lon} at ${at.toISOString()}`);
59
+ return;
60
+ }
61
+ console.log(`prices found:`);
62
+ console.log(pricebooks);
63
+ };
64
+ export const runFindUnpricedCharges = async () => {
65
+ const charges = await chargingProcessesApi().getUnpricedCharges();
66
+ console.log(`${charges.length} charges found:`);
67
+ console.log(charges);
68
+ };
69
+ /**
70
+ * Backfill `cost` on unpriced charges: for each charge the Supercharger
71
+ * prices valid at the charge's start are looked up by coordinate, and the
72
+ * Tesla per-kWh charging rate × the charge's energy (metered
73
+ * `charge_energy_used`, falling back to `charge_energy_added`) is written
74
+ * back. Charges not at a known Supercharger, without a kWh-based Tesla
75
+ * charging rate, or without a usable energy value are skipped and stay
76
+ * unpriced. Time-of-use is resolved at the charge's start instant; a charge
77
+ * spanning into the next window keeps the starting rate.
78
+ */
79
+ export const runProcessUnpricedCharges = async () => {
80
+ const summary = await chargingProcessesApi().runPricing();
81
+ console.log(`${summary.unpricedCharges} unpriced charges found`);
82
+ let priced = 0;
83
+ for (const { charge, topic, energy, rate, cost } of summary.items) {
84
+ switch (topic) {
85
+ case "noRate":
86
+ console.warn(`- charge ${charge.id}: no rate found, skipped`);
87
+ break;
88
+ case "noEnergyValue":
89
+ console.warn(`- charge ${charge.id}: rate found but no usable energy value, skipped`);
90
+ break;
91
+ case "chargeUpdated":
92
+ priced++;
93
+ console.log(`- charge ${charge.id} (${charge.start_date.toISOString()}): ` +
94
+ `${energy} kWh × ${rate?.rate} = ${cost} ${rate?.currencyCode}`);
95
+ break;
96
+ default:
97
+ break;
98
+ }
99
+ }
100
+ console.log(`${priced} of ${summary.unpricedCharges} charges priced`);
101
+ };
102
+ export const runFindFailures = async (o) => {
103
+ const failed = await failuresApi().getFailed(o.source, o.threshold);
104
+ console.log(`failures (>= ${o.threshold}): ${failed.charges.length} charges, ` +
105
+ `${failed.chargers.length} chargers, ${failed.slugs.length} slugs`);
106
+ for (const c of failed.charges)
107
+ console.log(`- charge #${c.charging_processes_id} ` +
108
+ `(${c.start_date ? c.start_date.toISOString() : "?"}): ${c.failure_count} failures`);
109
+ for (const c of failed.chargers)
110
+ console.log(`- charger ${c.name}, ${c.city}: ${c.failure_count} failures`);
111
+ for (const s of failed.slugs)
112
+ console.log(`- slug ${s.location_url_slug}: ${s.failure_count} failures`);
113
+ };
114
+ export const runResetFailures = async (o) => {
115
+ if (Boolean(o.id) === Boolean(o.all))
116
+ throw new Error("provide exactly one of --id or --all");
117
+ if (o.id !== undefined) {
118
+ if (o.source === "all")
119
+ throw new Error("--id requires a concrete --source (charges, chargers or slugs)");
120
+ await failuresApi().resetFailed(o.source, o.id);
121
+ console.log(`reset ${o.source} failure for id ${o.id}`);
122
+ return;
123
+ }
124
+ const counts = await failuresApi().resetAllFailed(o.source);
125
+ console.log(`reset ${counts.charges} charges, ${counts.chargers} chargers, ${counts.slugs} slugs`);
126
+ };
127
+ export const runNotifyFailures = async (o) => {
128
+ const summary = await failuresApi().notifyFailures(o.threshold, console.log);
129
+ console.log(summary);
130
+ if (!summary.configured)
131
+ console.log("pushover not configured: set PUSHOVER_API_TOKEN and PUSHOVER_USER_KEY to enable alerts");
132
+ };
133
+ /** Build a tick that logs its failure and pages it (Decision 8), never throwing. */
134
+ const guardedTick = (title, run) => async () => {
135
+ try {
136
+ await run();
137
+ }
138
+ catch (e) {
139
+ console.error(e);
140
+ const cfg = pushoverConfigFromEnv();
141
+ if (cfg)
142
+ await sendPushover(cfg, {
143
+ title,
144
+ message: e instanceof Error ? e.message : String(e),
145
+ priority: 1,
146
+ }, console.log);
147
+ }
148
+ };
149
+ /**
150
+ * Long-running daemon: a croner job runs the pricing backfill + failure
151
+ * notification on `--cron` (daily at 03:00 by default), and — only when
152
+ * `--sync-cron` is given — a second job runs the slug sync. A tick that throws
153
+ * is logged and paged but never stops the daemon. Never resolves; the shared
154
+ * pool stays open until SIGINT/SIGTERM closes it and exits.
155
+ */
156
+ export const runSchedule = async (o) => {
157
+ const tick = guardedTick("❌ Supercharger scheduler run failed", async () => {
158
+ await runProcessUnpricedCharges();
159
+ console.log(await failuresApi().notifyFailures(undefined, console.log));
160
+ });
161
+ const jobs = [new Cron(o.cron, { protect: true }, tick)];
162
+ if (o.syncCron)
163
+ jobs.push(new Cron(o.syncCron, { protect: true }, guardedTick("❌ Supercharger slug sync failed", async () => {
164
+ console.log(await slugsApi().syncLoad());
165
+ })));
166
+ const shutdown = () => {
167
+ for (const j of jobs)
168
+ j.stop();
169
+ void endSql().finally(() => exit(0));
170
+ };
171
+ process.on("SIGINT", shutdown);
172
+ process.on("SIGTERM", shutdown);
173
+ for (const j of jobs)
174
+ console.log(`next run: ${j.nextRun()?.toISOString()}`);
175
+ if (o.runOnStart)
176
+ await tick();
177
+ return await new Promise(() => { });
178
+ };
179
+ //# sourceMappingURL=cli.run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.run.js","sourceRoot":"","sources":["../src/cli.run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export * from "./cli.common.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export * from "./cli.common.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,iBAAiB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@mxpicture/tesla-superchargers-cli",
3
+ "version": "0.1.1",
4
+ "description": "CLI to fetch + store Tesla Supercharger locations and pricing",
5
+ "type": "module",
6
+ "author": "MXPicture",
7
+ "license": "MIT",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/MXPicture/npm-tesla-superchargers.git"
11
+ },
12
+ "bin": {
13
+ "teslamate-superchargers": "./dist/cli.js"
14
+ },
15
+ "exports": {
16
+ ".": {
17
+ "types": "./src/index.ts",
18
+ "default": "./dist/index.js"
19
+ },
20
+ "./package.json": "./package.json"
21
+ },
22
+ "files": [
23
+ "dist"
24
+ ],
25
+ "engines": {
26
+ "node": ">=24"
27
+ },
28
+ "scripts": {
29
+ "lint": "eslint \"src/**/*.ts\" --ext .ts --cache --cache-strategy content",
30
+ "lint:ci": "eslint \"src/**/*.ts\" --ext .ts --max-warnings=0",
31
+ "build": "tsc -b .",
32
+ "test": "tsc -b . && vitest run --passWithNoTests"
33
+ },
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "dependencies": {
38
+ "@commander-js/extra-typings": "^14.0.0",
39
+ "@mxpicture/tesla-superchargers-api": "workspace:*",
40
+ "@mxpicture/tesla-superchargers-mate": "workspace:*",
41
+ "commander": "^14.0.3",
42
+ "croner": "^10.0.1"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^25.2.3",
46
+ "eslint": "^9.39.3",
47
+ "typescript": "^5.9.3",
48
+ "vitest": "^4.0.18"
49
+ }
50
+ }