@mxpicture/tesla-superchargers-cloud-store 0.1.4 → 0.1.6
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/package.json +3 -3
- package/dist/client/DropboxAuth.d.ts +0 -32
- package/dist/client/DropboxAuth.d.ts.map +0 -1
- package/dist/client/DropboxAuth.js +0 -57
- package/dist/client/DropboxAuth.js.map +0 -1
- package/dist/common/chargers.common.d.ts +0 -11
- package/dist/common/chargers.common.d.ts.map +0 -1
- package/dist/common/chargers.common.js +0 -11
- package/dist/common/chargers.common.js.map +0 -1
- package/dist/common/failures.common.d.ts +0 -8
- package/dist/common/failures.common.d.ts.map +0 -1
- package/dist/common/failures.common.js +0 -33
- package/dist/common/failures.common.js.map +0 -1
- package/dist/common/invoicesCsv.common.d.ts +0 -85
- package/dist/common/invoicesCsv.common.d.ts.map +0 -1
- package/dist/common/invoicesCsv.common.js +0 -185
- package/dist/common/invoicesCsv.common.js.map +0 -1
- package/dist/common/pricebooks.common.d.ts +0 -47
- package/dist/common/pricebooks.common.d.ts.map +0 -1
- package/dist/common/pricebooks.common.js +0 -95
- package/dist/common/pricebooks.common.js.map +0 -1
- package/dist/common/pushover.common.d.ts +0 -23
- package/dist/common/pushover.common.d.ts.map +0 -1
- package/dist/common/pushover.common.js +0 -52
- package/dist/common/pushover.common.js.map +0 -1
- package/dist/common/sync.common.d.ts +0 -4
- package/dist/common/sync.common.d.ts.map +0 -1
- package/dist/common/sync.common.js +0 -10
- package/dist/common/sync.common.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mxpicture/tesla-superchargers-cloud-store",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Cloud store intergration e.g. dropbox",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "MXPicture",
|
|
@@ -40,8 +40,8 @@
|
|
|
40
40
|
"access": "public"
|
|
41
41
|
},
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"@mxpicture/tesla-superchargers-generated": "
|
|
44
|
-
"@mxpicture/tesla-superchargers-mate": "
|
|
43
|
+
"@mxpicture/tesla-superchargers-generated": "^0.1.6",
|
|
44
|
+
"@mxpicture/tesla-superchargers-mate": "^0.1.6",
|
|
45
45
|
"csv-parse": "^7.0.1",
|
|
46
46
|
"dropbox": "^10.37.1",
|
|
47
47
|
"json5": "^2.2.3",
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read-only Dropbox access: list a directory and download file content.
|
|
3
|
-
*
|
|
4
|
-
* Auth (read from the process environment on first use):
|
|
5
|
-
* - `DROPBOX_KEY` + `DROPBOX_SECRET` + `DROPBOX_REFRESH_TOKEN` — long-lived;
|
|
6
|
-
* the SDK exchanges the refresh token for short-lived access tokens itself.
|
|
7
|
-
* - `DROPBOX_ACCESS_TOKEN` — fallback, e.g. a token generated in the Dropbox
|
|
8
|
-
* App Console (expires after ~4h).
|
|
9
|
-
*/
|
|
10
|
-
import { Dropbox, type DropboxOptions } from "dropbox";
|
|
11
|
-
import type { DropboxAuthAccessParams, DropboxAuthClientParams } from "../types/dropbox.types.js";
|
|
12
|
-
export declare class DropboxAuthFactory {
|
|
13
|
-
private constructor();
|
|
14
|
-
static byEnv(env: Record<string, string | undefined>): IDropboxAuth;
|
|
15
|
-
}
|
|
16
|
-
export declare abstract class IDropboxAuth {
|
|
17
|
-
protected dbx: Dropbox | null;
|
|
18
|
-
constructor();
|
|
19
|
-
protected abstract clientParams(): DropboxOptions;
|
|
20
|
-
client(): Dropbox;
|
|
21
|
-
}
|
|
22
|
-
export declare class DropboxAuthAccess extends IDropboxAuth {
|
|
23
|
-
protected readonly auth: DropboxAuthAccessParams;
|
|
24
|
-
constructor(auth: DropboxAuthAccessParams);
|
|
25
|
-
protected clientParams(): DropboxOptions;
|
|
26
|
-
}
|
|
27
|
-
export declare class DropboxAuthClient extends IDropboxAuth {
|
|
28
|
-
protected readonly auth: DropboxAuthClientParams;
|
|
29
|
-
constructor(auth: DropboxAuthClientParams);
|
|
30
|
-
protected clientParams(): DropboxOptions;
|
|
31
|
-
}
|
|
32
|
-
//# sourceMappingURL=DropboxAuth.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DropboxAuth.d.ts","sourceRoot":"","sources":["../../src/client/DropboxAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,KAAK,EACV,uBAAuB,EACvB,uBAAuB,EACxB,MAAM,2BAA2B,CAAC;AAEnC,qBAAa,kBAAkB;IAC7B,OAAO;WAEO,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,YAAY;CAsB3E;AAED,8BAAsB,YAAY;IAChC,SAAS,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAQ;;IAIrC,SAAS,CAAC,QAAQ,CAAC,YAAY,IAAI,cAAc;IAE1C,MAAM,IAAI,OAAO;CAGzB;AAED,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;gBAE9B,IAAI,EAAE,uBAAuB;cAK7B,YAAY,IAAI,cAAc;CAGlD;AAED,qBAAa,iBAAkB,SAAQ,YAAY;IACjD,SAAS,CAAC,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;gBAE9B,IAAI,EAAE,uBAAuB;IAKhD,SAAS,CAAC,YAAY,IAAI,cAAc;CAOzC"}
|
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Read-only Dropbox access: list a directory and download file content.
|
|
3
|
-
*
|
|
4
|
-
* Auth (read from the process environment on first use):
|
|
5
|
-
* - `DROPBOX_KEY` + `DROPBOX_SECRET` + `DROPBOX_REFRESH_TOKEN` — long-lived;
|
|
6
|
-
* the SDK exchanges the refresh token for short-lived access tokens itself.
|
|
7
|
-
* - `DROPBOX_ACCESS_TOKEN` — fallback, e.g. a token generated in the Dropbox
|
|
8
|
-
* App Console (expires after ~4h).
|
|
9
|
-
*/
|
|
10
|
-
import { Dropbox } from "dropbox";
|
|
11
|
-
export class DropboxAuthFactory {
|
|
12
|
-
constructor() { }
|
|
13
|
-
static byEnv(env) {
|
|
14
|
-
const { DROPBOX_KEY, DROPBOX_SECRET, DROPBOX_REFRESH_TOKEN, DROPBOX_ACCESS_TOKEN, } = env;
|
|
15
|
-
if (DROPBOX_KEY && DROPBOX_SECRET && DROPBOX_REFRESH_TOKEN)
|
|
16
|
-
return new DropboxAuthClient({
|
|
17
|
-
clientId: DROPBOX_KEY,
|
|
18
|
-
clientSecret: DROPBOX_SECRET,
|
|
19
|
-
refreshToken: DROPBOX_REFRESH_TOKEN,
|
|
20
|
-
});
|
|
21
|
-
if (DROPBOX_ACCESS_TOKEN)
|
|
22
|
-
return new DropboxAuthAccess({ accessToken: DROPBOX_ACCESS_TOKEN });
|
|
23
|
-
throw new Error("Dropbox credentials missing: set DROPBOX_KEY + DROPBOX_SECRET + DROPBOX_REFRESH_TOKEN (or DROPBOX_ACCESS_TOKEN)");
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
export class IDropboxAuth {
|
|
27
|
-
dbx = null;
|
|
28
|
-
constructor() { }
|
|
29
|
-
client() {
|
|
30
|
-
return (this.dbx ??= new Dropbox(this.clientParams()));
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
export class DropboxAuthAccess extends IDropboxAuth {
|
|
34
|
-
auth;
|
|
35
|
-
constructor(auth) {
|
|
36
|
-
super();
|
|
37
|
-
this.auth = { ...auth };
|
|
38
|
-
}
|
|
39
|
-
clientParams() {
|
|
40
|
-
return { accessToken: this.auth.accessToken };
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
export class DropboxAuthClient extends IDropboxAuth {
|
|
44
|
-
auth;
|
|
45
|
-
constructor(auth) {
|
|
46
|
-
super();
|
|
47
|
-
this.auth = { ...auth };
|
|
48
|
-
}
|
|
49
|
-
clientParams() {
|
|
50
|
-
return {
|
|
51
|
-
clientId: this.auth.clientId,
|
|
52
|
-
clientSecret: this.auth.clientSecret,
|
|
53
|
-
refreshToken: this.auth.refreshToken,
|
|
54
|
-
};
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
//# sourceMappingURL=DropboxAuth.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"DropboxAuth.js","sourceRoot":"","sources":["../../src/client/DropboxAuth.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAuB,MAAM,SAAS,CAAC;AAMvD,MAAM,OAAO,kBAAkB;IAC7B,gBAAuB,CAAC;IAEjB,MAAM,CAAC,KAAK,CAAC,GAAuC;QACzD,MAAM,EACJ,WAAW,EACX,cAAc,EACd,qBAAqB,EACrB,oBAAoB,GACrB,GAAG,GAAG,CAAC;QAER,IAAI,WAAW,IAAI,cAAc,IAAI,qBAAqB;YACxD,OAAO,IAAI,iBAAiB,CAAC;gBAC3B,QAAQ,EAAE,WAAW;gBACrB,YAAY,EAAE,cAAc;gBAC5B,YAAY,EAAE,qBAAqB;aACpC,CAAC,CAAC;QAEL,IAAI,oBAAoB;YACtB,OAAO,IAAI,iBAAiB,CAAC,EAAE,WAAW,EAAE,oBAAoB,EAAE,CAAC,CAAC;QAEtE,MAAM,IAAI,KAAK,CACb,iHAAiH,CAClH,CAAC;IACJ,CAAC;CACF;AAED,MAAM,OAAgB,YAAY;IACtB,GAAG,GAAmB,IAAI,CAAC;IAErC,gBAAsB,CAAC;IAIhB,MAAM;QACX,OAAO,CAAC,IAAI,CAAC,GAAG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IAC9B,IAAI,CAA0B;IAEjD,YAAmB,IAA6B;QAC9C,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC1B,CAAC;IAEkB,YAAY;QAC7B,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC;IAChD,CAAC;CACF;AAED,MAAM,OAAO,iBAAkB,SAAQ,YAAY;IAC9B,IAAI,CAA0B;IAEjD,YAAmB,IAA6B;QAC9C,KAAK,EAAE,CAAC;QACR,IAAI,CAAC,IAAI,GAAG,EAAE,GAAG,IAAI,EAAE,CAAC;IAC1B,CAAC;IAES,YAAY;QACpB,OAAO;YACL,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;YAC5B,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;YACpC,YAAY,EAAE,IAAI,CAAC,IAAI,CAAC,YAAY;SACrC,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -1,11 +0,0 @@
|
|
|
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
|
|
@@ -1 +0,0 @@
|
|
|
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"}
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
/** Refetch a cached charger whose last fetch is older than this. */
|
|
2
|
-
export const CHARGER_STALE_AFTER_DAYS = 5;
|
|
3
|
-
/** Detail fetches per findByCoordinate call — the endpoint is slow and guarded. */
|
|
4
|
-
export const MAX_CHARGER_FETCHES = 3;
|
|
5
|
-
/** Candidates that failed this often are tried after the rest, so dead slugs stop burning the fetch budget first. */
|
|
6
|
-
export const FAILURE_DEPRIORITIZE_THRESHOLD = 3;
|
|
7
|
-
export const isFresh = (row) => row.fetched_at.getTime() >
|
|
8
|
-
Date.now() - CHARGER_STALE_AFTER_DAYS * 24 * 60 * 60 * 1000;
|
|
9
|
-
/** FK links are not part of the feed; a snapshot re-sync must not wipe them. */
|
|
10
|
-
export const withoutFkColumns = (columns) => columns.filter((column) => column !== "pic_slugs_id");
|
|
11
|
-
//# sourceMappingURL=chargers.common.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"chargers.common.js","sourceRoot":"","sources":["../../src/common/chargers.common.ts"],"names":[],"mappings":"AAEA,oEAAoE;AACpE,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC;AAE1C,mFAAmF;AACnF,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,CAAC;AAErC,qHAAqH;AACrH,MAAM,CAAC,MAAM,8BAA8B,GAAG,CAAC,CAAC;AAEhD,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAAgB,EAAW,EAAE,CACnD,GAAG,CAAC,UAAU,CAAC,OAAO,EAAE;IACxB,IAAI,CAAC,GAAG,EAAE,GAAG,wBAAwB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC;AAE9D,gFAAgF;AAChF,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,OAAiB,EAAY,EAAE,CAC9D,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,cAAc,CAAC,CAAC"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import type { PushoverMessage } from "../types/pushover.types.js";
|
|
2
|
-
import type { FailedSources } from "../types/failures.types.js";
|
|
3
|
-
/**
|
|
4
|
-
* Build the Pushover message for a set of failing rows, or null when every
|
|
5
|
-
* source is empty (nothing to page). Pure — unit-tested without a request.
|
|
6
|
-
*/
|
|
7
|
-
export declare const buildFailureMessage: (failed: FailedSources) => PushoverMessage | null;
|
|
8
|
-
//# sourceMappingURL=failures.common.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"failures.common.d.ts","sourceRoot":"","sources":["../../src/common/failures.common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAClE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAehE;;;GAGG;AACH,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,aAAa,KACpB,eAAe,GAAG,IA2CpB,CAAC"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/** Max rows listed per source section before truncating with a summary line. */
|
|
2
|
-
const MAX_LISTED = 10;
|
|
3
|
-
/** One titled section: up to MAX_LISTED lines, then `…and N more.` if truncated. */
|
|
4
|
-
const section = (title, lines) => {
|
|
5
|
-
const shown = lines.slice(0, MAX_LISTED).join("\n");
|
|
6
|
-
const more = lines.length > MAX_LISTED
|
|
7
|
-
? `\n…and ${lines.length - MAX_LISTED} more.`
|
|
8
|
-
: "";
|
|
9
|
-
return `${title}\n${shown}${more}`;
|
|
10
|
-
};
|
|
11
|
-
/**
|
|
12
|
-
* Build the Pushover message for a set of failing rows, or null when every
|
|
13
|
-
* source is empty (nothing to page). Pure — unit-tested without a request.
|
|
14
|
-
*/
|
|
15
|
-
export const buildFailureMessage = (failed) => {
|
|
16
|
-
const sections = [];
|
|
17
|
-
if (failed.charges.length > 0)
|
|
18
|
-
sections.push(section("Charges:", failed.charges.map((c) => `• charge #${c.charging_processes_id} ` +
|
|
19
|
-
`(${c.start_date ? c.start_date.toISOString() : "?"}): ` +
|
|
20
|
-
`${c.failure_count} failures`)));
|
|
21
|
-
if (failed.chargers.length > 0)
|
|
22
|
-
sections.push(section("Chargers:", failed.chargers.map((c) => `• ${c.name}, ${c.city}: ${c.failure_count} failures`)));
|
|
23
|
-
if (failed.slugs.length > 0)
|
|
24
|
-
sections.push(section("Slugs:", failed.slugs.map((s) => `• ${s.location_url_slug}: ${s.failure_count} failures`)));
|
|
25
|
-
if (sections.length === 0)
|
|
26
|
-
return null;
|
|
27
|
-
return {
|
|
28
|
-
title: "🚫 Supercharger failures",
|
|
29
|
-
message: sections.join("\n\n"),
|
|
30
|
-
priority: 1,
|
|
31
|
-
};
|
|
32
|
-
};
|
|
33
|
-
//# sourceMappingURL=failures.common.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"failures.common.js","sourceRoot":"","sources":["../../src/common/failures.common.ts"],"names":[],"mappings":"AAGA,gFAAgF;AAChF,MAAM,UAAU,GAAG,EAAE,CAAC;AAEtB,oFAAoF;AACpF,MAAM,OAAO,GAAG,CAAC,KAAa,EAAE,KAAe,EAAU,EAAE;IACzD,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,MAAM,IAAI,GACR,KAAK,CAAC,MAAM,GAAG,UAAU;QACvB,CAAC,CAAC,UAAU,KAAK,CAAC,MAAM,GAAG,UAAU,QAAQ;QAC7C,CAAC,CAAC,EAAE,CAAC;IACT,OAAO,GAAG,KAAK,KAAK,KAAK,GAAG,IAAI,EAAE,CAAC;AACrC,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CACjC,MAAqB,EACG,EAAE;IAC1B,MAAM,QAAQ,GAAa,EAAE,CAAC;IAE9B,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QAC3B,QAAQ,CAAC,IAAI,CACX,OAAO,CACL,UAAU,EACV,MAAM,CAAC,OAAO,CAAC,GAAG,CAChB,CAAC,CAAC,EAAE,EAAE,CACJ,aAAa,CAAC,CAAC,qBAAqB,GAAG;YACvC,IAAI,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,GAAG,KAAK;YACxD,GAAG,CAAC,CAAC,aAAa,WAAW,CAChC,CACF,CACF,CAAC;IAEJ,IAAI,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC;QAC5B,QAAQ,CAAC,IAAI,CACX,OAAO,CACL,WAAW,EACX,MAAM,CAAC,QAAQ,CAAC,GAAG,CACjB,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,aAAa,WAAW,CAC7D,CACF,CACF,CAAC;IAEJ,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC;QACzB,QAAQ,CAAC,IAAI,CACX,OAAO,CACL,QAAQ,EACR,MAAM,CAAC,KAAK,CAAC,GAAG,CACd,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,iBAAiB,KAAK,CAAC,CAAC,aAAa,WAAW,CAC/D,CACF,CACF,CAAC;IAEJ,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvC,OAAO;QACL,KAAK,EAAE,0BAA0B;QACjC,OAAO,EAAE,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC;QAC9B,QAAQ,EAAE,CAAC;KACZ,CAAC;AACJ,CAAC,CAAC"}
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tesla charging-CSV import for pic_invoices.
|
|
3
|
-
*
|
|
4
|
-
* Pipeline: raw CSV string
|
|
5
|
-
* → csv-parse (structure: delimiters, quoting, headers)
|
|
6
|
-
* → zod row schema (semantics: "N/A" → null, "22.1285 kwh" → value+unit,
|
|
7
|
-
* "0.51/kwh" → value+unit, NUMERIC precision checks, ISO dates)
|
|
8
|
-
* → PicInvoicesInitializer
|
|
9
|
-
* → parameterized INSERT (numerics stay strings; pg casts to NUMERIC losslessly)
|
|
10
|
-
*
|
|
11
|
-
* deps: npm i csv-parse postgres zod
|
|
12
|
-
*/
|
|
13
|
-
import type { Invoice, Meta } from "@mxpicture/tesla-superchargers-mate/types";
|
|
14
|
-
import { z } from "zod";
|
|
15
|
-
export declare const invoicesCsvSchema: z.ZodObject<{
|
|
16
|
-
ChargeStartDateTime: z.ZodPipe<z.ZodString, z.ZodTransform<Date, string>>;
|
|
17
|
-
Name: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
18
|
-
Vin: z.ZodString;
|
|
19
|
-
Model: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
20
|
-
Country: z.ZodString;
|
|
21
|
-
SiteLocationName: z.ZodString;
|
|
22
|
-
Description: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
23
|
-
QuantityBase: z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
24
|
-
value: number;
|
|
25
|
-
unit: string;
|
|
26
|
-
}, string>>;
|
|
27
|
-
QuantityTier1: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
28
|
-
value: number;
|
|
29
|
-
unit: string;
|
|
30
|
-
}, string>>>>;
|
|
31
|
-
QuantityTier2: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
32
|
-
value: number;
|
|
33
|
-
unit: string;
|
|
34
|
-
}, string>>>>;
|
|
35
|
-
QuantityTier3: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
36
|
-
value: number;
|
|
37
|
-
unit: string;
|
|
38
|
-
}, string>>>>;
|
|
39
|
-
QuantityTier4: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
40
|
-
value: number;
|
|
41
|
-
unit: string;
|
|
42
|
-
}, string>>>>;
|
|
43
|
-
InvoiceNumber: z.ZodString;
|
|
44
|
-
UnitCostBase: z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
45
|
-
value: number;
|
|
46
|
-
unit: string;
|
|
47
|
-
}, string>>;
|
|
48
|
-
UnitCostTier1: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
49
|
-
value: number;
|
|
50
|
-
unit: string;
|
|
51
|
-
}, string>>>>;
|
|
52
|
-
UnitCostTier2: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
53
|
-
value: number;
|
|
54
|
-
unit: string;
|
|
55
|
-
}, string>>>>;
|
|
56
|
-
UnitCostTier3: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
57
|
-
value: number;
|
|
58
|
-
unit: string;
|
|
59
|
-
}, string>>>>;
|
|
60
|
-
UnitCostTier4: z.ZodPreprocess<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<{
|
|
61
|
-
value: number;
|
|
62
|
-
unit: string;
|
|
63
|
-
}, string>>>>;
|
|
64
|
-
VAT: z.ZodString;
|
|
65
|
-
"Total Exc. VAT": z.ZodString;
|
|
66
|
-
"Total Inc. VAT": z.ZodString;
|
|
67
|
-
Status: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
68
|
-
Invoice: z.ZodPreprocess<z.ZodNullable<z.ZodString>>;
|
|
69
|
-
}, z.core.$strip>;
|
|
70
|
-
export type InvoicesCsv = z.infer<typeof invoicesCsvSchema>;
|
|
71
|
-
export interface InvoicesCsvError {
|
|
72
|
-
line: number;
|
|
73
|
-
issues: z.core.$ZodIssue[];
|
|
74
|
-
}
|
|
75
|
-
/** One line per invalid row: `line 3: QuantityBase: invalid quantity: "x"`. */
|
|
76
|
-
export declare const formatInvoicesCsvErrors: (errors: InvoicesCsvError[]) => string;
|
|
77
|
-
export declare const parseInvoicesCsv: (csvText: string) => {
|
|
78
|
-
invoices: InvoicesCsv[];
|
|
79
|
-
errors: InvoicesCsvError[];
|
|
80
|
-
};
|
|
81
|
-
export declare const fromInvoiceCsv: ({ csv, meta, }: {
|
|
82
|
-
csv: InvoicesCsv;
|
|
83
|
-
meta: Meta;
|
|
84
|
-
}) => Invoice;
|
|
85
|
-
//# sourceMappingURL=invoicesCsv.common.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"invoicesCsv.common.d.ts","sourceRoot":"","sources":["../../src/common/invoicesCsv.common.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAAK,EACV,OAAO,EAEP,IAAI,EACL,MAAM,2CAA2C,CAAC;AAEnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAmGxB,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAwB5B,CAAC;AAEH,MAAM,MAAM,WAAW,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAM5D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;CAC5B;AAED,+EAA+E;AAC/E,eAAO,MAAM,uBAAuB,GAAI,QAAQ,gBAAgB,EAAE,KAAG,MAQtD,CAAC;AAEhB,eAAO,MAAM,gBAAgB,GAC3B,SAAS,MAAM,KACd;IACD,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,MAAM,EAAE,gBAAgB,EAAE,CAAC;CAoB5B,CAAC;AAEF,eAAO,MAAM,cAAc,GAAI,gBAG5B;IACD,GAAG,EAAE,WAAW,CAAC;IACjB,IAAI,EAAE,IAAI,CAAC;CACZ,KAAG,OAgCH,CAAC"}
|
|
@@ -1,185 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tesla charging-CSV import for pic_invoices.
|
|
3
|
-
*
|
|
4
|
-
* Pipeline: raw CSV string
|
|
5
|
-
* → csv-parse (structure: delimiters, quoting, headers)
|
|
6
|
-
* → zod row schema (semantics: "N/A" → null, "22.1285 kwh" → value+unit,
|
|
7
|
-
* "0.51/kwh" → value+unit, NUMERIC precision checks, ISO dates)
|
|
8
|
-
* → PicInvoicesInitializer
|
|
9
|
-
* → parameterized INSERT (numerics stay strings; pg casts to NUMERIC losslessly)
|
|
10
|
-
*
|
|
11
|
-
* deps: npm i csv-parse postgres zod
|
|
12
|
-
*/
|
|
13
|
-
import { removeUndefined } from "@mxpicture/tesla-superchargers-mate/transform";
|
|
14
|
-
import { parse } from "csv-parse/sync";
|
|
15
|
-
import { z } from "zod";
|
|
16
|
-
/* ------------------------------------------------------------------ */
|
|
17
|
-
/* helpers */
|
|
18
|
-
/* ------------------------------------------------------------------ */
|
|
19
|
-
const castNum = (name, str) => {
|
|
20
|
-
const value = str === null ? str : Number(str);
|
|
21
|
-
if (value === null || !Number.isFinite(value))
|
|
22
|
-
throw new Error(`invalid ${name}: "${str}"`);
|
|
23
|
-
return value;
|
|
24
|
-
};
|
|
25
|
-
/** "N/A" / "" / whitespace → null, everything else → trimmed string. */
|
|
26
|
-
const naToNull = (v) => {
|
|
27
|
-
if (typeof v !== "string")
|
|
28
|
-
return v;
|
|
29
|
-
const t = v.trim();
|
|
30
|
-
return t === "" || t.toUpperCase() === "N/A" ? null : t;
|
|
31
|
-
};
|
|
32
|
-
/**
|
|
33
|
-
* Decimal kept as *string* (matches Kanel's typing of pg NUMERIC) with a
|
|
34
|
-
* precision/scale check mirroring the column definition, so bad values fail
|
|
35
|
-
* in validation instead of as a pg error mid-insert.
|
|
36
|
-
*/
|
|
37
|
-
const numericString = (precision, scale) => z
|
|
38
|
-
.string()
|
|
39
|
-
.trim()
|
|
40
|
-
.regex(/^-?\d+(\.\d+)?$/, "not a decimal number")
|
|
41
|
-
.refine((s) => {
|
|
42
|
-
const [int = "", frac = ""] = s.replace("-", "").split(".");
|
|
43
|
-
return frac.length <= scale && int.length <= precision - scale;
|
|
44
|
-
}, `exceeds NUMERIC(${precision}, ${scale})`);
|
|
45
|
-
/** "22.1285 kwh" → { value: 22.1285, unit: "kwh" } (unit optional). */
|
|
46
|
-
const quantity = z
|
|
47
|
-
.string()
|
|
48
|
-
.trim()
|
|
49
|
-
.transform((s, ctx) => {
|
|
50
|
-
const m = s.match(/^(-?\d+(?:\.\d+)?)(?:\s+(\S+))?$/);
|
|
51
|
-
if (!m) {
|
|
52
|
-
ctx.addIssue({ code: "custom", message: `invalid quantity: "${s}"` });
|
|
53
|
-
return z.NEVER;
|
|
54
|
-
}
|
|
55
|
-
const value = m[1] === null ? m[1] : Number(m[1]);
|
|
56
|
-
if (value === null || !Number.isFinite(value)) {
|
|
57
|
-
ctx.addIssue({ code: "custom", message: `invalid quantity: "${s}"` });
|
|
58
|
-
return z.NEVER;
|
|
59
|
-
}
|
|
60
|
-
return { value, unit: m[2]?.toLowerCase() ?? null };
|
|
61
|
-
})
|
|
62
|
-
.refine((q) => numericString(8, 4).safeParse(String(q.value)).success, {
|
|
63
|
-
message: "quantity exceeds NUMERIC(8, 4)",
|
|
64
|
-
});
|
|
65
|
-
/** "0.51/kwh" → { value: 0.51, unit: "kwh" }. */
|
|
66
|
-
const unitCost = z
|
|
67
|
-
.string()
|
|
68
|
-
.trim()
|
|
69
|
-
.transform((s, ctx) => {
|
|
70
|
-
const m = s.match(/^(-?\d+(?:\.\d+)?)\s*\/\s*(\S+)$/);
|
|
71
|
-
if (!m) {
|
|
72
|
-
ctx.addIssue({ code: "custom", message: `invalid unit cost: "${s}"` });
|
|
73
|
-
return z.NEVER;
|
|
74
|
-
}
|
|
75
|
-
const value = m[1] === null ? m[1] : Number(m[1]);
|
|
76
|
-
if (value === null || !Number.isFinite(value)) {
|
|
77
|
-
ctx.addIssue({ code: "custom", message: `invalid unit cost: "${s}"` });
|
|
78
|
-
return z.NEVER;
|
|
79
|
-
}
|
|
80
|
-
return { value, unit: m[2].toLowerCase() };
|
|
81
|
-
})
|
|
82
|
-
.refine((c) => numericString(4, 2).safeParse(String(c.value)).success, {
|
|
83
|
-
message: "unit cost exceeds NUMERIC(4, 2)",
|
|
84
|
-
});
|
|
85
|
-
/** ISO-8601 with offset ("2026-03-31T14:56:00+02:00") → Date. */
|
|
86
|
-
const isoDate = z
|
|
87
|
-
.string()
|
|
88
|
-
.trim()
|
|
89
|
-
.transform((s, ctx) => {
|
|
90
|
-
const d = new Date(s);
|
|
91
|
-
if (Number.isNaN(d.getTime())) {
|
|
92
|
-
ctx.addIssue({ code: "custom", message: `invalid date: "${s}"` });
|
|
93
|
-
return z.NEVER;
|
|
94
|
-
}
|
|
95
|
-
return d;
|
|
96
|
-
});
|
|
97
|
-
const nullable = (schema) => z.preprocess(naToNull, schema.nullable());
|
|
98
|
-
const nonEmpty = z.string().trim().min(1);
|
|
99
|
-
/* ------------------------------------------------------------------ */
|
|
100
|
-
/* CSV row schema (keys = exact CSV headers) */
|
|
101
|
-
/* ------------------------------------------------------------------ */
|
|
102
|
-
export const invoicesCsvSchema = z.object({
|
|
103
|
-
ChargeStartDateTime: isoDate,
|
|
104
|
-
Name: nullable(nonEmpty),
|
|
105
|
-
Vin: nonEmpty,
|
|
106
|
-
Model: nullable(nonEmpty),
|
|
107
|
-
Country: nonEmpty,
|
|
108
|
-
SiteLocationName: nonEmpty,
|
|
109
|
-
Description: nullable(nonEmpty),
|
|
110
|
-
QuantityBase: quantity,
|
|
111
|
-
QuantityTier1: nullable(quantity),
|
|
112
|
-
QuantityTier2: nullable(quantity),
|
|
113
|
-
QuantityTier3: nullable(quantity),
|
|
114
|
-
QuantityTier4: nullable(quantity),
|
|
115
|
-
InvoiceNumber: nonEmpty,
|
|
116
|
-
UnitCostBase: unitCost,
|
|
117
|
-
UnitCostTier1: nullable(unitCost),
|
|
118
|
-
UnitCostTier2: nullable(unitCost),
|
|
119
|
-
UnitCostTier3: nullable(unitCost),
|
|
120
|
-
UnitCostTier4: nullable(unitCost),
|
|
121
|
-
VAT: numericString(5, 2),
|
|
122
|
-
"Total Exc. VAT": numericString(5, 2),
|
|
123
|
-
"Total Inc. VAT": numericString(5, 2),
|
|
124
|
-
Status: nullable(nonEmpty),
|
|
125
|
-
Invoice: nullable(z.string().trim().url()),
|
|
126
|
-
});
|
|
127
|
-
/** One line per invalid row: `line 3: QuantityBase: invalid quantity: "x"`. */
|
|
128
|
-
export const formatInvoicesCsvErrors = (errors) => errors
|
|
129
|
-
.map(({ line, issues }) => `line ${line}: ${issues
|
|
130
|
-
.map((issue) => `${issue.path.join(".")}: ${issue.message}`)
|
|
131
|
-
.join("; ")}`)
|
|
132
|
-
.join("\n");
|
|
133
|
-
export const parseInvoicesCsv = (csvText) => {
|
|
134
|
-
// csv-parse handles quoting ("Windischeschenbach, Germany"), BOM, CRLF.
|
|
135
|
-
const records = parse(csvText, {
|
|
136
|
-
columns: true, // first line = header, rows become objects
|
|
137
|
-
bom: true,
|
|
138
|
-
skip_empty_lines: true,
|
|
139
|
-
trim: true,
|
|
140
|
-
});
|
|
141
|
-
const invoices = [];
|
|
142
|
-
const errors = [];
|
|
143
|
-
records.forEach((record, i) => {
|
|
144
|
-
const result = invoicesCsvSchema.safeParse(record);
|
|
145
|
-
if (result.success)
|
|
146
|
-
invoices.push(result.data);
|
|
147
|
-
else
|
|
148
|
-
errors.push({ line: i + 2, issues: result.error.issues });
|
|
149
|
-
});
|
|
150
|
-
return { invoices, errors };
|
|
151
|
-
};
|
|
152
|
-
export const fromInvoiceCsv = ({ csv, meta, }) => {
|
|
153
|
-
const result = {
|
|
154
|
-
id: undefined,
|
|
155
|
-
chargingProcessesId: null,
|
|
156
|
-
fetched_at: meta.fetched_at,
|
|
157
|
-
last_fetch_uuid: meta.last_fetch_uuid,
|
|
158
|
-
chargeStartDateTime: csv.ChargeStartDateTime,
|
|
159
|
-
name: csv.Name,
|
|
160
|
-
vin: csv.Vin,
|
|
161
|
-
model: csv.Model,
|
|
162
|
-
country: csv.Country,
|
|
163
|
-
siteLocationName: csv.SiteLocationName,
|
|
164
|
-
description: csv.Description,
|
|
165
|
-
ucom: csv.QuantityBase.unit,
|
|
166
|
-
quantityBase: csv.QuantityBase.value,
|
|
167
|
-
quantityTier1: csv.QuantityTier1?.value,
|
|
168
|
-
quantityTier2: csv.QuantityTier2?.value,
|
|
169
|
-
quantityTier3: csv.QuantityTier3?.value,
|
|
170
|
-
quantityTier4: csv.QuantityTier4?.value,
|
|
171
|
-
invoiceNumber: csv.InvoiceNumber,
|
|
172
|
-
unitCostBase: csv.UnitCostBase.value,
|
|
173
|
-
unitCostTier1: csv.UnitCostTier1?.value,
|
|
174
|
-
unitCostTier2: csv.UnitCostTier2?.value,
|
|
175
|
-
unitCostTier3: csv.UnitCostTier3?.value,
|
|
176
|
-
unitCostTier4: csv.UnitCostTier4?.value,
|
|
177
|
-
vat: castNum("VAT", csv.VAT),
|
|
178
|
-
totalExcVat: castNum("Total Exc. VAT", csv["Total Exc. VAT"]),
|
|
179
|
-
totalIncVat: castNum("Total Inc. VAT", csv["Total Inc. VAT"]),
|
|
180
|
-
status: csv.Status,
|
|
181
|
-
invoice: csv.Invoice,
|
|
182
|
-
};
|
|
183
|
-
return removeUndefined(result);
|
|
184
|
-
};
|
|
185
|
-
//# sourceMappingURL=invoicesCsv.common.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"invoicesCsv.common.js","sourceRoot":"","sources":["../../src/common/invoicesCsv.common.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pure pricebook helpers: snapshot-group comparison for the history sync and
|
|
3
|
-
* the time-of-use window filter for prices-at-a-time lookups. No DB access —
|
|
4
|
-
* unit-testable in isolation.
|
|
5
|
-
*/
|
|
6
|
-
import type { ChargingRate, PricebookContent } from "../types/pricebooks.types.js";
|
|
7
|
-
/** Feed values identifying the row that prices a Tesla vehicle's charging. */
|
|
8
|
-
export declare const TESLA_VEHICLE_MAKE = "tsla";
|
|
9
|
-
export declare const CHARGING_FEE_TYPE = "charging";
|
|
10
|
-
export declare const KWH_UOM = "kwh";
|
|
11
|
-
/** Canonical `HH:MM:SS` for a TIME value (Date → its UTC wall time). */
|
|
12
|
-
export declare const normalizeTime: (time: Date | string) => string;
|
|
13
|
-
export declare const normalizeRate: (rate: string | number) => string;
|
|
14
|
-
/** One row's content columns as a canonical string, order-independent in `days`. */
|
|
15
|
-
export declare const canonicalRow: (row: PricebookContent) => string;
|
|
16
|
-
/** Local weekday (0=Sunday … 6=Saturday, matching the feed's `days`) and `HH:MM:SS` of `at` in an IANA time zone. */
|
|
17
|
-
export declare const localDayTime: (at: Date, timeZone: string) => {
|
|
18
|
-
weekday: number;
|
|
19
|
-
time: string;
|
|
20
|
-
};
|
|
21
|
-
/**
|
|
22
|
-
* Does this row's time-of-use window cover the instant `at` (in the charger's
|
|
23
|
-
* time zone)? Empty `days` means no day restriction (non-TOU rows). The feed
|
|
24
|
-
* partitions a day into windows that never span into the next day, with
|
|
25
|
-
* `00:00` as `end` meaning end-of-day (e.g. `00:00–16:00`, `16:00–20:00`,
|
|
26
|
-
* `20:00–00:00`); `start == end == 00:00` is a whole-day window. `end` is
|
|
27
|
-
* exclusive — each instant falls into exactly one window of a partition.
|
|
28
|
-
*/
|
|
29
|
-
export declare const pricebookCoversInstant: (row: Pick<PricebookContent, "days" | "start_time" | "end_time">, at: Date, timeZone: string) => boolean;
|
|
30
|
-
/**
|
|
31
|
-
* Order-independent multiset equality over the content columns — the "did any
|
|
32
|
-
* price change?" check of the history sync. Meta columns (`fetched_at`,
|
|
33
|
-
* `last_fetch_uuid`, ids) are ignored. Normalization matters: a false
|
|
34
|
-
* "different" here creates a bogus new group on every fetch.
|
|
35
|
-
*/
|
|
36
|
-
export declare const samePricebookGroup: (a: PricebookContent[], b: PricebookContent[]) => boolean;
|
|
37
|
-
/**
|
|
38
|
-
* The per-kWh rate a Tesla vehicle pays for charging, picked from the
|
|
39
|
-
* variant rows valid at one instant (member/non-member × vehicle make ×
|
|
40
|
-
* fee type, as `findPrices` returns them): fee type "charging", vehicle
|
|
41
|
-
* make "tesla", the non-member row when both memberships are present
|
|
42
|
-
* (Tesla drivers need no membership). Returns null when no such row
|
|
43
|
-
* exists or the row doesn't bill per kWh — per-minute billing depends on
|
|
44
|
-
* charging power, which stored energy totals don't carry.
|
|
45
|
-
*/
|
|
46
|
-
export declare const teslaChargingRate: (rows: PricebookContent[]) => ChargingRate | null;
|
|
47
|
-
//# sourceMappingURL=pricebooks.common.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pricebooks.common.d.ts","sourceRoot":"","sources":["../../src/common/pricebooks.common.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,KAAK,EACV,YAAY,EACZ,gBAAgB,EACjB,MAAM,8BAA8B,CAAC;AAEtC,8EAA8E;AAC9E,eAAO,MAAM,kBAAkB,SAAS,CAAC;AACzC,eAAO,MAAM,iBAAiB,aAAa,CAAC;AAC5C,eAAO,MAAM,OAAO,QAAQ,CAAC;AAE7B,wEAAwE;AACxE,eAAO,MAAM,aAAa,GAAI,MAAM,IAAI,GAAG,MAAM,KAAG,MAInD,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,GAAG,MAAM,KAAG,MAC7B,CAAC;AAE1B,oFAAoF;AACpF,eAAO,MAAM,YAAY,GAAI,KAAK,gBAAgB,KAAG,MAcxC,CAAC;AAEd,qHAAqH;AACrH,eAAO,MAAM,YAAY,GACvB,IAAI,IAAI,EACR,UAAU,MAAM,KACf;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAkBjC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GACjC,KAAK,IAAI,CAAC,gBAAgB,EAAE,MAAM,GAAG,YAAY,GAAG,UAAU,CAAC,EAC/D,IAAI,IAAI,EACR,UAAU,MAAM,KACf,OASF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB,GAC7B,GAAG,gBAAgB,EAAE,EACrB,GAAG,gBAAgB,EAAE,KACpB,OAKF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,GAC5B,MAAM,gBAAgB,EAAE,KACvB,YAAY,GAAG,IAWjB,CAAC"}
|
|
@@ -1,95 +0,0 @@
|
|
|
1
|
-
/** Feed values identifying the row that prices a Tesla vehicle's charging. */
|
|
2
|
-
export const TESLA_VEHICLE_MAKE = "tsla";
|
|
3
|
-
export const CHARGING_FEE_TYPE = "charging";
|
|
4
|
-
export const KWH_UOM = "kwh";
|
|
5
|
-
/** Canonical `HH:MM:SS` for a TIME value (Date → its UTC wall time). */
|
|
6
|
-
export const normalizeTime = (time) => {
|
|
7
|
-
if (time instanceof Date)
|
|
8
|
-
return time.toISOString().slice(11, 19); // transforms build Date(0) + UTC hours
|
|
9
|
-
const [h = "0", m = "0", s = "0"] = time.split(".")[0].split(":");
|
|
10
|
-
return [h, m, s].map((part) => part.padStart(2, "0")).join(":");
|
|
11
|
-
};
|
|
12
|
-
export const normalizeRate = (rate) => Number(rate).toFixed(2);
|
|
13
|
-
/** One row's content columns as a canonical string, order-independent in `days`. */
|
|
14
|
-
export const canonicalRow = (row) => [
|
|
15
|
-
row.currency_code,
|
|
16
|
-
row.uom,
|
|
17
|
-
[...row.days].sort((a, b) => a - b).join(","),
|
|
18
|
-
normalizeTime(row.start_time),
|
|
19
|
-
normalizeTime(row.end_time),
|
|
20
|
-
row.vehicle_make_type,
|
|
21
|
-
row.fee_type,
|
|
22
|
-
row.is_member_pricebook,
|
|
23
|
-
row.is_tou,
|
|
24
|
-
normalizeRate(row.rate_base),
|
|
25
|
-
normalizeRate(row.rate_tier_1),
|
|
26
|
-
normalizeRate(row.rate_tier_2),
|
|
27
|
-
].join("|");
|
|
28
|
-
/** Local weekday (0=Sunday … 6=Saturday, matching the feed's `days`) and `HH:MM:SS` of `at` in an IANA time zone. */
|
|
29
|
-
export const localDayTime = (at, timeZone) => {
|
|
30
|
-
const parts = new Intl.DateTimeFormat("en-US", {
|
|
31
|
-
timeZone,
|
|
32
|
-
weekday: "short",
|
|
33
|
-
hourCycle: "h23",
|
|
34
|
-
hour: "2-digit",
|
|
35
|
-
minute: "2-digit",
|
|
36
|
-
second: "2-digit",
|
|
37
|
-
}).formatToParts(at);
|
|
38
|
-
const part = (type) => parts.find((p) => p.type === type)?.value ?? "";
|
|
39
|
-
const weekday = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"].indexOf(part("weekday"));
|
|
40
|
-
return {
|
|
41
|
-
weekday,
|
|
42
|
-
time: `${part("hour")}:${part("minute")}:${part("second")}`,
|
|
43
|
-
};
|
|
44
|
-
};
|
|
45
|
-
/**
|
|
46
|
-
* Does this row's time-of-use window cover the instant `at` (in the charger's
|
|
47
|
-
* time zone)? Empty `days` means no day restriction (non-TOU rows). The feed
|
|
48
|
-
* partitions a day into windows that never span into the next day, with
|
|
49
|
-
* `00:00` as `end` meaning end-of-day (e.g. `00:00–16:00`, `16:00–20:00`,
|
|
50
|
-
* `20:00–00:00`); `start == end == 00:00` is a whole-day window. `end` is
|
|
51
|
-
* exclusive — each instant falls into exactly one window of a partition.
|
|
52
|
-
*/
|
|
53
|
-
export const pricebookCoversInstant = (row, at, timeZone) => {
|
|
54
|
-
const { weekday, time } = localDayTime(at, timeZone);
|
|
55
|
-
if (row.days.length > 0 && !row.days.includes(weekday))
|
|
56
|
-
return false;
|
|
57
|
-
const start = normalizeTime(row.start_time);
|
|
58
|
-
const end = normalizeTime(row.end_time);
|
|
59
|
-
if (start === "00:00:00" && end === "00:00:00")
|
|
60
|
-
return true; // whole day
|
|
61
|
-
if (start > end)
|
|
62
|
-
return time >= start || time < end; // end 00:00 = end of day
|
|
63
|
-
return time >= start && time < end;
|
|
64
|
-
};
|
|
65
|
-
/**
|
|
66
|
-
* Order-independent multiset equality over the content columns — the "did any
|
|
67
|
-
* price change?" check of the history sync. Meta columns (`fetched_at`,
|
|
68
|
-
* `last_fetch_uuid`, ids) are ignored. Normalization matters: a false
|
|
69
|
-
* "different" here creates a bogus new group on every fetch.
|
|
70
|
-
*/
|
|
71
|
-
export const samePricebookGroup = (a, b) => {
|
|
72
|
-
if (a.length !== b.length)
|
|
73
|
-
return false;
|
|
74
|
-
const canonical = (rows) => rows.map(canonicalRow).sort().join("\n");
|
|
75
|
-
return canonical(a) === canonical(b);
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* The per-kWh rate a Tesla vehicle pays for charging, picked from the
|
|
79
|
-
* variant rows valid at one instant (member/non-member × vehicle make ×
|
|
80
|
-
* fee type, as `findPrices` returns them): fee type "charging", vehicle
|
|
81
|
-
* make "tesla", the non-member row when both memberships are present
|
|
82
|
-
* (Tesla drivers need no membership). Returns null when no such row
|
|
83
|
-
* exists or the row doesn't bill per kWh — per-minute billing depends on
|
|
84
|
-
* charging power, which stored energy totals don't carry.
|
|
85
|
-
*/
|
|
86
|
-
export const teslaChargingRate = (rows) => {
|
|
87
|
-
const candidates = rows.filter((row) => row.fee_type.toLowerCase() === CHARGING_FEE_TYPE &&
|
|
88
|
-
row.vehicle_make_type.toLowerCase() === TESLA_VEHICLE_MAKE);
|
|
89
|
-
const row = candidates.find((candidate) => !candidate.is_member_pricebook) ??
|
|
90
|
-
candidates[0];
|
|
91
|
-
if (!row || row.uom.toLowerCase() !== KWH_UOM)
|
|
92
|
-
return null;
|
|
93
|
-
return { rate: Number(row.rate_base), currencyCode: row.currency_code };
|
|
94
|
-
};
|
|
95
|
-
//# sourceMappingURL=pricebooks.common.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pricebooks.common.js","sourceRoot":"","sources":["../../src/common/pricebooks.common.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal Pushover (https://pushover.net) sender. Mirrors the shape used by the
|
|
3
|
-
* sibling deployment scripts (a token/user app message with an optional
|
|
4
|
-
* priority), so it reuses the same PUSHOVER_* credentials the deployment already
|
|
5
|
-
* injects. Sending NEVER throws — a notify failure is logged and reported via
|
|
6
|
-
* the return value so it can't abort the run that is trying to alert. When
|
|
7
|
-
* either credential is missing the whole feature is a no-op.
|
|
8
|
-
*/
|
|
9
|
-
import type { PushoverConfig, PushoverMessage } from "../types/pushover.types.js";
|
|
10
|
-
/**
|
|
11
|
-
* Pushover credentials from `PUSHOVER_API_TOKEN` / `PUSHOVER_USER_KEY`, or null
|
|
12
|
-
* when either is unset (so the caller treats alerting as disabled).
|
|
13
|
-
*/
|
|
14
|
-
export declare const pushoverConfigFromEnv: () => PushoverConfig | null;
|
|
15
|
-
/** The form body Pushover expects. Pure, so it is unit-tested without a request. */
|
|
16
|
-
export declare const buildPushoverForm: (cfg: PushoverConfig, msg: PushoverMessage) => Record<string, string>;
|
|
17
|
-
/**
|
|
18
|
-
* POST one message to Pushover. Returns true on success; on any failure it logs
|
|
19
|
-
* via `logger` and returns false (never throws), so a notify error can't kill
|
|
20
|
-
* the caller.
|
|
21
|
-
*/
|
|
22
|
-
export declare const sendPushover: (cfg: PushoverConfig, msg: PushoverMessage, logger?: (m: string) => void) => Promise<boolean>;
|
|
23
|
-
//# sourceMappingURL=pushover.common.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pushover.common.d.ts","sourceRoot":"","sources":["../../src/common/pushover.common.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EACV,cAAc,EACd,eAAe,EAChB,MAAM,4BAA4B,CAAC;AAIpC;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAAO,cAAc,GAAG,IAKzD,CAAC;AAEF,oFAAoF;AACpF,eAAO,MAAM,iBAAiB,GAC5B,KAAK,cAAc,EACnB,KAAK,eAAe,KACnB,MAAM,CAAC,MAAM,EAAE,MAAM,CAMtB,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,YAAY,GACvB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,SAAQ,CAAC,CAAC,EAAE,MAAM,KAAK,IAAe,KACrC,OAAO,CAAC,OAAO,CAkBjB,CAAC"}
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Minimal Pushover (https://pushover.net) sender. Mirrors the shape used by the
|
|
3
|
-
* sibling deployment scripts (a token/user app message with an optional
|
|
4
|
-
* priority), so it reuses the same PUSHOVER_* credentials the deployment already
|
|
5
|
-
* injects. Sending NEVER throws — a notify failure is logged and reported via
|
|
6
|
-
* the return value so it can't abort the run that is trying to alert. When
|
|
7
|
-
* either credential is missing the whole feature is a no-op.
|
|
8
|
-
*/
|
|
9
|
-
const PUSHOVER_URL = "https://api.pushover.net/1/messages.json";
|
|
10
|
-
/**
|
|
11
|
-
* Pushover credentials from `PUSHOVER_API_TOKEN` / `PUSHOVER_USER_KEY`, or null
|
|
12
|
-
* when either is unset (so the caller treats alerting as disabled).
|
|
13
|
-
*/
|
|
14
|
-
export const pushoverConfigFromEnv = () => {
|
|
15
|
-
const token = process.env.PUSHOVER_API_TOKEN;
|
|
16
|
-
const user = process.env.PUSHOVER_USER_KEY;
|
|
17
|
-
if (!token || !user)
|
|
18
|
-
return null;
|
|
19
|
-
return { token, user };
|
|
20
|
-
};
|
|
21
|
-
/** The form body Pushover expects. Pure, so it is unit-tested without a request. */
|
|
22
|
-
export const buildPushoverForm = (cfg, msg) => ({
|
|
23
|
-
token: cfg.token,
|
|
24
|
-
user: cfg.user,
|
|
25
|
-
title: msg.title,
|
|
26
|
-
message: msg.message,
|
|
27
|
-
priority: String(msg.priority ?? 0),
|
|
28
|
-
});
|
|
29
|
-
/**
|
|
30
|
-
* POST one message to Pushover. Returns true on success; on any failure it logs
|
|
31
|
-
* via `logger` and returns false (never throws), so a notify error can't kill
|
|
32
|
-
* the caller.
|
|
33
|
-
*/
|
|
34
|
-
export const sendPushover = async (cfg, msg, logger = () => { }) => {
|
|
35
|
-
try {
|
|
36
|
-
const res = await fetch(PUSHOVER_URL, {
|
|
37
|
-
method: "POST",
|
|
38
|
-
body: new URLSearchParams(buildPushoverForm(cfg, msg)),
|
|
39
|
-
});
|
|
40
|
-
if (!res.ok) {
|
|
41
|
-
logger(`pushover send failed: HTTP ${res.status}`);
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
logger(`pushover sent: ${msg.title}`);
|
|
45
|
-
return true;
|
|
46
|
-
}
|
|
47
|
-
catch (e) {
|
|
48
|
-
logger(`pushover send failed: ${e instanceof Error ? e.message : String(e)}`);
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
};
|
|
52
|
-
//# sourceMappingURL=pushover.common.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pushover.common.js","sourceRoot":"","sources":["../../src/common/pushover.common.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAOH,MAAM,YAAY,GAAG,0CAA0C,CAAC;AAEhE;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAA0B,EAAE;IAC/D,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC;IAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;IAC3C,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI;QAAE,OAAO,IAAI,CAAC;IACjC,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AACzB,CAAC,CAAC;AAEF,oFAAoF;AACpF,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,GAAmB,EACnB,GAAoB,EACI,EAAE,CAAC,CAAC;IAC5B,KAAK,EAAE,GAAG,CAAC,KAAK;IAChB,IAAI,EAAE,GAAG,CAAC,IAAI;IACd,KAAK,EAAE,GAAG,CAAC,KAAK;IAChB,OAAO,EAAE,GAAG,CAAC,OAAO;IACpB,QAAQ,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAC;CACpC,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,EAC/B,GAAmB,EACnB,GAAoB,EACpB,SAA8B,GAAG,EAAE,GAAE,CAAC,EACpB,EAAE;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,YAAY,EAAE;YACpC,MAAM,EAAE,MAAM;YACd,IAAI,EAAE,IAAI,eAAe,CAAC,iBAAiB,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;SACvD,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,CAAC,8BAA8B,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC;YACnD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,CAAC,kBAAkB,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC;QACtC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,CACJ,yBAAyB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CACtE,CAAC;QACF,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sync.common.d.ts","sourceRoot":"","sources":["../../src/common/sync.common.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,eAAO,MAAM,yBAAyB,MAAM,CAAC;AAE7C,eAAO,MAAM,iBAAiB,UAM7B,CAAC"}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/** Abort the sync when the feed shrinks below this share of the active rows. */
|
|
2
|
-
export const CIRCUIT_BREAKER_MIN_RATIO = 0.5;
|
|
3
|
-
export const SYNC_META_COLUMNS = [
|
|
4
|
-
"fetched_at",
|
|
5
|
-
"last_fetch_uuid",
|
|
6
|
-
"failure_count",
|
|
7
|
-
"failure_notified_at",
|
|
8
|
-
"deleted_at",
|
|
9
|
-
];
|
|
10
|
-
//# sourceMappingURL=sync.common.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sync.common.js","sourceRoot":"","sources":["../../src/common/sync.common.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,MAAM,CAAC,MAAM,yBAAyB,GAAG,GAAG,CAAC;AAE7C,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,YAAY;IACZ,iBAAiB;IACjB,eAAe;IACf,qBAAqB;IACrB,YAAY;CACb,CAAC"}
|