@open-charging-cloud/chargy-core 0.11.3 → 0.12.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/CHANGELOG.md +158 -0
- package/README.md +228 -202
- package/dist/OCMF.d.ts.map +1 -1
- package/dist/OCPI.d.ts.map +1 -1
- package/dist/browser/index.js +201 -74
- package/dist/browser/index.js.map +1 -1
- package/dist/chargePoint.d.ts.map +1 -1
- package/dist/chargy.d.ts.map +1 -1
- package/dist/interfaces/CryptoUtils.d.ts.map +1 -1
- package/dist/interfaces/chargyInterfaces.d.ts +2 -1
- package/dist/interfaces/chargyInterfaces.d.ts.map +1 -1
- package/dist/interfaces/chargyLib.d.ts +2 -0
- package/dist/interfaces/chargyLib.d.ts.map +1 -1
- package/dist/interfaces/secp224k1.d.ts +2 -0
- package/dist/interfaces/secp224k1.d.ts.map +1 -1
- package/dist/node/index.js +201 -74
- package/dist/node/index.js.map +1 -1
- package/package.json +110 -106
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
While the version number is below 1.0.0, breaking changes are released in minor
|
|
7
|
+
versions and are always listed first below.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
## [0.12.0] - 2026-08-15
|
|
11
|
+
|
|
12
|
+
### Breaking
|
|
13
|
+
|
|
14
|
+
- **`IECCurves.secp512r1` is now `IECCurves.secp521r1`.** The old member named a
|
|
15
|
+
curve that does not exist. The rest of the library already used the correct
|
|
16
|
+
`secp521r1` throughout, so `IECCurves` had no valid member for the NIST P-521
|
|
17
|
+
curve it actually supports. Anything referring to the old name has to be
|
|
18
|
+
updated; the string value changes from `"secp512r1"` to `"secp521r1"` as well.
|
|
19
|
+
|
|
20
|
+
- **`signJSONMessage()` no longer reports success when it produced no signature.**
|
|
21
|
+
Previously it resolved to `true` even when every key pair was unusable, so a
|
|
22
|
+
caller guarding on the return value could publish an unsigned message. It now
|
|
23
|
+
resolves to `true` only if at least one signature was created, which matches
|
|
24
|
+
the behaviour that already applied to an empty key pair array. This also
|
|
25
|
+
affects the `signMessage()` and `SignMessage()` aliases. A signature that
|
|
26
|
+
fails its own verification is no longer left behind in the caller's message.
|
|
27
|
+
|
|
28
|
+
- **PDF/A-3 attachment extraction now requires PDF.js 6.2.** The bundled
|
|
29
|
+
`pdfjs-dist` moved from 6.0.227 to 6.2.108, whose `getAttachments()` returns a
|
|
30
|
+
`Map` and no longer delivers the file bytes eagerly. This is handled inside
|
|
31
|
+
the library and needs no change in consuming code, but applications pinning
|
|
32
|
+
their own `pdfjs-dist` need to move along.
|
|
33
|
+
|
|
34
|
+
- **The declared minimum Node version is now 22.13**, corrected from 20.19. The
|
|
35
|
+
old value never held: `pdfjs-dist` requires `>=22.13.0` and `file-type`
|
|
36
|
+
requires `>=22`, so installing on Node 20 produced `EBADENGINE` warnings and
|
|
37
|
+
failed outright under `engine-strict`. No code changed, the declaration now
|
|
38
|
+
states what the dependency tree already demanded.
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- **EMH and GDF signatures no longer depend on the verifying machine's time
|
|
43
|
+
zone.** These meters sign their own local time, and the offset used to
|
|
44
|
+
reconstruct the signed buffer was taken from the host instead of from the
|
|
45
|
+
record. A correctly signed charging record therefore verified in one time zone
|
|
46
|
+
and was reported as `InvalidSignature` in another. The offset is now read from
|
|
47
|
+
the timestamp when it states one, and otherwise assumed to be `Europe/Berlin`,
|
|
48
|
+
resolved for the instant of the record including daylight saving time. Alfen
|
|
49
|
+
was never affected.
|
|
50
|
+
|
|
51
|
+
- **A valid ChargePoint signature could be overwritten by a later public key.**
|
|
52
|
+
When no key matches the EVSE Id, all available keys are tried in turn, but the
|
|
53
|
+
loop did not stop after a successful verification, so a subsequent
|
|
54
|
+
non-matching key turned a valid result into `InvalidSignature`.
|
|
55
|
+
|
|
56
|
+
- **secp224k1 verification accepted public keys that are not on the curve** and
|
|
57
|
+
fed them straight into the group arithmetic. Points are now validated against
|
|
58
|
+
`y² = x³ + 5` with reduced coordinates, and verification fails closed instead
|
|
59
|
+
of throwing, so a caller trying several candidate keys is not interrupted.
|
|
60
|
+
Two arithmetic defects behind it were corrected as well: `modInv()` returned
|
|
61
|
+
`1` for a non-invertible value instead of reporting that no inverse exists,
|
|
62
|
+
and `ECadd()` divided by zero when adding a point to itself, silently
|
|
63
|
+
returning a result that was not even on the curve.
|
|
64
|
+
|
|
65
|
+
- **P-521 charging sessions showed no hash information**, because the display
|
|
66
|
+
branch matched the misspelled curve name.
|
|
67
|
+
|
|
68
|
+
- `npm run typecheck` and `npm run lint` pass again. The type error came from
|
|
69
|
+
`@types/node` 26 dropping the `createPublicKey(KeyObject)` overload; the lint
|
|
70
|
+
errors were two nullable booleans in a conditional.
|
|
71
|
+
|
|
72
|
+
- **OCMF charging sessions no longer all carry the same identifier.** The
|
|
73
|
+
session `@id` was a string literal, so every record parsed from OCMF — across
|
|
74
|
+
different meters, containers and charging processes — was labelled
|
|
75
|
+
`1554181214441:-1965658344385548683:2`. It is now `OCMF-` followed by the
|
|
76
|
+
SHA-256 over the canonical form of the payload and signature of each OCMF
|
|
77
|
+
document the session was built from: reproducible for a given record, and
|
|
78
|
+
distinct between records. Canonical rather than the document text, so that
|
|
79
|
+
formatting the record does not carry — pretty-printed JSON, or line endings
|
|
80
|
+
rewritten by a checkout — cannot change it. The record-level `@id` follows it.
|
|
81
|
+
|
|
82
|
+
- **OCMF charging sessions report their actual start and end.** `begin` and
|
|
83
|
+
`end` were the literal `"?"`, both on the session and, since it copies them,
|
|
84
|
+
on the record. They are now the earliest and latest reading timestamp, ordered
|
|
85
|
+
by instant rather than lexically, because the timestamps keep the offset the
|
|
86
|
+
meter reported.
|
|
87
|
+
|
|
88
|
+
- **OCPI containers no longer drop their EVSE Id and meter information.** The
|
|
89
|
+
container infos handed to the OCMF parser carried an `EVSEIds` field that does
|
|
90
|
+
not exist on `IContainerInfos`, so it was silently ignored and the charging
|
|
91
|
+
session ended up without an `EVSEId`; the `meterInfo` block was not passed on
|
|
92
|
+
at all. Both are now converted into the `EVSEs` and `energyMeters` the parser
|
|
93
|
+
actually merges, and what the signed OCMF payload states about the meter takes
|
|
94
|
+
precedence over the container, which only fills the gaps.
|
|
95
|
+
|
|
96
|
+
### Added
|
|
97
|
+
|
|
98
|
+
- `url` on `IManufacturer`, so that a manufacturer URL supplied by a container
|
|
99
|
+
survives. OCMF itself has no field for it.
|
|
100
|
+
- `secp224k1.isOnCurve()` for validating a point against the curve equation.
|
|
101
|
+
- `timeZoneOffsetMinutes()` and `meterTimeZone` in `chargyLib`, which resolve a
|
|
102
|
+
daylight-saving-aware offset for an IANA time zone at a given instant.
|
|
103
|
+
- ML-DSA-44 and ML-DSA-87 are recognised when parsing DER public keys; only
|
|
104
|
+
ML-DSA-65 was mapped before.
|
|
105
|
+
- Test fixtures for the Porsche Charging Data Format (PCDF).
|
|
106
|
+
|
|
107
|
+
### Internal dependencies
|
|
108
|
+
|
|
109
|
+
- The Noble cryptography stack moved to `@noble/curves` 2.3.0,
|
|
110
|
+
`@noble/hashes` 2.3.0 and `@noble/post-quantum` 0.7.0. The three are updated
|
|
111
|
+
together on purpose: `@noble/post-quantum` 0.6.1 pins curves and hashes to
|
|
112
|
+
`~2.2.0`, so raising curves on its own would have installed a second, nested
|
|
113
|
+
copy of both rather than upgrading them. 0.7.0 asks for `~2.3.0`, which keeps
|
|
114
|
+
a single deduplicated copy of each.
|
|
115
|
+
|
|
116
|
+
### Security
|
|
117
|
+
|
|
118
|
+
- `pdfjs-dist` 6.0.227 → 6.2.108, closing
|
|
119
|
+
[GHSA-hq66-cqwq-w95j](https://github.com/advisories/GHSA-hq66-cqwq-w95j)
|
|
120
|
+
(high severity: arbitrary JavaScript execution when opening a malicious PDF).
|
|
121
|
+
- `postcss` 8.5.16 → 8.5.26 and `brace-expansion` 5.0.7 → 5.0.9, both build-time
|
|
122
|
+
dependencies.
|
|
123
|
+
- `npm audit --omit=dev` now reports only `elliptic`, which has no fix available
|
|
124
|
+
and is used solely for verifying legacy P-192 charging data.
|
|
125
|
+
|
|
126
|
+
### Internal
|
|
127
|
+
|
|
128
|
+
Nothing here changes the published package; it is listed for contributors.
|
|
129
|
+
|
|
130
|
+
- CI and Nightly GitHub Actions workflows. CI gates every push across three legs
|
|
131
|
+
(Ubuntu on the declared minimum Node 22.13 and on 26, Windows on 24) and
|
|
132
|
+
uploads JUnit results per leg. Nightly repeats that, additionally installs
|
|
133
|
+
without the lockfile so an upstream release that breaks us shows up before a
|
|
134
|
+
lockfile refresh pulls it in, and reports `npm audit`.
|
|
135
|
+
- `pdfjs-dist` stays pinned to an exact version on purpose, since it has shipped
|
|
136
|
+
a silently breaking attachment API change within a minor release. See
|
|
137
|
+
"PDF.js Version Pin" in the README before raising it.
|
|
138
|
+
- The test suite pins `TZ` to `UTC`, deliberately not `Europe/Berlin`, so that
|
|
139
|
+
code reading the time zone from the host fails the suite instead of passing on
|
|
140
|
+
a German workstation.
|
|
141
|
+
- `CHARGY_UPDATE_FIXTURES=1` regenerates the expected verification reports
|
|
142
|
+
rather than having a dozen golden files edited by hand.
|
|
143
|
+
- New tests for secp224k1, for signed timestamps, and for the OCMF session
|
|
144
|
+
identity. The OCPI test is no longer skipped. Three PTB container tests remain
|
|
145
|
+
skipped: their fixtures were signed over payloads that OCMF rejects, so they
|
|
146
|
+
have never run and need regenerating.
|
|
147
|
+
- The BSM `ocmf_withoutIF` fixture was a byte-identical copy of its neighbour
|
|
148
|
+
and is replaced by `ocmf_withIF.xml`, which covers the branch that actually
|
|
149
|
+
lacked one. Since identification flags sit inside the signed payload, that
|
|
150
|
+
fixture is generated and signed by a script committed next to it.
|
|
151
|
+
- The `.npmignore` was removed. With a `files` array it had no effect, which
|
|
152
|
+
packing with and without it confirmed.
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
## [0.11.3] and earlier
|
|
156
|
+
|
|
157
|
+
See the commit history at
|
|
158
|
+
<https://github.com/OpenChargingCloud/ChargyCore.TS/commits/master>.
|
package/README.md
CHANGED
|
@@ -1,202 +1,228 @@
|
|
|
1
|
-
# Chargy Core
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- **
|
|
25
|
-
- **
|
|
26
|
-
- **
|
|
27
|
-
- **
|
|
28
|
-
|
|
29
|
-
- **
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
[
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
- **
|
|
56
|
-
- **
|
|
57
|
-
- **
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
```bash
|
|
80
|
-
npm install @open-charging-cloud/chargy-core
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
npm
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
1
|
+
# Chargy Core - TypeScript
|
|
2
|
+
|
|
3
|
+
[](https://github.com/OpenChargingCloud/ChargyCore.TS/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/OpenChargingCloud/ChargyCore.TS/actions/workflows/nightly.yml)
|
|
5
|
+
|
|
6
|
+
Chargy Core is a transparency software library for the validation of secure and transparent e-mobility charging processes, as defined by the *German Calibration Law ("Eichrecht")* in combination with the [Alternative Fuels Infrastructure Regulation (AFIR)](https://transport.ec.europa.eu/transport-themes/clean-transport/alternative-fuels-sustainable-mobility-europe/alternative-fuels-infrastructure_en) and the new [Measuring instruments (MID)](https://single-market-economy.ec.europa.eu/single-market/goods/european-standards/harmonised-standards/measuring-instruments-mid_en) of the European Commission and the [European Digital Quality Infrastructure](https://www.qi-digital.de/en/). The software allows you to verify the cryptographic signatures of energy measurements within charge detail records and comes with a couple of useful extentions to simplify the entire process for endusers and operators.
|
|
7
|
+
|
|
8
|
+
This software is written as a modern ESM TypeScript package with generated declaration files, providing shared core functionality for the Chargy Desktop, Web & Mobile applications.
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
## Benefits of Chargy
|
|
12
|
+
|
|
13
|
+
1. Chargy comes with __*meta data*__. True charging transparency is more than just signed smart meter values. Chargy allows you to group multiple signed smart meter values to entire charging sessions and to add additional meta data like EVSE information, geo coordinates, tariffs, ... within your backend in order to improve the user experience for the ev drivers.
|
|
14
|
+
2. Chargy is __*secure*__. Chargy implements a public key infrastructure for managing certificates of smart meters, EVSEs, charging stations, charging station operators and e-mobility providers. By this the ev driver will always retrieve the correct public key to verify a charging process automatically and without complicated manual lookups in external databases.
|
|
15
|
+
3. Chargy is __*Open Source*__. In contrast to other vendors in e-mobility, we belief that true transparency is only trustworthy if the entire process and the required software is open and reusable under a fair copyleft license (AGPL).
|
|
16
|
+
4. Chargy is __*open for your contributions*__. We currently support adapters for the protocols of different charging station vendors like chargeIT mobility, ABL (OCMF), chargepoint. The certification at the Physikalisch-Technische Bundesanstalt (PTB) is provided by chargeIT mobility. If you want to add your protocol or a protocol adapter feel free to read the contributor license agreement and to send us a pull request.
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
## Supported Charge Transparency Data Formats
|
|
20
|
+
|
|
21
|
+
ChargyCore.TS supports a broad range of charge transparency data formats used by charging stations, energy meters, backend systems, and invoice-related exports.
|
|
22
|
+
|
|
23
|
+
Currently supported formats include:
|
|
24
|
+
- **Alfen** charge transparency data
|
|
25
|
+
- **Bauer** energy meter data (2 format variants)
|
|
26
|
+
- **ChargePoint** transparency data (2 format variants)
|
|
27
|
+
- **EDL40** and **ISA-EDL40 SML** data
|
|
28
|
+
- **EMH** energy meter data
|
|
29
|
+
- **Mennekes** XML
|
|
30
|
+
- **OCMF**, versions v1.1 to v1.4
|
|
31
|
+
- Bonner Eichrechtstage **Tariff Text** Extensions
|
|
32
|
+
- EdDSA support: Ed25519 and Ed448
|
|
33
|
+
- Post-Quantum Cryptography support: ML-DSA-44, ML-DSA-65, ML-DSA-87
|
|
34
|
+
- **Porsche Charging Data Format (PCDF)**
|
|
35
|
+
|
|
36
|
+
Detailed per-format documentation (data structures, signed payloads and signature verification) is available in [`documentation/`](documentation/README.md).
|
|
37
|
+
|
|
38
|
+
The long-standing, consumer-oriented CTR data model is described in the draft
|
|
39
|
+
[Charge Transparency Record format specification](documentation/CTR_Format.md).
|
|
40
|
+
CTR connects signed technical evidence with charging sessions, tariffs, costs,
|
|
41
|
+
and PDF/A-3 invoices so EV drivers can assess a bill without having to understand
|
|
42
|
+
each meter vendor's cryptographic format.
|
|
43
|
+
Additional draft CTR extension specifications are available for
|
|
44
|
+
[legally relevant log messages](documentation/CTR_Legally_Relevant_Log_Messages.md)
|
|
45
|
+
and [time synchronization sources](documentation/CTR_Time_Synchronization_Sources.md),
|
|
46
|
+
including event pagination, hash chaining, NTS source information, clock
|
|
47
|
+
quality, and significant time-source changes.
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
## Supported Data Representations
|
|
51
|
+
|
|
52
|
+
ChargyCore.TS accepts multiple data representations in order to simplify the validation of individual charge transparency files as well as larger collections of transparency data, for example data sets attached to monthly invoices or exported from backend systems.
|
|
53
|
+
|
|
54
|
+
Supported representations include:
|
|
55
|
+
- **Plain Files** containing a single charge transparency data set.
|
|
56
|
+
- **chargeIT Container Format**, a JSON-based container format for a single charging session (2 format variants).
|
|
57
|
+
- **Chargy Container Format**, a JSON-based container format for multiple charging sessions.
|
|
58
|
+
- **SAFE XML Container Format**, an XML-based container format for a single charging session, optionally enriched with additional Chargy metadata about the charging session.
|
|
59
|
+
- **PTB Container Format**, a JSON-based container format for a single charging session.
|
|
60
|
+
- **Archive formats** such as ***tar, ZIP, tar.gz***, and similar formats that combine or compress multiple charge transparency files.
|
|
61
|
+
- **QR-Code images**, such as ***PNG, JPG, JPEG or SVG files***, where the QR-Code represents a charge transparency data set.
|
|
62
|
+
- **PDF/A-3** files transporting a charge transparency file as an embedded additional data stream.
|
|
63
|
+
|
|
64
|
+
This allows applications to pass transparency data to ChargyCore.TS in the form in which it was originally received, without having to manually unpack, decode, or normalize every file beforehand.
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
## Applications based on this library
|
|
68
|
+
|
|
69
|
+
- [Chargy Web App](https://github.com/OpenChargingCloud/ChargyWebApp/) (node.js), live demo at [https://chargy.charging.cloud](https://chargy.charging.cloud)
|
|
70
|
+
- [Chargy Desktop App](https://github.com/OpenChargingCloud/ChargyDesktopApp/) (Electron)
|
|
71
|
+
- [Chargy Mobile Apps](https://github.com/OpenChargingCloud/ChargyMobileApp/) (Android/iOS)
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
## Usage
|
|
75
|
+
|
|
76
|
+
This package is published on npm as [`@open-charging-cloud/chargy-core`](https://www.npmjs.com/package/@open-charging-cloud/chargy-core)
|
|
77
|
+
|
|
78
|
+
First install it e.g. via npm
|
|
79
|
+
```bash
|
|
80
|
+
npm install @open-charging-cloud/chargy-core@latest
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
or, for reproducible builds, pin a specific version:
|
|
84
|
+
```bash
|
|
85
|
+
npm install @open-charging-cloud/chargy-core@<version>
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Basic Import (TypeScript / ESM) TypeScript
|
|
89
|
+
```ts
|
|
90
|
+
import { Chargy } from "@open-charging-cloud/chargy-core";
|
|
91
|
+
```
|
|
92
|
+
The package ships as a modern ESM package and includes generated TypeScript declarations, so it can be used directly in TypeScript projects without additional type packages.
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
### Signature providers
|
|
96
|
+
|
|
97
|
+
ChargyCore uses audited Noble implementations for modern signature algorithms. The common `SignatureSuite` API supports ECDSA over secp256k1, P-256, P-384 and P-521; Ed25519, Ed25519ctx, Ed25519ph, Ed448 and Ed448ph; and the FIPS 204 ML-DSA-44, ML-DSA-65 and ML-DSA-87 parameter sets. The older `elliptic` implementation is restricted to verification of legacy P-192 charging data.
|
|
98
|
+
|
|
99
|
+
Keys and signatures use `Uint8Array`, and every serialized JSON signature records its algorithm and encoding. For example:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import {
|
|
103
|
+
generateSignatureKeyPair,
|
|
104
|
+
signMessage,
|
|
105
|
+
verifyJSONMessageSignatures
|
|
106
|
+
} from "@open-charging-cloud/chargy-core";
|
|
107
|
+
|
|
108
|
+
const keyPair = generateSignatureKeyPair("ML-DSA-65");
|
|
109
|
+
const record = { sessionId: "DE*TEST*E1", energy: 12.5 };
|
|
110
|
+
|
|
111
|
+
await signMessage(record, keyPair);
|
|
112
|
+
const valid = await verifyJSONMessageSignatures(record);
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
Use the distinct `Ed25519ph`, `Ed448ph`, or ML-DSA algorithm identifier when a protocol requires that variant. The generic `prehashed` option is intentionally rejected for these schemes so that pure and pre-hash signatures cannot be confused accidentally.
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
### Runtime Architecture
|
|
119
|
+
|
|
120
|
+
ChargyCore is consumed in different JavaScript runtimes. The browser-based Chargy WebApp and Electron renderer processes have Web APIs such as `DOMParser`, `Blob`, `TextEncoder`, `ImageData`, `DOMMatrix`, `Path2D`, and browser worker loading semantics. Node.js-based tests, command line tools, server-side verification, and build-time checks do not provide the same environment.
|
|
121
|
+
|
|
122
|
+
For that reason the package ships two JavaScript builds behind one public import:
|
|
123
|
+
|
|
124
|
+
```text
|
|
125
|
+
dist/browser/index.js
|
|
126
|
+
dist/node/index.js
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The runtime-specific file is selected through conditional package exports in `package.json`. Browser bundlers should resolve the `browser` condition and receive `dist/browser/index.js`. Node.js resolves the `node` condition and receives `dist/node/index.js`.
|
|
130
|
+
|
|
131
|
+
This split is especially important for PDF.js. Browser contexts should use the normal `pdfjs-dist` build, because the browser already provides the canvas and DOM APIs PDF.js expects. Node.js should use `pdfjs-dist/legacy/build/pdf.mjs`, because the legacy build contains Node-oriented setup for the missing canvas-related globals and avoids the modern browser-only assumptions.
|
|
132
|
+
|
|
133
|
+
Keeping these paths separate has several advantages:
|
|
134
|
+
|
|
135
|
+
- Browser bundles do not include the Node/legacy PDF.js path as an unused lazy chunk.
|
|
136
|
+
- Node tests and CLI-style usage do not depend on browser-only PDF.js behavior.
|
|
137
|
+
- Chargy apps do not need local Webpack aliases or test polyfills for ChargyCore internals.
|
|
138
|
+
- Bundle checks can verify that the browser build only references browser PDF.js imports and the Node build only references legacy PDF.js imports.
|
|
139
|
+
|
|
140
|
+
When adding runtime-sensitive dependencies, avoid branching on runtime inside shared source code if that would make bundlers see both implementations. Prefer a small adapter under `src/` and let the build or conditional exports select the runtime-specific implementation.
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
### PDF.js Version Pin
|
|
144
|
+
|
|
145
|
+
> **`pdfjs-dist` is pinned to an exact version, currently `6.2.108`. Always run the PDF/A-3 test when raising it.**
|
|
146
|
+
|
|
147
|
+
It is the only dependency in `package.json` without a `^`, because PDF.js has shipped a silently breaking attachment API change within a minor release. Going from `6.0.227` to `6.2.108` changed `getDocument().getAttachments()` in two ways:
|
|
148
|
+
|
|
149
|
+
1. It resolves to a **`Map`** instead of a plain object. Reading the result with `Object.values()` yields an empty array for a `Map`, so every attachment is dropped.
|
|
150
|
+
2. Entries no longer carry the file bytes eagerly. `content` is only set when it happens to be loaded already, otherwise the payload has to be fetched via the new `getAttachmentContent(id)`.
|
|
151
|
+
|
|
152
|
+
Both are handled in `src/chargy.ts`, which iterates the `Map` and falls back to `getAttachmentContent()` whenever an entry has no inline `content`.
|
|
153
|
+
|
|
154
|
+
What makes this class of change dangerous is that it fails silently: nothing throws, so the `try`/`catch` around the call never fires. The embedded record simply disappears and verification then reports `InvalidSessionFormat` with *"No charge transparency records found!"*. `npm run typecheck` and `npm run lint` both stay green; only `tests/SAFE.tests.ts` ("SAFE Testdata 02 with XML namespace via PDF/A-3") detects it, by extracting a real embedded XML file from `tests/fixtures/SAFE/SAFE-Testdata-02_withXMLNamespace.pdf`.
|
|
155
|
+
|
|
156
|
+
So before changing the pin, always run:
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
npm run test:node -- tests/SAFE.tests.ts
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Staying on an old version is not a safe default either — `6.0.227` was affected by [GHSA-hq66-cqwq-w95j](https://github.com/advisories/GHSA-hq66-cqwq-w95j) (high severity, arbitrary JavaScript execution when opening a malicious PDF), which is fixed in `6.2.108`.
|
|
163
|
+
|
|
164
|
+
|
|
165
|
+
## Development
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npm install
|
|
169
|
+
npm run typecheck
|
|
170
|
+
npm run lint
|
|
171
|
+
npm run build
|
|
172
|
+
npm run test:node
|
|
173
|
+
npm run test:bundle
|
|
174
|
+
npm run test:browser
|
|
175
|
+
npm test
|
|
176
|
+
npm run verify
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
The build emits the package into `dist/`.
|
|
180
|
+
|
|
181
|
+
|
|
182
|
+
### Expected Test Flow
|
|
183
|
+
|
|
184
|
+
For code changes, use the full verification flow before publishing or handing a package to the Chargy apps:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npm run verify
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
`verify` runs the following checks:
|
|
191
|
+
|
|
192
|
+
- `npm run typecheck`: validates the TypeScript sources and test/config TypeScript files.
|
|
193
|
+
- `npm run lint`: runs the strict type-aware ESLint setup and fails on every warning or error.
|
|
194
|
+
- `npm test`: runs all runtime checks:
|
|
195
|
+
- `npm run test:node`: runs the Chargy fixture tests in Vitest's Node environment and uses the Node PDF.js adapter.
|
|
196
|
+
- `npm run build`: creates both package builds.
|
|
197
|
+
- `npm run test:bundle`: checks the generated bundles so the browser build only references the browser PDF.js path and the Node build only references the legacy PDF.js path.
|
|
198
|
+
- `npm run test:browser`: imports `dist/browser/index.js` in headless Chromium via Vitest Browser Mode and verifies the public browser entry can be loaded and instantiated.
|
|
199
|
+
- `npm run build`: recreates the final publishable `dist/` output.
|
|
200
|
+
|
|
201
|
+
For dependency, build, export, PDF.js, or browser-facing changes, run the individual steps while iterating and finish with `npm run verify`. The browser test requires Playwright's Chromium browser; if it is missing locally, run:
|
|
202
|
+
|
|
203
|
+
```bash
|
|
204
|
+
npx playwright install chromium
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Publishing
|
|
208
|
+
|
|
209
|
+
```bash
|
|
210
|
+
npm version 0.12.1 --no-git-tag-version
|
|
211
|
+
npm run verify
|
|
212
|
+
npm pack --dry-run
|
|
213
|
+
npm pack
|
|
214
|
+
npm login
|
|
215
|
+
npm whoami
|
|
216
|
+
npm publish
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
## Funding
|
|
221
|
+
|
|
222
|
+
This Open Source project is partially funded by the [NGI Zero Commons Fund](https://nlnet.nl/commonsfund/) as part of our [EVQI project](https://nlnet.nl/project/EVQI/).
|
|
223
|
+
|
|
224
|
+
We also appreciate any additional funding and long-term support for the Chargy family, for example via [GitHub Sponsors](https://github.com/sponsors/GraphDefined), as it helps us keep the project sustainable, independent and useful for the entire e-mobility community.
|
|
225
|
+
|
|
226
|
+
<center>
|
|
227
|
+
<img src="images/NGI0_tag.svg" height="30">
|
|
228
|
+
</center>
|