@open-charging-cloud/chargy-core 0.6.1 → 0.6.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +2 -2
  2. package/dist/ACrypt.d.ts +2 -2
  3. package/dist/ACrypt.d.ts.map +1 -1
  4. package/dist/Alfen.d.ts +6 -6
  5. package/dist/Alfen.d.ts.map +1 -1
  6. package/dist/BSMCrypt01.d.ts +8 -9
  7. package/dist/BSMCrypt01.d.ts.map +1 -1
  8. package/dist/EMHCrypt01.d.ts +8 -8
  9. package/dist/EMHCrypt01.d.ts.map +1 -1
  10. package/dist/GDFCrypt01.d.ts +8 -8
  11. package/dist/GDFCrypt01.d.ts.map +1 -1
  12. package/dist/Mennekes.d.ts +22 -22
  13. package/dist/Mennekes.d.ts.map +1 -1
  14. package/dist/OCMF.d.ts +25 -27
  15. package/dist/OCMF.d.ts.map +1 -1
  16. package/dist/OCPI.d.ts +2 -4
  17. package/dist/OCPI.d.ts.map +1 -1
  18. package/dist/PCDF.d.ts +1 -1
  19. package/dist/PCDF.d.ts.map +1 -1
  20. package/dist/QIDigital_DCC.d.ts +1 -1
  21. package/dist/QIDigital_DCC.d.ts.map +1 -1
  22. package/dist/QIDigital_DCoA.d.ts +1 -1
  23. package/dist/QIDigital_DCoA.d.ts.map +1 -1
  24. package/dist/QIDigital_DCoC.d.ts +1 -1
  25. package/dist/QIDigital_DCoC.d.ts.map +1 -1
  26. package/dist/SAFE_XML.d.ts +16 -16
  27. package/dist/SAFE_XML.d.ts.map +1 -1
  28. package/dist/XMLContainer.d.ts +2 -2
  29. package/dist/XMLContainer.d.ts.map +1 -1
  30. package/dist/browser/index.js +943 -895
  31. package/dist/browser/index.js.map +1 -1
  32. package/dist/chargeIT.d.ts +1 -3
  33. package/dist/chargeIT.d.ts.map +1 -1
  34. package/dist/chargePoint.d.ts +3 -3
  35. package/dist/chargePoint.d.ts.map +1 -1
  36. package/dist/chargy.d.ts +12 -12
  37. package/dist/chargy.d.ts.map +1 -1
  38. package/dist/chargyLib.d.ts +4 -0
  39. package/dist/chargyLib.d.ts.map +1 -1
  40. package/dist/interfaces/IChargeTransparencyRecord.d.ts +76 -76
  41. package/dist/interfaces/IChargeTransparencyRecord.d.ts.map +1 -1
  42. package/dist/interfaces/chargyInterfaces.d.ts +97 -107
  43. package/dist/interfaces/chargyInterfaces.d.ts.map +1 -1
  44. package/dist/node/index.js +943 -895
  45. package/dist/node/index.js.map +1 -1
  46. package/dist/pdfjs/browser.d.ts +2 -1
  47. package/dist/pdfjs/browser.d.ts.map +1 -1
  48. package/dist/qrCodeReader.d.ts.map +1 -1
  49. package/dist/secp224k1.d.ts +10 -11
  50. package/dist/secp224k1.d.ts.map +1 -1
  51. package/dist/verificationResults.d.ts +1 -1
  52. package/dist/verificationResults.d.ts.map +1 -1
  53. package/package.json +3 -3
@@ -8005,9 +8005,7 @@ var secp224k1 = class {
8005
8005
  N = BigInt("0x010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7");
8006
8006
  // Number of points in the field
8007
8007
  Acurve = BigInt(0);
8008
- // These two are defined on the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve
8009
- Bcurve = BigInt(5);
8010
- // These two are defined on the elliptic curve. y^2 = x^3 + Acurve * x + Bcurve
8008
+ // Defined on the elliptic curve. y^2 = x^3 + Acurve * x + 5
8011
8009
  Gx = BigInt("0xA1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C");
8012
8010
  Gy = BigInt("0x7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5");
8013
8011
  GPoint = [this.Gx, this.Gy];
@@ -8104,6 +8102,7 @@ var secp224k1 = class {
8104
8102
  address: this.modulo(publicKey[1], this.Two) == this.One ? "03" + Px : "02" + Px
8105
8103
  };
8106
8104
  }
8105
+ return void 0;
8107
8106
  }
8108
8107
  };
8109
8108
 
@@ -8232,13 +8231,13 @@ function CreateError(message, level = "high" /* high */) {
8232
8231
  };
8233
8232
  }
8234
8233
  function isISessionCryptoResult1(obj) {
8235
- return typeof obj === "object" && obj !== null && obj.status !== void 0;
8234
+ return isObject(obj) && obj["status"] !== void 0;
8236
8235
  }
8237
8236
  function isISessionCryptoResult2(obj) {
8238
- return typeof obj === "object" && obj !== null && obj.status !== void 0 && obj.status !== "InvalidSessionFormat" /* InvalidSessionFormat */;
8237
+ return isObject(obj) && obj["status"] !== void 0 && obj["status"] !== "InvalidSessionFormat" /* InvalidSessionFormat */;
8239
8238
  }
8240
8239
  function isICryptoResult(obj) {
8241
- return typeof obj === "object" && obj !== null && obj.status !== void 0;
8240
+ return isObject(obj) && obj["status"] !== void 0;
8242
8241
  }
8243
8242
  var InformationRelevance = /* @__PURE__ */ ((InformationRelevance2) => {
8244
8243
  InformationRelevance2["Unknown"] = "Unknown";
@@ -8326,6 +8325,26 @@ function toArrayBuffer(data) {
8326
8325
  function toUint8Array(data) {
8327
8326
  return data instanceof Uint8Array ? data : new Uint8Array(data);
8328
8327
  }
8328
+ function getArrayElement(values, index, message = "Missing array element") {
8329
+ const value = values[index];
8330
+ if (value === void 0)
8331
+ throw new Error(message + " at index " + index.toString());
8332
+ return value;
8333
+ }
8334
+ function getFirstArrayElement(values, message = "Missing first array element") {
8335
+ return getArrayElement(values, 0, message);
8336
+ }
8337
+ function getLastArrayElement(values, message = "Missing last array element") {
8338
+ return getArrayElement(values, values.length - 1, message);
8339
+ }
8340
+ function getArrayLikeElement(values, index, message = "Missing array-like element") {
8341
+ if (index < 0 || index >= values.length)
8342
+ throw new Error(message + " at index " + index.toString());
8343
+ const value = values[index];
8344
+ if (value === void 0)
8345
+ throw new Error(message + " at index " + index.toString());
8346
+ return value;
8347
+ }
8329
8348
  function normalizeXMLText(xmlText) {
8330
8349
  return (xmlText ?? "").replace(/^\uFEFF/, "").replace(/\r\n?/g, "\n").replace(/>\s+</g, "><").trim();
8331
8350
  }
@@ -8337,15 +8356,16 @@ function getDirectChildByLocalName(parent, localName) {
8337
8356
  }
8338
8357
  function getTrimmedTextContent(element) {
8339
8358
  const text = element?.textContent.trim();
8340
- return text && text.length > 0 ? text : void 0;
8359
+ return text != null && text.length > 0 ? text : void 0;
8341
8360
  }
8342
8361
  function parseDescription(parent) {
8343
8362
  const descriptions = getDirectChildrenByLocalName(parent, "description");
8344
8363
  const textMap = {};
8345
8364
  for (const description of descriptions) {
8346
- const language = description.getAttribute("language")?.trim() || "und";
8365
+ const languageAttribute = description.getAttribute("language")?.trim();
8366
+ const language = languageAttribute != null && languageAttribute.length > 0 ? languageAttribute : "und";
8347
8367
  const text = description.textContent.trim();
8348
- if (text)
8368
+ if (text.length > 0)
8349
8369
  textMap[language] = text;
8350
8370
  }
8351
8371
  return Object.keys(textMap).length > 0 ? textMap : void 0;
@@ -8381,12 +8401,14 @@ function ParseJSON_LD(Text, _Context = "") {
8381
8401
  function firstKey(obj) {
8382
8402
  for (const a in obj)
8383
8403
  return a;
8404
+ return void 0;
8384
8405
  }
8385
8406
  function firstValue(obj) {
8386
8407
  if (obj == void 0)
8387
8408
  return void 0;
8388
8409
  for (const a in obj)
8389
8410
  return obj[a];
8411
+ return void 0;
8390
8412
  }
8391
8413
  var uiLocale = typeof window !== "undefined" ? window.navigator.language : "de";
8392
8414
  function setUILocale(locale) {
@@ -8419,14 +8441,17 @@ function parseOBIS(OBIS) {
8419
8441
  return `${String(media)}-${String(channel)}:${String(indicator)}.${String(mode)}.${String(quantities)}*${String(storage)}`;
8420
8442
  }
8421
8443
  var OBIS_RegExpr = new RegExp("((\\d+)\\-)?((\\d+):)?((\\d+)\\.)(\\d+)(\\.(\\d+))?(\\*(\\d+))?");
8444
+ function optionalOBISMatchValue(value) {
8445
+ return value ?? "0";
8446
+ }
8422
8447
  function OBIS2Hex(OBIS) {
8423
8448
  const OBISElements = OBIS.match(OBIS_RegExpr);
8424
- return OBISElements == null ? "000000000000" : parseInt(OBISElements[2]).toString(16).padStart(2, "0") + // optional A
8425
- parseInt(OBISElements[4]).toString(16).padStart(2, "0") + // optional B
8426
- parseInt(OBISElements[6]).toString(16).padStart(2, "0") + // mandatory C
8427
- parseInt(OBISElements[7]).toString(16).padStart(2, "0") + // mandatory D
8428
- parseInt(OBISElements[9]).toString(16).padStart(2, "0") + // optional E
8429
- parseInt(OBISElements[11]).toString(16).padStart(2, "0");
8449
+ return OBISElements == null ? "000000000000" : parseInt(optionalOBISMatchValue(OBISElements[2])).toString(16).padStart(2, "0") + // optional A
8450
+ parseInt(optionalOBISMatchValue(OBISElements[4])).toString(16).padStart(2, "0") + // optional B
8451
+ parseInt(optionalOBISMatchValue(OBISElements[6])).toString(16).padStart(2, "0") + // mandatory C
8452
+ parseInt(optionalOBISMatchValue(OBISElements[7])).toString(16).padStart(2, "0") + // mandatory D
8453
+ parseInt(optionalOBISMatchValue(OBISElements[9])).toString(16).padStart(2, "0") + // optional E
8454
+ parseInt(optionalOBISMatchValue(OBISElements[11])).toString(16).padStart(2, "0");
8430
8455
  }
8431
8456
  function OBIS2MeasurementName(OBISString) {
8432
8457
  switch (OBISString) {
@@ -8469,15 +8494,15 @@ function measurementName2human(In) {
8469
8494
  }
8470
8495
  }
8471
8496
  function IsNullOrEmpty(value) {
8472
- return !value;
8497
+ return value == null || value.length === 0;
8473
8498
  }
8474
8499
  function WhenNullOrEmpty(value, replacement) {
8475
- if (!value)
8500
+ if (value == null || value.length === 0)
8476
8501
  return replacement;
8477
8502
  return value;
8478
8503
  }
8479
8504
  function hex2bin(hex, Reverse) {
8480
- if (Reverse) {
8505
+ if (Reverse === true) {
8481
8506
  const reversed = [];
8482
8507
  for (let i = 0; i < hex.length; i += 2)
8483
8508
  reversed.push(hex.substring(i, i + 2));
@@ -8591,7 +8616,7 @@ function SetHex(dv, hex, offset, reverse) {
8591
8616
  const bytes = parseHexString(hex);
8592
8617
  const buffer = new ArrayBuffer(bytes.length);
8593
8618
  const tv = new DataView(buffer);
8594
- if (reverse)
8619
+ if (reverse === true)
8595
8620
  bytes.reverse();
8596
8621
  for (let i = 0; i < bytes.length; i++) {
8597
8622
  dv.setUint8(offset + i, bytes[i] ?? 0);
@@ -8640,7 +8665,7 @@ function SetUInt32(dv, value, offset, reverse) {
8640
8665
  const bytes = getInt32Bytes(value);
8641
8666
  const buffer = new ArrayBuffer(bytes.length);
8642
8667
  const tv = new DataView(buffer);
8643
- if (reverse)
8668
+ if (reverse === true)
8644
8669
  bytes.reverse();
8645
8670
  for (let i = 0; i < bytes.length; i++) {
8646
8671
  dv.setUint8(offset + i, bytes[i] ?? 0);
@@ -8652,7 +8677,7 @@ function SetUInt64(dv, value, offset, reverse) {
8652
8677
  const bytes = getInt64Bytes(value);
8653
8678
  const buffer = new ArrayBuffer(bytes.length);
8654
8679
  const tv = new DataView(buffer);
8655
- if (reverse)
8680
+ if (reverse === true)
8656
8681
  bytes.reverse();
8657
8682
  for (let i = 0; i < bytes.length; i++) {
8658
8683
  dv.setUint8(offset + i, bytes[i] ?? 0);
@@ -8684,7 +8709,7 @@ function SetUInt32_withCode(dv, value, scale, obis, offset, reverse) {
8684
8709
  const obisBytes = getInt8Bytes(obis);
8685
8710
  const buffer = new ArrayBuffer(valueBytes.length + 2);
8686
8711
  const tv = new DataView(buffer);
8687
- if (reverse)
8712
+ if (reverse === true)
8688
8713
  valueBytes.reverse();
8689
8714
  for (let i = 0; i < valueBytes.length; i++) {
8690
8715
  dv.setUint8(offset + i, valueBytes[i] ?? 0);
@@ -8747,8 +8772,7 @@ function CreateDiv2(ParentDiv, ChildClassName, ChildAInnerHTML, ChildBInnerHTML)
8747
8772
  return childDiv;
8748
8773
  }
8749
8774
  function pad(text, paddingValue) {
8750
- if (text == void 0)
8751
- text = "";
8775
+ text ??= "";
8752
8776
  return (text + Array(2 * paddingValue).join("0")).substring(0, 2 * paddingValue);
8753
8777
  }
8754
8778
  async function sha256(message) {
@@ -8894,7 +8918,7 @@ function jsonPrettyPrinter(value, KeyLookup) {
8894
8918
  value,
8895
8919
  0,
8896
8920
  "",
8897
- KeyLookup ?? ((path, key) => key)
8921
+ KeyLookup ?? ((_path, key) => key)
8898
8922
  );
8899
8923
  }
8900
8924
  function _jsonPrettyPrinter(value, indentLevel, path, keyLookup) {
@@ -8973,13 +8997,15 @@ var ACrypt = class {
8973
8997
  }
8974
8998
  AddToVisualBuffer(valueHEX, bufferDiv, lineDiv) {
8975
8999
  const newText = CreateDiv(bufferDiv, "entry", valueHEX);
9000
+ const lineId = getArrayLikeElement(lineDiv.children, 0, "Missing visual buffer line id");
9001
+ const lineHex = getArrayLikeElement(lineDiv.children, 1, "Missing visual buffer line hex");
8976
9002
  newText.onmouseenter = function() {
8977
- lineDiv.children[0]?.classList.add("overEntry");
8978
- lineDiv.children[1]?.classList.add("overEntry");
9003
+ lineId.classList.add("overEntry");
9004
+ lineHex.classList.add("overEntry");
8979
9005
  };
8980
9006
  newText.onmouseleave = function() {
8981
- lineDiv.children[0]?.classList.remove("overEntry");
8982
- lineDiv.children[1]?.classList.remove("overEntry");
9007
+ lineId.classList.remove("overEntry");
9008
+ lineHex.classList.remove("overEntry");
8983
9009
  };
8984
9010
  lineDiv.onmouseenter = function() {
8985
9011
  newText.classList.add("overEntry");
@@ -8995,7 +9021,7 @@ var Alfen = class {
8995
9021
  this.chargy = chargy;
8996
9022
  }
8997
9023
  bufferToHex(buffer, Reverse) {
8998
- return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
9024
+ return (Reverse === true ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
8999
9025
  }
9000
9026
  bufferToNumber(buffer) {
9001
9027
  return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
@@ -9030,28 +9056,29 @@ var Alfen = class {
9030
9056
  signedValues = Content;
9031
9057
  let previousTimestamp = "";
9032
9058
  for (let i = 0; i < signedValues.length; i++) {
9033
- const elements = signedValues[i]?.split(";");
9034
- if (elements?.length != 6 && elements?.length != 7)
9059
+ const elements = getArrayElement(signedValues, i, "Missing Alfen signed value").split(";");
9060
+ if (elements.length != 6 && elements.length != 7)
9035
9061
  return {
9036
9062
  status: "InvalidSessionFormat" /* InvalidSessionFormat */,
9037
9063
  message: this.chargy.GetMultilanguageText("Invalid number of signed meter values!"),
9038
9064
  certainty: 0
9039
9065
  };
9040
- const FormatId = elements[0];
9041
- const Type = elements[1];
9042
- const BlobVersion = elements[2];
9043
- const PublicKey = this.chargy.base32Decode(elements[3] ?? "", "RFC4648");
9044
- const DataSet = this.chargy.base32Decode(elements[4] ?? "", "RFC4648");
9045
- const Signature = this.chargy.base32Decode(elements[5] ?? "", "RFC4648");
9066
+ const FormatId = getArrayElement(elements, 0, "Missing Alfen format id");
9067
+ const Type = getArrayElement(elements, 1, "Missing Alfen type");
9068
+ const BlobVersion = getArrayElement(elements, 2, "Missing Alfen blob version");
9069
+ const publicKeyValue = getArrayElement(elements, 3, "Missing Alfen public key");
9070
+ const PublicKey = this.chargy.base32Decode(publicKeyValue, "RFC4648");
9071
+ const DataSet = this.chargy.base32Decode(getArrayElement(elements, 4, "Missing Alfen data set"), "RFC4648");
9072
+ const Signature = this.chargy.base32Decode(getArrayElement(elements, 5, "Missing Alfen signature"), "RFC4648");
9046
9073
  if (common.PublicKey === "")
9047
- common.PublicKey = elements[3] ?? "";
9048
- else if (elements[3] !== common.PublicKey)
9074
+ common.PublicKey = publicKeyValue;
9075
+ else if (publicKeyValue !== common.PublicKey)
9049
9076
  return {
9050
9077
  status: "InvalidSessionFormat" /* InvalidSessionFormat */,
9051
9078
  message: this.chargy.GetMultilanguageText("Inconsistent public keys!"),
9052
9079
  certainty: 0
9053
9080
  };
9054
- if (FormatId !== "AP" || Type?.length !== 1 || BlobVersion?.length !== 1 || BlobVersion !== "3" || PublicKey.byteLength !== 25 || DataSet.byteLength !== 82 || Signature.byteLength !== 48) {
9081
+ if (FormatId !== "AP" || Type.length !== 1 || BlobVersion.length !== 1 || BlobVersion !== "3" || PublicKey.byteLength !== 25 || DataSet.byteLength !== 82 || Signature.byteLength !== 48) {
9055
9082
  return {
9056
9083
  status: "InvalidSessionFormat" /* InvalidSessionFormat */,
9057
9084
  message: this.chargy.GetMultilanguageText("Invalid charging session format!"),
@@ -9168,14 +9195,8 @@ var Alfen = class {
9168
9195
  const evseId = asString(containerInfos["EVSEId"]) ?? "DE*GEF*EVSE*CHARGY*1";
9169
9196
  const chargingStationId = asString(containerInfos["ChargingStationId"]) ?? "DE*GEF*STATION*CHARGY*1";
9170
9197
  const chargingSessionId = asString(chargingSession?.["@id"]);
9171
- const firstDataSet = common.dataSets[0];
9172
- const lastDataSet = common.dataSets[common.dataSets.length - 1];
9173
- if (firstDataSet === void 0 || lastDataSet === void 0)
9174
- return {
9175
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
9176
- message: this.chargy.GetMultilanguageText("Invalid number of signed meter values!"),
9177
- certainty: 0
9178
- };
9198
+ const firstDataSet = getFirstArrayElement(common.dataSets, "Missing first Alfen data set");
9199
+ const lastDataSet = getLastArrayElement(common.dataSets, "Missing last Alfen data set");
9179
9200
  const _CTR = {
9180
9201
  "@id": chargingSessionId ?? common.InternalSessionId.toString(),
9181
9202
  "@context": "https://open.charging.cloud/contexts/CTR+json",
@@ -9456,62 +9477,62 @@ var AlfenCrypt01 = class extends ACrypt {
9456
9477
  }
9457
9478
  return {};
9458
9479
  }
9459
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
9480
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
9460
9481
  const result = measurementValue.result;
9461
9482
  {
9462
9483
  introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "AlfenCrypt01").replace("{cryptoAlgorithm}", this.description);
9463
9484
  }
9464
9485
  {
9465
- if (PlainTextDiv.parentElement && PlainTextDiv.parentElement.children[0]) {
9466
- PlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (320 Bytes, hex)";
9486
+ if (PlainTextDiv.parentElement) {
9487
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (320 Bytes, hex)";
9467
9488
  }
9468
9489
  PlainTextDiv.style.fontFamily = "";
9469
9490
  PlainTextDiv.style.whiteSpace = "";
9470
9491
  PlainTextDiv.style.maxHeight = "";
9471
9492
  PlainTextDiv.style.overflowY = "";
9472
- this.CreateLocalizedLine("Adapter Id", measurementValue.measurement.adapterId, result.adapterId || "", infoDiv, PlainTextDiv);
9473
- this.CreateLocalizedLine("Adapter Firmware Version", measurementValue.measurement.adapterFWVersion, result.adapterFWVersion || "", infoDiv, PlainTextDiv);
9474
- this.CreateLocalizedLine("Adapter Firmware Checksum", measurementValue.measurement.adapterFWChecksum, result.adapterFWChecksum || "", infoDiv, PlainTextDiv);
9475
- this.CreateLocalizedLine("Meter number", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, PlainTextDiv);
9493
+ this.CreateLocalizedLine("Adapter Id", measurementValue.measurement.adapterId, result.adapterId ?? "", infoDiv, PlainTextDiv);
9494
+ this.CreateLocalizedLine("Adapter Firmware Version", measurementValue.measurement.adapterFWVersion, result.adapterFWVersion ?? "", infoDiv, PlainTextDiv);
9495
+ this.CreateLocalizedLine("Adapter Firmware Checksum", measurementValue.measurement.adapterFWChecksum, result.adapterFWChecksum ?? "", infoDiv, PlainTextDiv);
9496
+ this.CreateLocalizedLine("Meter number", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
9476
9497
  this.CreateLocalizedLine(
9477
9498
  "Meter status",
9478
9499
  hex2bin(measurementValue.statusMeter, true) + " (" + measurementValue.statusMeter + ' hex)<br /><span class="statusInfos">' + this.DecodeMeterStatus(measurementValue.statusMeter).join("<br />") + "</span>",
9479
- result.statusMeter || "",
9500
+ result.statusMeter ?? "",
9480
9501
  infoDiv,
9481
9502
  PlainTextDiv
9482
9503
  );
9483
9504
  this.CreateLocalizedLine(
9484
9505
  "Adapter status",
9485
9506
  hex2bin(measurementValue.statusAdapter, true) + " (" + measurementValue.statusAdapter + ' hex)<br /><span class="statusInfos">' + this.DecodeAdapterStatus(measurementValue.statusAdapter).join("<br />") + "</span>",
9486
- result.statusAdapter || "",
9507
+ result.statusAdapter ?? "",
9487
9508
  infoDiv,
9488
9509
  PlainTextDiv
9489
9510
  );
9490
- this.CreateLocalizedLine("Seconds index", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, PlainTextDiv);
9491
- this.CreateLocalizedLine("Timestamp", UTC2human(measurementValue.timestamp), result.timestamp || "", infoDiv, PlainTextDiv);
9492
- this.CreateLocalizedLine("OBIS code", measurementValue.measurement.obis, result.obisId || "", infoDiv, PlainTextDiv);
9493
- this.CreateLocalizedLine("Unit (encoded)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded || "", infoDiv, PlainTextDiv);
9494
- this.CreateLocalizedLine("Scaling", measurementValue.measurement.scale, result.scalar || "", infoDiv, PlainTextDiv);
9495
- this.CreateLocalizedLine("Measurement Value", measurementValue.value.toString() + " Wh", result.value || "", infoDiv, PlainTextDiv);
9496
- this.CreateLocalizedLine("Authorization", (measurementValue.measurement.chargingSession?.authorizationStart["@id"] ?? "") + " hex", pad(result.uid, 20) || "", infoDiv, PlainTextDiv);
9497
- this.CreateLocalizedLine("SessionId", measurementValue.measurement.chargingSession?.["@id"] ?? "", result.sessionId || "", infoDiv, PlainTextDiv);
9498
- this.CreateLocalizedLine("Pagination counter", measurementValue.paginationId, result.paging || "", infoDiv, PlainTextDiv);
9511
+ this.CreateLocalizedLine("Seconds index", measurementValue.secondsIndex, result.secondsIndex ?? "", infoDiv, PlainTextDiv);
9512
+ this.CreateLocalizedLine("Timestamp", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
9513
+ this.CreateLocalizedLine("OBIS code", measurementValue.measurement.obis, result.obisId ?? "", infoDiv, PlainTextDiv);
9514
+ this.CreateLocalizedLine("Unit (encoded)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
9515
+ this.CreateLocalizedLine("Scaling", measurementValue.measurement.scale, result.scalar ?? "", infoDiv, PlainTextDiv);
9516
+ this.CreateLocalizedLine("Measurement Value", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
9517
+ this.CreateLocalizedLine("Authorization", (measurementValue.measurement.chargingSession?.authorizationStart["@id"] ?? "") + " hex", pad(result.uid, 20), infoDiv, PlainTextDiv);
9518
+ this.CreateLocalizedLine("SessionId", measurementValue.measurement.chargingSession?.["@id"] ?? "", result.sessionId ?? "", infoDiv, PlainTextDiv);
9519
+ this.CreateLocalizedLine("Pagination counter", measurementValue.paginationId, result.paging ?? "", infoDiv, PlainTextDiv);
9499
9520
  }
9500
9521
  {
9501
- if (HashedPlainTextDiv.parentElement && HashedPlainTextDiv.parentElement.children[0]) {
9502
- HashedPlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Hashed plain text") + " (SHA256, hex)";
9522
+ if (HashedPlainTextDiv.parentElement) {
9523
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = this.chargy.GetLocalizedMessage("Hashed plain text") + " (SHA256, hex)";
9503
9524
  }
9504
9525
  const hashValueText = typeof result.hashValue === "string" ? result.hashValue : result.hashValue?.toString(16) ?? "";
9505
9526
  HashedPlainTextDiv.innerHTML = hashValueText.match(/.{1,8}/g)?.join(" ") ?? "";
9506
9527
  }
9507
- if (result.publicKey && result.publicKey != "") {
9508
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[0]) {
9509
- PublicKeyDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Public Key") + " (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "base32)";
9528
+ if (result.publicKey != null && result.publicKey.length > 0) {
9529
+ if (PublicKeyDiv.parentElement) {
9530
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = this.chargy.GetLocalizedMessage("Public Key") + " (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "base32)";
9510
9531
  }
9511
9532
  if (!IsNullOrEmpty(result.publicKey))
9512
9533
  PublicKeyDiv.innerHTML = result.publicKey.match(/.{1,4}/g)?.join(" ") ?? "";
9513
9534
  }
9514
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[3]) {
9535
+ if (PublicKeyDiv.parentElement?.children[3]) {
9515
9536
  PublicKeyDiv.parentElement.children[3].innerHTML = "";
9516
9537
  if (result.publicKeySignatures) {
9517
9538
  for (const signature of result.publicKeySignatures) {
@@ -9530,14 +9551,14 @@ var AlfenCrypt01 = class extends ACrypt {
9530
9551
  }
9531
9552
  }
9532
9553
  if (result.signature != null) {
9533
- if (SignatureExpectedDiv.parentElement && SignatureExpectedDiv.parentElement.children[0]) {
9534
- SignatureExpectedDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (" + (result.signature.format ?? "") + ", hex)";
9554
+ if (SignatureExpectedDiv.parentElement) {
9555
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (" + (result.signature.format ?? "") + ", hex)";
9535
9556
  }
9536
- if (result.signature.r && result.signature.s) {
9557
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0) {
9537
9558
  const signatureR = result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
9538
9559
  const signatureS = result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
9539
9560
  SignatureExpectedDiv.innerHTML = "r: " + signatureR + "<br />s: " + signatureS;
9540
- } else if (result.signature.value)
9561
+ } else if (result.signature.value != null && result.signature.value.length > 0)
9541
9562
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
9542
9563
  }
9543
9564
  {
@@ -9779,10 +9800,14 @@ var BSMCrypt01 = class extends ACrypt {
9779
9800
  throw new Error(`Invalid identification of signed meter value #${String(measurementCounter - 1)}!`);
9780
9801
  const previousParts = previousId.split("-");
9781
9802
  const currentParts = currentId.split("-");
9782
- if (previousParts.length !== 2 || currentParts.length !== 2 || previousParts[0] !== currentParts[0] || previousParts[1] === void 0 || currentParts[1] === void 0 || // parseInt returns NaN in case parsing fails which in turn does not match
9803
+ const previousPrefix = previousParts.at(0);
9804
+ const previousCounter = previousParts.at(1);
9805
+ const currentPrefix = currentParts.at(0);
9806
+ const currentCounter = currentParts.at(1);
9807
+ if (previousParts.length !== 2 || currentParts.length !== 2 || previousPrefix !== currentPrefix || previousCounter === void 0 || currentCounter === void 0 || // parseInt returns NaN in case parsing fails which in turn does not match
9783
9808
  // anything (not even NaN). This way we are checking that both counter values
9784
9809
  // are numeric too.
9785
- parseInt(previousParts[1], 10) >= parseInt(currentParts[1], 10)) {
9810
+ parseInt(previousCounter, 10) >= parseInt(currentCounter, 10)) {
9786
9811
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeasurementIdP", measurementCounter)));
9787
9812
  }
9788
9813
  }
@@ -9820,7 +9845,7 @@ var BSMCrypt01 = class extends ACrypt {
9820
9845
  precision: asNumber(displayedFormat?.["precision"])
9821
9846
  };
9822
9847
  });
9823
- if (currentMeasurement["meterInfo"]) {
9848
+ if (currentMeasurement["meterInfo"] != null) {
9824
9849
  const meterInfoObj2 = asJSONObject(currentMeasurement["meterInfo"]);
9825
9850
  if (meterInfoObj2?.["firmwareVersion"] !== common.meterInfo_firmwareVersion)
9826
9851
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_FirmwareVersionP", measurementCounter)));
@@ -9828,42 +9853,42 @@ var BSMCrypt01 = class extends ACrypt {
9828
9853
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_PublicKeyP", measurementCounter)));
9829
9854
  if (meterInfoObj2?.["meterId"] !== common.meterInfo_meterId)
9830
9855
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_MeterIdP", measurementCounter)));
9831
- if (meterInfoObj2?.["meterId"] !== additionalValues.filter((element) => element.measurandName === "MA1")[0]?.value)
9856
+ if (meterInfoObj2?.["meterId"] !== additionalValues.find((element) => element.measurandName === "MA1")?.value)
9832
9857
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_MeterIdP", measurementCounter)));
9833
9858
  if (meterInfoObj2?.["manufacturer"] !== common.meterInfo_manufacturer)
9834
9859
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_ManufacturerP", measurementCounter)));
9835
9860
  if (meterInfoObj2?.["type"] !== common.meterInfo_type)
9836
9861
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_MeterInfo_TypeP", measurementCounter)));
9837
9862
  }
9838
- if (currentMeasurement["contract"]) {
9863
+ if (currentMeasurement["contract"] != null) {
9839
9864
  const contractObj2 = asJSONObject(currentMeasurement["contract"]);
9840
- if (additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("contract-id:")).length == 0)
9865
+ if (additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("contract-id:") === true).length == 0)
9841
9866
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
9842
9867
  if (contractObj2?.["id"] !== common.contract_id)
9843
9868
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
9844
9869
  if (contractObj2?.["type"] !== common.contract_type)
9845
9870
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_TypeP", measurementCounter)));
9846
- const contractInfo = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("contract-id:"))[0]?.value;
9871
+ const contractInfo = additionalValues.find((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("contract-id:") === true)?.value;
9847
9872
  if (contractInfo != null) {
9848
- if (contractObj2?.["type"] && contractInfo !== "contract-id: " + (common.contract_type ?? "-") + ":" + common.contract_id)
9873
+ if (contractObj2?.["type"] != null && contractInfo !== "contract-id: " + (common.contract_type ?? "-") + ":" + common.contract_id)
9849
9874
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
9850
- if (!contractObj2?.["type"] && contractInfo !== "contract-id: " + common.contract_id)
9875
+ if (contractObj2?.["type"] == null && contractInfo !== "contract-id: " + common.contract_id)
9851
9876
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_Contract_IdP", measurementCounter)));
9852
9877
  }
9853
9878
  }
9854
9879
  const rcrInAdditional = additionalValues.find((element) => element.measurandName == "RCR");
9855
9880
  if (currentMeasurement["value"] == null)
9856
9881
  throw new Error(`Missing value within signed meter value #${String(measurementCounter)}!`);
9857
- if ((valueObj2?.["measurand"] || valueObj2?.["measuredValue"]) && rcrInAdditional === void 0)
9882
+ if ((valueObj2?.["measurand"] != null || valueObj2?.["measuredValue"] != null) && rcrInAdditional === void 0)
9858
9883
  throw new Error(`Missing 'RCR' within the additional values of signed meter value #${String(measurementCounter)}!`);
9859
- if (valueObj2?.["measurand"]) {
9884
+ if (valueObj2?.["measurand"] != null) {
9860
9885
  const measurandObj2 = asJSONObject(valueObj2["measurand"]);
9861
9886
  if (measurandObj2?.["id"] !== common.value_measurand_id || measurandObj2["id"] !== rcrInAdditional?.measurandId)
9862
9887
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_Measurand_IdentificationP", measurementCounter)));
9863
9888
  if (measurandObj2?.["name"] !== common.value_measurand_name || measurandObj2["name"] !== rcrInAdditional?.measurandName)
9864
9889
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_Measurand_NameP", measurementCounter)));
9865
9890
  }
9866
- if (valueObj2?.["measuredValue"]) {
9891
+ if (valueObj2?.["measuredValue"] != null) {
9867
9892
  if (measuredValueObj2?.["value"] !== rcrInAdditional?.value)
9868
9893
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValueP", measurementCounter)));
9869
9894
  if (measuredValueObj2?.["scale"] !== common.value_measuredValue_scale || measuredValueObj2?.["scale"] !== rcrInAdditional?.scale)
@@ -9875,15 +9900,15 @@ var BSMCrypt01 = class extends ACrypt {
9875
9900
  if (measuredValueObj2?.["valueType"] !== common.value_measuredValue_valueType || measuredValueObj2?.["valueType"] !== rcrInAdditional?.valueType)
9876
9901
  currentErrors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_SignedMeterValue_TypeP", measurementCounter)));
9877
9902
  }
9878
- if (currentMeasurement["chargePoint"] && asJSONObject(currentMeasurement["chargePoint"])?.["softwareVersion"] !== common.chargePoint_softwareVersion)
9903
+ if (currentMeasurement["chargePoint"] != null && asJSONObject(currentMeasurement["chargePoint"])?.["softwareVersion"] !== common.chargePoint_softwareVersion)
9879
9904
  currentErrors.push(CreateError(this.chargy.GetMultilanguageText("Inconsistent_ChargingStation_FirmwareVersion")));
9880
- const signedEVSEId = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("evse-id:"));
9905
+ const signedEVSEId = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("evse-id:") === true);
9881
9906
  if (signedEVSEId.length == 1) {
9882
9907
  const evse__id = (asString(signedEVSEId[0]?.value) ?? "").replace("evse-id:", "").trim();
9883
9908
  if (evse__id !== "unknown" && ExpectedEVSEId !== evse__id)
9884
9909
  currentErrors.push(CreateError(this.chargy.GetMultilanguageText("Inconsistent_EVSE_Identification")));
9885
9910
  }
9886
- const signedCSCSWVersion = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") && asString(element.value)?.startsWith("csc-sw-version:"));
9911
+ const signedCSCSWVersion = additionalValues.filter((element) => element.measurandName?.startsWith("Meta") === true && asString(element.value)?.startsWith("csc-sw-version:") === true);
9887
9912
  if (signedCSCSWVersion.length == 1) {
9888
9913
  const csc_sw_version = asString(signedCSCSWVersion[0]?.value)?.replace("csc-sw-version:", "").trim() ?? null;
9889
9914
  if (previousCscSwVersion !== null && previousCscSwVersion !== csc_sw_version)
@@ -9948,6 +9973,8 @@ var BSMCrypt01 = class extends ACrypt {
9948
9973
  case "Evt":
9949
9974
  Evt = asNumber(additionalValue.value) ?? NaN;
9950
9975
  break;
9976
+ default:
9977
+ break;
9951
9978
  }
9952
9979
  }
9953
9980
  const currentRCRValue = asNumber(RCR?.value) ?? NaN;
@@ -10010,18 +10037,17 @@ var BSMCrypt01 = class extends ACrypt {
10010
10037
  });
10011
10038
  }
10012
10039
  const n = common.dataSets.length - 1;
10013
- const firstDataSet = common.dataSets[0];
10014
- const lastDataSet = common.dataSets[n];
10015
- if (firstDataSet === void 0 || firstDataSet.TypParsed !== "START" && firstDataSet.TypParsed !== "TURN ON")
10040
+ const firstDataSet = getFirstArrayElement(common.dataSets, "Missing first BSM data set");
10041
+ const lastDataSet = getArrayElement(common.dataSets, n, "Missing last BSM data set");
10042
+ if (firstDataSet.TypParsed !== "START" && firstDataSet.TypParsed !== "TURN ON")
10016
10043
  throw new Error(this.chargy.GetLocalizedMessageWithParameter("Inconsistent_EnergyMeterValueP", 1));
10017
10044
  for (let i = 1; i < common.dataSets.length - 1; i++) {
10018
10045
  if (common.dataSets[i]?.TypParsed !== "CURRENT")
10019
10046
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("Inconsistent_EnergyMeterValueP", measurementCounter + 1)));
10020
10047
  }
10021
- if (lastDataSet === void 0 || lastDataSet.TypParsed !== "END" && lastDataSet.TypParsed !== "TURN OFF")
10048
+ if (lastDataSet.TypParsed !== "END" && lastDataSet.TypParsed !== "TURN OFF")
10022
10049
  throw new Error(this.chargy.GetLocalizedMessageWithParameter("Inconsistent_EnergyMeterValueP", n + 1));
10023
- if (CTR.chargingSessions == null)
10024
- CTR.chargingSessions = [];
10050
+ CTR.chargingSessions ??= [];
10025
10051
  const ASN1_SignatureSchema = this.chargy.asn1.define("Signature", function() {
10026
10052
  this.seq().obj(
10027
10053
  this.key("r").int(),
@@ -10138,12 +10164,12 @@ var BSMCrypt01 = class extends ACrypt {
10138
10164
  CTR.chargingSessions.push(session);
10139
10165
  CTR["@id"] = common.meterInfo_meterId + "-" + String(firstDataSet.Epoch);
10140
10166
  {
10141
- const firstChargingSession = CTR.chargingSessions[0];
10142
- const lastChargingSession = CTR.chargingSessions[CTR.chargingSessions.length - 1];
10143
- if (firstChargingSession !== void 0 && (CTR.begin == void 0 || CTR.begin === "" || CTR.begin > firstChargingSession.begin)) {
10167
+ const firstChargingSession = getFirstArrayElement(CTR.chargingSessions, "Missing first BSM charging session");
10168
+ const lastChargingSession = getLastArrayElement(CTR.chargingSessions, "Missing last BSM charging session");
10169
+ if (CTR.begin == void 0 || CTR.begin === "" || CTR.begin > firstChargingSession.begin) {
10144
10170
  CTR.begin = firstChargingSession.begin;
10145
10171
  }
10146
- if (lastChargingSession?.end !== void 0) {
10172
+ if (lastChargingSession.end !== void 0) {
10147
10173
  if (CTR.end == void 0 || CTR.end === "" || CTR.end < lastChargingSession.end)
10148
10174
  CTR.end = lastChargingSession.end;
10149
10175
  }
@@ -10315,58 +10341,63 @@ var BSMCrypt01 = class extends ACrypt {
10315
10341
  }
10316
10342
  return {};
10317
10343
  }
10318
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
10344
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
10319
10345
  if (measurementValue.measurement === void 0)
10320
10346
  return new Error("Invalid measurement!");
10321
10347
  const result = measurementValue.result;
10322
10348
  introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "BSMCrypt01").replace("{cryptoAlgorithm}", this.description);
10323
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
10324
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (" + measurementValue.result.ArraySize.toString() + " Bytes, hex)";
10349
+ if (PlainTextDiv.parentElement) {
10350
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (" + measurementValue.result.ArraySize.toString() + " Bytes, hex)";
10325
10351
  }
10326
10352
  PlainTextDiv.style.fontFamily = "";
10327
10353
  PlainTextDiv.style.whiteSpace = "";
10328
10354
  PlainTextDiv.style.maxHeight = "";
10329
10355
  PlainTextDiv.style.overflowY = "";
10330
- this.CreateLine("Snapshot-Typ", this.ParseTyp(measurementValue.Typ), result.Typ || "", infoDiv, PlainTextDiv);
10331
- this.CreateLine("RCR", (measurementValue.RCR * 10 ** measurementValue.RCR_SF).toString() + " " + measurementValue.RCR_Unit, result.RCR || "", infoDiv, PlainTextDiv);
10332
- this.CreateLine("TotWhImp", (measurementValue.TotWhImp * 10 ** measurementValue.TotWhImp_SF).toString() + " " + measurementValue.TotWhImp_Unit, result.TotWhImp || "", infoDiv, PlainTextDiv);
10333
- this.CreateLine("W", (measurementValue.W * 10 ** measurementValue.W_SF).toString() + " " + measurementValue.W_Unit, result.W || "", infoDiv, PlainTextDiv);
10334
- this.CreateLine("MA1", measurementValue.MA1, result.MA1 || "", infoDiv, PlainTextDiv);
10335
- this.CreateLine("RCnt", measurementValue.RCnt, result.RCnt || "", infoDiv, PlainTextDiv);
10336
- this.CreateLine("OS", measurementValue.OS, result.OS || "", infoDiv, PlainTextDiv);
10337
- this.CreateLine("Zeitstempel", UTC2human(measurementValue.Epoch), result.Epoch || "", infoDiv, PlainTextDiv);
10338
- this.CreateLine("TZO", measurementValue.TZO.toString() + " Minuten", result.TZO || "", infoDiv, PlainTextDiv);
10339
- this.CreateLine("EpochSetCnt", measurementValue.EpochSetCnt, result.EpochSetCnt || "", infoDiv, PlainTextDiv);
10340
- this.CreateLine("EpochSetOS", measurementValue.EpochSetOS, result.EpochSetOS || "", infoDiv, PlainTextDiv);
10341
- this.CreateLine("DI", measurementValue.DI, result.DI || "", infoDiv, PlainTextDiv);
10342
- this.CreateLine("DO", measurementValue.DO, result.DO || "", infoDiv, PlainTextDiv);
10343
- this.CreateLine("Meta1", measurementValue.Meta1, result.Meta1 || "", infoDiv, PlainTextDiv);
10344
- this.CreateLine("Meta2", measurementValue.Meta2, result.Meta2 || "", infoDiv, PlainTextDiv);
10345
- this.CreateLine("Meta3", measurementValue.Meta3, result.Meta3 || "", infoDiv, PlainTextDiv);
10346
- this.CreateLine("Evt", this.ParseEvents(measurementValue.Evt).join("<br>"), result.Evt || "", infoDiv, PlainTextDiv);
10347
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
10348
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text (SHA256, hex)";
10356
+ this.CreateLine("Snapshot-Typ", this.ParseTyp(measurementValue.Typ), result.Typ, infoDiv, PlainTextDiv);
10357
+ this.CreateLine("RCR", (measurementValue.RCR * 10 ** measurementValue.RCR_SF).toString() + " " + measurementValue.RCR_Unit, result.RCR, infoDiv, PlainTextDiv);
10358
+ this.CreateLine("TotWhImp", (measurementValue.TotWhImp * 10 ** measurementValue.TotWhImp_SF).toString() + " " + measurementValue.TotWhImp_Unit, result.TotWhImp, infoDiv, PlainTextDiv);
10359
+ this.CreateLine("W", (measurementValue.W * 10 ** measurementValue.W_SF).toString() + " " + measurementValue.W_Unit, result.W, infoDiv, PlainTextDiv);
10360
+ this.CreateLine("MA1", measurementValue.MA1, result.MA1, infoDiv, PlainTextDiv);
10361
+ this.CreateLine("RCnt", measurementValue.RCnt, result.RCnt, infoDiv, PlainTextDiv);
10362
+ this.CreateLine("OS", measurementValue.OS, result.OS, infoDiv, PlainTextDiv);
10363
+ this.CreateLine("Zeitstempel", UTC2human(measurementValue.Epoch), result.Epoch, infoDiv, PlainTextDiv);
10364
+ this.CreateLine("TZO", measurementValue.TZO.toString() + " Minuten", result.TZO, infoDiv, PlainTextDiv);
10365
+ this.CreateLine("EpochSetCnt", measurementValue.EpochSetCnt, result.EpochSetCnt, infoDiv, PlainTextDiv);
10366
+ this.CreateLine("EpochSetOS", measurementValue.EpochSetOS, result.EpochSetOS, infoDiv, PlainTextDiv);
10367
+ this.CreateLine("DI", measurementValue.DI, result.DI, infoDiv, PlainTextDiv);
10368
+ this.CreateLine("DO", measurementValue.DO, result.DO, infoDiv, PlainTextDiv);
10369
+ this.CreateLine("Meta1", measurementValue.Meta1, result.Meta1, infoDiv, PlainTextDiv);
10370
+ this.CreateLine("Meta2", measurementValue.Meta2, result.Meta2, infoDiv, PlainTextDiv);
10371
+ this.CreateLine("Meta3", measurementValue.Meta3, result.Meta3, infoDiv, PlainTextDiv);
10372
+ this.CreateLine("Evt", this.ParseEvents(measurementValue.Evt).join("<br>"), result.Evt, infoDiv, PlainTextDiv);
10373
+ if (HashedPlainTextDiv.parentElement) {
10374
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, hex)";
10349
10375
  }
10350
10376
  HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
10351
10377
  if (result.publicKey != null && result.publicKey != "") {
10352
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
10353
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "hex)";
10378
+ if (PublicKeyDiv.parentElement) {
10379
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
10354
10380
  }
10355
10381
  if (!IsNullOrEmpty(result.publicKey))
10356
10382
  PublicKeyDiv.innerHTML = result.publicKey.startsWith("04") ? '<span class="leadingFour">04</span> ' + (result.publicKey.substring(2).match(/.{1,8}/g)?.join(" ") ?? "-") : result.publicKey.match(/.{1,8}/g)?.join(" ") ?? "-";
10357
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
10358
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
10383
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
10384
+ if (publicKeySignatureContainer !== void 0) {
10385
+ publicKeySignatureContainer.innerHTML = "";
10359
10386
  }
10360
10387
  if (result.publicKeySignatures) {
10361
10388
  for (const signature of result.publicKeySignatures) {
10362
10389
  try {
10363
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
10364
- if (signatureDiv != null && measurementValue.measurement.chargingSession != null && measurementValue.measurement.chargingSession.EVSE != null && measurementValue.measurement.chargingSession.EVSE.meters.length > 0 && measurementValue.measurement.chargingSession.EVSE.meters[0] != null && measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys != null && measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys.length > 0) {
10390
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
10391
+ const chargingSession = measurementValue.measurement.chargingSession;
10392
+ const evse = chargingSession?.EVSE;
10393
+ const meter = evse?.meters.at(0);
10394
+ const publicKey = meter?.publicKeys?.at(0);
10395
+ if (signatureDiv != null && chargingSession != null && evse != null && meter != null && publicKey != null) {
10365
10396
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
10366
- measurementValue.measurement.chargingSession.chargingStation,
10367
- measurementValue.measurement.chargingSession.EVSE,
10368
- measurementValue.measurement.chargingSession.EVSE.meters[0],
10369
- measurementValue.measurement.chargingSession.EVSE.meters[0].publicKeys[0],
10397
+ chargingSession.chargingStation,
10398
+ evse,
10399
+ meter,
10400
+ publicKey,
10370
10401
  signature
10371
10402
  );
10372
10403
  }
@@ -10377,12 +10408,12 @@ var BSMCrypt01 = class extends ACrypt {
10377
10408
  }
10378
10409
  }
10379
10410
  if (result.signature != null) {
10380
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
10381
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (" + (result.signature.format || "") + ", hex)";
10411
+ if (SignatureExpectedDiv.parentElement) {
10412
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
10382
10413
  }
10383
- if (result.signature.r && result.signature.s)
10414
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
10384
10415
  SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-");
10385
- else if (result.signature.value)
10416
+ else if (result.signature.value != null && result.signature.value.length > 0)
10386
10417
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
10387
10418
  }
10388
10419
  switch (result.status) {
@@ -10408,6 +10439,7 @@ var BSMCrypt01 = class extends ACrypt {
10408
10439
  SignatureCheckDiv.innerHTML = '<i class="fas fa-times-circle"></i><div id="description">Ung\xFCltige Signatur</div>';
10409
10440
  break;
10410
10441
  }
10442
+ return void 0;
10411
10443
  }
10412
10444
  //#region Helper methods
10413
10445
  PrefixConverter(input) {
@@ -10486,30 +10518,35 @@ var BSMCrypt01 = class extends ACrypt {
10486
10518
  if ((value & 1 << 29) != 0) events.push("OEM 15");
10487
10519
  return events;
10488
10520
  }
10489
- DecodeStatus(statusValue) {
10490
- const statusArray = [];
10491
- try {
10492
- const status = parseInt(statusValue);
10493
- if ((status & 1) == 1)
10494
- statusArray.push("Fehler erkannt");
10495
- if ((status & 2) == 2)
10496
- statusArray.push("Synchrone Messwert\xFCbermittlung");
10497
- if ((status & 8) == 8)
10498
- statusArray.push("System-Uhr ist synchron");
10499
- else
10500
- statusArray.push("System-Uhr ist nicht synchron");
10501
- if ((status & 16) == 16)
10502
- statusArray.push("R\xFCcklaufsperre aktiv");
10503
- if ((status & 32) == 32)
10504
- statusArray.push("Energierichtung -A");
10505
- if ((status & 64) == 64)
10506
- statusArray.push("Magnetfeld erkannt");
10507
- } catch {
10508
- statusArray.push("Invalid status!");
10509
- }
10510
- return statusArray;
10511
- }
10512
- //#endregion
10521
+ // private DecodeStatus(statusValue: string) : Array<string>
10522
+ // {
10523
+ // const statusArray:string[] = [];
10524
+ // try
10525
+ // {
10526
+ // const status = parseInt(statusValue);
10527
+ // if ((status & 1) == 1)
10528
+ // statusArray.push("Fehler erkannt");
10529
+ // if ((status & 2) == 2)
10530
+ // statusArray.push("Synchrone Messwertübermittlung");
10531
+ // // Bit 3 is reserved!
10532
+ // if ((status & 8) == 8)
10533
+ // statusArray.push("System-Uhr ist synchron");
10534
+ // else
10535
+ // statusArray.push("System-Uhr ist nicht synchron");
10536
+ // if ((status & 16) == 16)
10537
+ // statusArray.push("Rücklaufsperre aktiv");
10538
+ // if ((status & 32) == 32)
10539
+ // statusArray.push("Energierichtung -A");
10540
+ // if ((status & 64) == 64)
10541
+ // statusArray.push("Magnetfeld erkannt");
10542
+ // }
10543
+ // catch
10544
+ // {
10545
+ // statusArray.push("Invalid status!");
10546
+ // }
10547
+ // return statusArray;
10548
+ // }
10549
+ // //#endregion
10513
10550
  };
10514
10551
 
10515
10552
  // src/CanonicalJSON.ts
@@ -10909,7 +10946,7 @@ var EMHCrypt01 = class extends ACrypt {
10909
10946
  measurementValue.result = cryptoResult;
10910
10947
  return cryptoResult;
10911
10948
  }
10912
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0) {
10949
+ if (measurementValue.measurement?.chargingSession === void 0) {
10913
10950
  return {
10914
10951
  status: "InvalidMeasurement" /* InvalidMeasurement */
10915
10952
  };
@@ -10948,9 +10985,10 @@ var EMHCrypt01 = class extends ACrypt {
10948
10985
  cryptoResult.meter = meter;
10949
10986
  if (meter.publicKeys != null && meter.publicKeys.length > 0) {
10950
10987
  try {
10951
- cryptoResult.publicKey = meter.publicKeys[0]?.value?.toLowerCase();
10952
- cryptoResult.publicKeyFormat = meter.publicKeys[0]?.format;
10953
- cryptoResult.publicKeySignatures = meter.publicKeys[0]?.signatures;
10988
+ const publicKey = meter.publicKeys.at(0);
10989
+ cryptoResult.publicKey = publicKey?.value?.toLowerCase();
10990
+ cryptoResult.publicKeyFormat = publicKey?.format;
10991
+ cryptoResult.publicKeySignatures = publicKey?.signatures;
10954
10992
  try {
10955
10993
  if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
10956
10994
  cryptoResult.sha256value,
@@ -10975,59 +11013,60 @@ var EMHCrypt01 = class extends ACrypt {
10975
11013
  }
10976
11014
  return {};
10977
11015
  }
10978
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
10979
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0 || measurementValue.measurement.chargingSession.authorizationStart.timestamp === void 0) {
11016
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11017
+ if (measurementValue.measurement?.chargingSession?.authorizationStart.timestamp === void 0) {
10980
11018
  return new Error("Invalid measurement!");
10981
11019
  }
10982
11020
  const result = measurementValue.result;
10983
11021
  introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "EMHCrypt01").replace("{cryptoAlgorithm}", this.description);
10984
11022
  {
10985
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
10986
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (320 Bytes, hex)";
11023
+ if (PlainTextDiv.parentElement) {
11024
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (320 Bytes, hex)";
10987
11025
  }
10988
11026
  PlainTextDiv.style.fontFamily = "";
10989
11027
  PlainTextDiv.style.whiteSpace = "";
10990
11028
  PlainTextDiv.style.maxHeight = "";
10991
11029
  PlainTextDiv.style.overflowY = "";
10992
- this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, PlainTextDiv);
10993
- this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp || "", infoDiv, PlainTextDiv);
10994
- this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + ' hex)<br /><span class="statusInfos">' + this.DecodeStatus(measurementValue.infoStatus).join("<br />") + "</span>", result.infoStatus || "", infoDiv, PlainTextDiv);
10995
- this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex || "", infoDiv, PlainTextDiv);
10996
- this.CreateLine("Paginierungsz\xE4hler", parseInt(measurementValue.paginationId, 16), result.paginationId || "", infoDiv, PlainTextDiv);
10997
- this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis || "", infoDiv, PlainTextDiv);
10998
- this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded || "", infoDiv, PlainTextDiv);
10999
- this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, PlainTextDiv);
11000
- this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value || "", infoDiv, PlainTextDiv);
11001
- this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex || "", infoDiv, PlainTextDiv);
11002
- this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, PlainTextDiv);
11003
- this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, PlainTextDiv);
11030
+ this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
11031
+ this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
11032
+ this.CreateLine("Status", hex2bin(measurementValue.infoStatus) + " (" + measurementValue.infoStatus + ' hex)<br /><span class="statusInfos">' + this.DecodeStatus(measurementValue.infoStatus).join("<br />") + "</span>", result.infoStatus ?? "", infoDiv, PlainTextDiv);
11033
+ this.CreateLine("Sekundenindex", measurementValue.secondsIndex, result.secondsIndex ?? "", infoDiv, PlainTextDiv);
11034
+ this.CreateLine("Paginierungsz\xE4hler", parseInt(measurementValue.paginationId, 16), result.paginationId ?? "", infoDiv, PlainTextDiv);
11035
+ this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis ?? "", infoDiv, PlainTextDiv);
11036
+ this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
11037
+ this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale ?? "", infoDiv, PlainTextDiv);
11038
+ this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
11039
+ this.CreateLine("Logbuchindex", measurementValue.logBookIndex + " hex", result.logBookIndex ?? "", infoDiv, PlainTextDiv);
11040
+ this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128), infoDiv, PlainTextDiv);
11041
+ this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151), infoDiv, PlainTextDiv);
11004
11042
  }
11005
11043
  {
11006
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
11007
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
11044
+ if (HashedPlainTextDiv.parentElement) {
11045
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
11008
11046
  }
11009
11047
  HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
11010
11048
  }
11011
11049
  if (result.publicKey != null && result.publicKey != "") {
11012
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
11013
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "hex)";
11050
+ if (PublicKeyDiv.parentElement) {
11051
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
11014
11052
  }
11015
11053
  if (!IsNullOrEmpty(result.publicKey))
11016
11054
  PublicKeyDiv.innerHTML = result.publicKey.startsWith("04") ? '<span class="leadingFour">04</span> ' + (result.publicKey.substring(2).match(/.{1,8}/g)?.join(" ") ?? "") : result.publicKey.match(/.{1,8}/g)?.join(" ") ?? "";
11017
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
11018
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
11055
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
11056
+ if (publicKeySignatureContainer !== void 0) {
11057
+ publicKeySignatureContainer.innerHTML = "";
11019
11058
  }
11020
11059
  if (result.publicKeySignatures) {
11021
11060
  for (const signature of result.publicKeySignatures) {
11022
11061
  try {
11023
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
11062
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
11024
11063
  if (signatureDiv) {
11025
11064
  signatureDiv.classList.add("signature");
11026
11065
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
11027
11066
  measurementValue.measurement.chargingSession.chargingStation,
11028
11067
  measurementValue.measurement.chargingSession.EVSE,
11029
- measurementValue.measurement.chargingSession.EVSE?.meters[0],
11030
- measurementValue.measurement.chargingSession.EVSE?.meters[0]?.publicKeys?.[0],
11068
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
11069
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
11031
11070
  signature
11032
11071
  );
11033
11072
  signatureDiv.onclick = () => {
@@ -11041,12 +11080,12 @@ var EMHCrypt01 = class extends ACrypt {
11041
11080
  }
11042
11081
  }
11043
11082
  if (result.signature != null) {
11044
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
11045
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (" + (result.signature.format || "") + ", hex)";
11083
+ if (SignatureExpectedDiv.parentElement) {
11084
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
11046
11085
  }
11047
- if (result.signature.r && result.signature.s)
11086
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
11048
11087
  SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "");
11049
- else if (result.signature.value)
11088
+ else if (result.signature.value != null && result.signature.value.length > 0)
11050
11089
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
11051
11090
  }
11052
11091
  {
@@ -11074,6 +11113,7 @@ var EMHCrypt01 = class extends ACrypt {
11074
11113
  break;
11075
11114
  }
11076
11115
  }
11116
+ return void 0;
11077
11117
  }
11078
11118
  //#region Helper methods
11079
11119
  DecodeStatus(statusValue) {
@@ -11142,7 +11182,7 @@ var GDFCrypt01 = class extends ACrypt {
11142
11182
  measurementValue.result = cryptoResult;
11143
11183
  return cryptoResult;
11144
11184
  }
11145
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0) {
11185
+ if (measurementValue.measurement?.chargingSession === void 0) {
11146
11186
  return {
11147
11187
  status: "InvalidMeasurement" /* InvalidMeasurement */
11148
11188
  };
@@ -11177,9 +11217,10 @@ var GDFCrypt01 = class extends ACrypt {
11177
11217
  cryptoResult.meter = meter;
11178
11218
  if (meter.publicKeys != null && meter.publicKeys.length > 0) {
11179
11219
  try {
11180
- cryptoResult.publicKey = meter.publicKeys[0]?.value?.toLowerCase();
11181
- cryptoResult.publicKeyFormat = meter.publicKeys[0]?.format;
11182
- cryptoResult.publicKeySignatures = meter.publicKeys[0]?.signatures;
11220
+ const publicKey = meter.publicKeys.at(0);
11221
+ cryptoResult.publicKey = publicKey?.value?.toLowerCase();
11222
+ cryptoResult.publicKeyFormat = publicKey?.format;
11223
+ cryptoResult.publicKeySignatures = publicKey?.signatures;
11183
11224
  try {
11184
11225
  if (this.curve.keyFromPublic(cryptoResult.publicKey ?? "", "hex").verify(
11185
11226
  cryptoResult.sha256value,
@@ -11204,54 +11245,55 @@ var GDFCrypt01 = class extends ACrypt {
11204
11245
  }
11205
11246
  return {};
11206
11247
  }
11207
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11208
- if (measurementValue.measurement === void 0 || measurementValue.measurement.chargingSession === void 0 || measurementValue.measurement.chargingSession.authorizationStart.timestamp === void 0) {
11248
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11249
+ if (measurementValue.measurement?.chargingSession?.authorizationStart.timestamp === void 0) {
11209
11250
  return new Error("Invalid measurement!");
11210
11251
  }
11211
11252
  const result = measurementValue.result;
11212
11253
  introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "GDFCrypt01").replace("{cryptoAlgorithm}", this.description);
11213
11254
  {
11214
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
11215
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (320 Bytes, hex)";
11255
+ if (PlainTextDiv.parentElement) {
11256
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (320 Bytes, hex)";
11216
11257
  }
11217
11258
  PlainTextDiv.style.fontFamily = "";
11218
11259
  PlainTextDiv.style.whiteSpace = "";
11219
11260
  PlainTextDiv.style.maxHeight = "";
11220
11261
  PlainTextDiv.style.overflowY = "";
11221
- this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId || "", infoDiv, PlainTextDiv);
11222
- this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp || "", infoDiv, PlainTextDiv);
11223
- this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis || "", infoDiv, PlainTextDiv);
11224
- this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded || "", infoDiv, PlainTextDiv);
11225
- this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale || "", infoDiv, PlainTextDiv);
11226
- this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value || "", infoDiv, PlainTextDiv);
11227
- this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128) || "", infoDiv, PlainTextDiv);
11228
- this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151) || "", infoDiv, PlainTextDiv);
11262
+ this.CreateLine("Z\xE4hlernummer", measurementValue.measurement.energyMeterId, result.meterId ?? "", infoDiv, PlainTextDiv);
11263
+ this.CreateLine("Zeitstempel", UTC2human(measurementValue.timestamp), result.timestamp ?? "", infoDiv, PlainTextDiv);
11264
+ this.CreateLine("OBIS-Kennzahl", measurementValue.measurement.obis, result.obis ?? "", infoDiv, PlainTextDiv);
11265
+ this.CreateLine("Einheit (codiert)", measurementValue.measurement.unitEncoded ?? 0, result.unitEncoded ?? "", infoDiv, PlainTextDiv);
11266
+ this.CreateLine("Skalierung", measurementValue.measurement.scale, result.scale ?? "", infoDiv, PlainTextDiv);
11267
+ this.CreateLine("Messwert", measurementValue.value.toString() + " Wh", result.value ?? "", infoDiv, PlainTextDiv);
11268
+ this.CreateLine("Autorisierung", measurementValue.measurement.chargingSession.authorizationStart["@id"] + " hex", pad(result.authorizationStart, 128), infoDiv, PlainTextDiv);
11269
+ this.CreateLine("Autorisierungszeitpunkt", UTC2human(measurementValue.measurement.chargingSession.authorizationStart.timestamp), pad(result.authorizationStartTimestamp, 151), infoDiv, PlainTextDiv);
11229
11270
  }
11230
11271
  {
11231
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
11232
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
11272
+ if (HashedPlainTextDiv.parentElement) {
11273
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text (SHA256, 24 bytes, hex)";
11233
11274
  }
11234
11275
  HashedPlainTextDiv.innerHTML = result.sha256value?.match(/.{1,8}/g)?.join(" ") ?? "";
11235
11276
  }
11236
11277
  if (result.publicKey != null && result.publicKey != "") {
11237
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
11238
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (result.publicKeyFormat ? result.publicKeyFormat + ", " : "") + "hex)";
11278
+ if (PublicKeyDiv.parentElement) {
11279
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (result.publicKeyFormat != null && result.publicKeyFormat.length > 0 ? result.publicKeyFormat + ", " : "") + "hex)";
11239
11280
  }
11240
11281
  if (!IsNullOrEmpty(result.publicKey))
11241
11282
  PublicKeyDiv.innerHTML = result.publicKey.startsWith("04") ? '<span class="leadingFour">04</span> ' + (result.publicKey.substring(2).match(/.{1,8}/g)?.join(" ") ?? "") : result.publicKey.match(/.{1,8}/g)?.join(" ") ?? "";
11242
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
11243
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
11283
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
11284
+ if (publicKeySignatureContainer !== void 0) {
11285
+ publicKeySignatureContainer.innerHTML = "";
11244
11286
  }
11245
11287
  if (result.publicKeySignatures) {
11246
11288
  for (const signature of result.publicKeySignatures) {
11247
11289
  try {
11248
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
11290
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
11249
11291
  if (signatureDiv != null)
11250
11292
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
11251
11293
  measurementValue.measurement.chargingSession.chargingStation,
11252
11294
  measurementValue.measurement.chargingSession.EVSE,
11253
- measurementValue.measurement.chargingSession.EVSE?.meters[0],
11254
- measurementValue.measurement.chargingSession.EVSE?.meters[0]?.publicKeys?.[0],
11295
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
11296
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
11255
11297
  signature
11256
11298
  );
11257
11299
  } catch (exception) {
@@ -11261,12 +11303,12 @@ var GDFCrypt01 = class extends ACrypt {
11261
11303
  }
11262
11304
  }
11263
11305
  if (result.signature != null) {
11264
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
11265
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (" + (result.signature.format || "") + ", hex)";
11306
+ if (SignatureExpectedDiv.parentElement) {
11307
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (" + (result.signature.format ?? "") + ", hex)";
11266
11308
  }
11267
- if (result.signature.r && result.signature.s)
11309
+ if (result.signature.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0)
11268
11310
  SignatureExpectedDiv.innerHTML = "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "");
11269
- else if (result.signature.value)
11311
+ else if (result.signature.value != null && result.signature.value.length > 0)
11270
11312
  SignatureExpectedDiv.innerHTML = result.signature.value.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "-";
11271
11313
  }
11272
11314
  {
@@ -11294,6 +11336,7 @@ var GDFCrypt01 = class extends ACrypt {
11294
11336
  break;
11295
11337
  }
11296
11338
  }
11339
+ return void 0;
11297
11340
  }
11298
11341
  };
11299
11342
  var MENNEKES_EDL40_XMLNS = "http://www.mennekes.de/Mennekes.EdlVerification.xsd";
@@ -11540,7 +11583,7 @@ var MennekesCrypt01 = class extends ACrypt {
11540
11583
  signedData.byteOffset + signedData.byteLength
11541
11584
  );
11542
11585
  cryptoResult.hashValue = (await sha256(new DataView(signedDataBuffer))).substring(0, 48);
11543
- const publicKey = cleanHex(meter.publicKeys[0]?.value ?? measurement.publicKey);
11586
+ const publicKey = cleanHex(meter.publicKeys.at(0)?.value ?? measurement.publicKey);
11544
11587
  if (publicKey.length !== 96)
11545
11588
  return setResult("InvalidPublicKey" /* InvalidPublicKey */);
11546
11589
  const result = this.curve192r1.keyFromPublic("04" + publicKey, "hex").verify(
@@ -11571,7 +11614,7 @@ var MennekesCrypt01 = class extends ACrypt {
11571
11614
  PublicKeyDiv.innerHTML = result.publicKey?.match(/.{1,8}/g)?.join(" ") ?? "";
11572
11615
  if (SignatureExpectedDiv.parentElement?.children[0])
11573
11616
  SignatureExpectedDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
11574
- SignatureExpectedDiv.innerHTML = result.signature?.r && result.signature.s ? "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") : "";
11617
+ SignatureExpectedDiv.innerHTML = result.signature?.r != null && result.signature.r.length > 0 && result.signature.s != null && result.signature.s.length > 0 ? "r: " + (result.signature.r.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (result.signature.s.toLowerCase().match(/.{1,8}/g)?.join(" ") ?? "") : "";
11575
11618
  SignatureCheckDiv.innerHTML = result.status === "ValidSignature" /* ValidSignature */ ? '<i class="fas fa-check-circle"></i><div id="description">' + this.chargy.GetLocalizedMessage("Valid signature") + "</div>" : '<i class="fas fa-times-circle"></i><div id="description">' + this.chargy.GetLocalizedMessage("Invalid signature") + "</div>";
11576
11619
  return Promise.resolve(void 0);
11577
11620
  }
@@ -11590,10 +11633,7 @@ function parseMennekesXMLDocument(XMLDocument) {
11590
11633
  throw new Error("No Mennekes ChargingProcess element found!");
11591
11634
  if (isLocalName(XMLDocument.documentElement, "ChargingProcess")) {
11592
11635
  if (chargingProcesses.length > 1) {
11593
- const chargingProcess = chargingProcesses[0];
11594
- if (chargingProcess != void 0)
11595
- return chargingProcess;
11596
- throw new Error("No Mennekes ChargingProcess found!");
11636
+ return getFirstArrayElement(chargingProcesses, "No Mennekes ChargingProcess found!");
11597
11637
  }
11598
11638
  }
11599
11639
  return {
@@ -11716,8 +11756,8 @@ function toMennekesMeasurementValue(measurement) {
11716
11756
  }
11717
11757
  function validateMennekesLawConformity(measurementValues, chargy) {
11718
11758
  const errors = new Array();
11719
- const start = measurementValues[0];
11720
- const end = measurementValues[measurementValues.length - 1];
11759
+ const start = measurementValues.at(0);
11760
+ const end = measurementValues.at(-1);
11721
11761
  if (start == null || end == null)
11722
11762
  return [
11723
11763
  CreateError(chargy.GetMultilanguageText("Mennekes EDL40 requires at least two measurement values."))
@@ -11847,9 +11887,9 @@ var OCMFv1_x = class extends ACrypt {
11847
11887
  }
11848
11888
  async VerifyMeasurement(measurementValue) {
11849
11889
  measurementValue.method = this;
11850
- return {
11890
+ return Promise.resolve({
11851
11891
  status: measurementValue.result?.status ?? "Unvalidated" /* Unvalidated */
11852
- };
11892
+ });
11853
11893
  }
11854
11894
  PayloadDictionary(Path, Key) {
11855
11895
  if (Path === "RD") {
@@ -11919,7 +11959,7 @@ var OCMFv1_x = class extends ACrypt {
11919
11959
  return Key;
11920
11960
  }
11921
11961
  }
11922
- SignatureDictionary(Path, Key) {
11962
+ SignatureDictionary(_Path, Key) {
11923
11963
  switch (Key) {
11924
11964
  case "SA":
11925
11965
  return "Signature Algorithm";
@@ -11933,16 +11973,16 @@ var OCMFv1_x = class extends ACrypt {
11933
11973
  return Key;
11934
11974
  }
11935
11975
  }
11936
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11976
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, _infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
11937
11977
  if (!measurementValue.measurement || !measurementValue.ocmfDocument || !measurementValue.measurement.chargingSession) {
11938
11978
  return new Error("Invalid measurement!");
11939
11979
  }
11940
11980
  {
11941
- introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "OCMFCrypt01").replace("{cryptoAlgorithm}", measurementValue.ocmfDocument.publicKey && typeof measurementValue.ocmfDocument.publicKey !== "string" ? "(" + measurementValue.ocmfDocument.publicKey.algorithm + ") " : "");
11981
+ introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "OCMFCrypt01").replace("{cryptoAlgorithm}", measurementValue.ocmfDocument.publicKey != null && typeof measurementValue.ocmfDocument.publicKey !== "string" ? "(" + measurementValue.ocmfDocument.publicKey.algorithm + ") " : "");
11942
11982
  }
11943
11983
  {
11944
- if (PlainTextDiv.parentElement && PlainTextDiv.parentElement.children[0]) {
11945
- PlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (OCMF|&lt;" + this.chargy.GetLocalizedMessage("payload") + "&gt;|&lt;" + this.chargy.GetLocalizedMessage("signature") + "&gt;)";
11984
+ if (PlainTextDiv.parentElement) {
11985
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = this.chargy.GetLocalizedMessage("Plain text") + " (OCMF|&lt;" + this.chargy.GetLocalizedMessage("payload") + "&gt;|&lt;" + this.chargy.GetLocalizedMessage("signature") + "&gt;)";
11946
11986
  }
11947
11987
  PlainTextDiv.innerText = "";
11948
11988
  const compactValueDiv = document.createElement("div");
@@ -11974,29 +12014,30 @@ var OCMFv1_x = class extends ACrypt {
11974
12014
  };
11975
12015
  }
11976
12016
  {
11977
- if (HashedPlainTextDiv.parentElement && HashedPlainTextDiv.parentElement.children[0]) {
11978
- HashedPlainTextDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Hashed payload") + " (" + measurementValue.ocmfDocument.hashAlgorithm + ")";
12017
+ if (HashedPlainTextDiv.parentElement) {
12018
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed payload header").innerHTML = this.chargy.GetLocalizedMessage("Hashed payload") + " (" + measurementValue.ocmfDocument.hashAlgorithm + ")";
11979
12019
  }
11980
12020
  HashedPlainTextDiv.innerHTML = measurementValue.ocmfDocument.hashValue.match(/.{1,8}/g)?.join(" ") ?? "0x00000000000000000000000000000000000";
11981
12021
  }
11982
- if (measurementValue.ocmfDocument.publicKey) {
11983
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[0]) {
11984
- PublicKeyDiv.parentElement.children[0].innerHTML = typeof measurementValue.ocmfDocument.publicKey === "string" ? this.chargy.GetLocalizedMessage("Public Key") : this.chargy.GetLocalizedMessage("Public Key") + " (" + measurementValue.ocmfDocument.publicKey.algorithm + ", " + measurementValue.ocmfDocument.publicKey.encoding + ")";
12022
+ if (measurementValue.ocmfDocument.publicKey != null) {
12023
+ if (PublicKeyDiv.parentElement) {
12024
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = typeof measurementValue.ocmfDocument.publicKey === "string" ? this.chargy.GetLocalizedMessage("Public Key") : this.chargy.GetLocalizedMessage("Public Key") + " (" + measurementValue.ocmfDocument.publicKey.algorithm + ", " + measurementValue.ocmfDocument.publicKey.encoding + ")";
11985
12025
  }
11986
12026
  PublicKeyDiv.innerHTML = typeof measurementValue.ocmfDocument.publicKey === "string" ? measurementValue.ocmfDocument.publicKey : "der: " + (measurementValue.ocmfDocument.publicKey.value?.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br /><br />x:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.publicKey.x.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />y:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.publicKey.y.match(/.{1,8}/g)?.join(" ") ?? "-");
11987
12027
  }
11988
- if (PublicKeyDiv.parentElement && PublicKeyDiv.parentElement.children[3]) {
11989
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
12028
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
12029
+ if (publicKeySignatureContainer !== void 0) {
12030
+ publicKeySignatureContainer.innerHTML = "";
11990
12031
  const result = measurementValue.result;
11991
12032
  if (result.publicKeySignatures) {
11992
12033
  for (const signature of result.publicKeySignatures) {
11993
12034
  try {
11994
- const signatureDiv = PublicKeyDiv.parentElement.children[3].appendChild(document.createElement("div"));
12035
+ const signatureDiv = publicKeySignatureContainer.appendChild(document.createElement("div"));
11995
12036
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
11996
12037
  measurementValue.measurement.chargingSession.chargingStation,
11997
12038
  measurementValue.measurement.chargingSession.EVSE,
11998
- measurementValue.measurement.chargingSession.EVSE?.meters[0],
11999
- measurementValue.measurement.chargingSession.EVSE?.meters[0]?.publicKeys?.[0],
12039
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0),
12040
+ measurementValue.measurement.chargingSession.EVSE?.meters.at(0)?.publicKeys?.at(0),
12000
12041
  signature
12001
12042
  );
12002
12043
  } catch {
@@ -12006,8 +12047,8 @@ var OCMFv1_x = class extends ACrypt {
12006
12047
  }
12007
12048
  }
12008
12049
  if (measurementValue.ocmfDocument.signature.SD) {
12009
- if (SignatureExpectedDiv.parentElement && SignatureExpectedDiv.parentElement.children[0]) {
12010
- SignatureExpectedDiv.parentElement.children[0].innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
12050
+ if (SignatureExpectedDiv.parentElement) {
12051
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = this.chargy.GetLocalizedMessage("Expected signature") + " (rs, hex)";
12011
12052
  }
12012
12053
  SignatureExpectedDiv.innerHTML = "der: " + (measurementValue.ocmfDocument.signature.SD.match(/.{1,8}/g)?.join(" ") ?? "-") + "<br /><br />r:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.signatureRS?.r?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "-") + "<br />s:&nbsp;&nbsp; " + (measurementValue.ocmfDocument.signatureRS?.s?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "-");
12013
12054
  }
@@ -12030,6 +12071,7 @@ var OCMFv1_x = class extends ACrypt {
12030
12071
  break;
12031
12072
  }
12032
12073
  }
12074
+ return void 0;
12033
12075
  }
12034
12076
  };
12035
12077
  var OCMFTransactionTypes = /* @__PURE__ */ ((OCMFTransactionTypes2) => {
@@ -12062,268 +12104,270 @@ var OCMF = class {
12062
12104
  const evseId = asString(containerInfos["EVSEId"]) ?? asString(evseInfo?.["@id"]) ?? "DE*GEF*EVSE*CHARGY*1";
12063
12105
  const stationDescription = asJSONObject(chargingStationInfo?.["description"]);
12064
12106
  const evseDescription = asJSONObject(evseInfo?.["description"]);
12065
- const firstOCMDJSONDocument = OCMFJSONDocuments[0];
12066
- if (firstOCMDJSONDocument != void 0) {
12067
- const formatVersion = firstOCMDJSONDocument.payload.FV;
12068
- const gatewayInformation = firstOCMDJSONDocument.payload.GI ?? firstOCMDJSONDocument.payload.VI;
12069
- const gatewaySerial = firstOCMDJSONDocument.payload.GS;
12070
- const gatewayVersion = firstOCMDJSONDocument.payload.GV ?? firstOCMDJSONDocument.payload.VV;
12071
- const paging = firstOCMDJSONDocument.payload.PG;
12072
- const meterVendor = firstOCMDJSONDocument.payload.MV;
12073
- const meterModel = firstOCMDJSONDocument.payload.MM;
12074
- const meterSerial = firstOCMDJSONDocument.payload.MS;
12075
- const effectiveMeterSerial = meterSerial ?? gatewaySerial;
12076
- const meterFirmware = firstOCMDJSONDocument.payload.MF;
12077
- const identificationStatus = firstOCMDJSONDocument.payload.IS;
12078
- const identificationLevel = firstOCMDJSONDocument.payload.IL;
12079
- const identificationFlags = firstOCMDJSONDocument.payload.IF;
12080
- const identificationType = firstOCMDJSONDocument.payload.IT;
12081
- const identificationData = firstOCMDJSONDocument.payload.ID;
12082
- const tariffText = firstOCMDJSONDocument.payload.TT;
12083
- const controlerFirmwareVersion = firstOCMDJSONDocument.payload.CF;
12084
- const lossCompensation = firstOCMDJSONDocument.payload.LC;
12085
- const chargePointIdType = firstOCMDJSONDocument.payload.CT;
12086
- const chargePointId = firstOCMDJSONDocument.payload.CI;
12087
- if (isOptionalString(formatVersion) && isOptionalString(gatewayInformation) && isOptionalString(gatewaySerial) && isOptionalString(gatewayVersion) && isMandatoryString(paging) && isOptionalString(meterVendor) && isOptionalString(meterModel) && // OCMF 1.0 table 3 lists MS as 1..1, but the later "Relation of Serial Numbers,
12088
- // Charge Point and Public Key" section makes the serial-number fields conditionally
12089
- // mandatory. KEBA KCP30 records identify the signing gateway via GS and omit MS.
12090
- // Therefore we keep meterSerial and gatewaySerial separate, but require at least one
12091
- // usable serial number for the CTR meter identity.
12092
- isMandatoryString(effectiveMeterSerial) && isOptionalString(meterFirmware) && // OCMF 1.x uses boolean IS values. OCMF 0.1 SAFE reference data used status strings
12093
- // such as "VERIFIED", so accept both forms and preserve the original value in the CTR.
12094
- (isMandatoryBoolean(identificationStatus) || isMandatoryString(identificationStatus)) && isOptionalString(identificationLevel) && //chargyLib.isMandatoryArrayOfStrings (identificationFlags) &&
12095
- isOptionalArrayOfStrings(identificationFlags) && // Note: Some vendors do not use this MANDATORY field!
12096
- // IT is 1..1 in the user-assignment table for transaction records. Some OCMF 1.0
12097
- // implementations omit it when no user is assigned (IS=false, ID empty). We tolerate
12098
- // this vendor compatibility case instead of rejecting otherwise valid signatures.
12099
- isOptionalString(identificationType) && isOptionalString(identificationData) && isOptionalString(tariffText) && isOptionalString(controlerFirmwareVersion) && isOptionalJSONObject(lossCompensation) && isOptionalString(chargePointIdType) && isOptionalString(chargePointId)) {
12100
- const paginationPrefix = paging.length > 0 ? paging[0]?.toLowerCase() : null;
12101
- const transactionType = paginationPrefix === "t" ? "transaction" /* transaction */ : paginationPrefix === "f" ? "fiscal" /* fiscal */ : "undefined" /* undefined */;
12102
- const pagination = paging.length > 1 ? parseNumber(paging.substring(1)) : null;
12103
- if (transactionType === "undefined" /* undefined */) return {
12104
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12105
- message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid transaction type!"),
12106
- certainty: 0
12107
- };
12108
- if (!isMandatoryNumber(pagination)) return {
12109
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12110
- message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid pagination counter!"),
12111
- certainty: 0
12112
- };
12113
- if (firstOCMDJSONDocument.payload.RD.length == 0) return {
12114
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12115
- message: this.chargy.GetMultilanguageText("Each OCMF data set must have at least one meter reading!"),
12116
- certainty: 0
12117
- };
12118
- const CTR = {
12119
- "@id": "?",
12120
- "@context": "https://open.charging.cloud/contexts/CTR+json",
12121
- //"@context": [ "https://open.charging.cloud/contexts/CTR+json", "https://open.charging.cloud/contexts/CTR_OCMF+json" ],
12107
+ const firstOCMDJSONDocument = getFirstArrayElement(OCMFJSONDocuments, "Missing first OCMF JSON document");
12108
+ const formatVersion = firstOCMDJSONDocument.payload.FV;
12109
+ const gatewayInformation = firstOCMDJSONDocument.payload.GI ?? firstOCMDJSONDocument.payload.VI;
12110
+ const gatewaySerial = firstOCMDJSONDocument.payload.GS;
12111
+ const gatewayVersion = firstOCMDJSONDocument.payload.GV ?? firstOCMDJSONDocument.payload.VV;
12112
+ const paging = firstOCMDJSONDocument.payload.PG;
12113
+ const meterVendor = firstOCMDJSONDocument.payload.MV;
12114
+ const meterModel = firstOCMDJSONDocument.payload.MM;
12115
+ const meterSerial = firstOCMDJSONDocument.payload.MS;
12116
+ const effectiveMeterSerial = meterSerial ?? gatewaySerial;
12117
+ const meterFirmware = firstOCMDJSONDocument.payload.MF;
12118
+ const identificationStatus = firstOCMDJSONDocument.payload.IS;
12119
+ const identificationLevel = firstOCMDJSONDocument.payload.IL;
12120
+ const identificationFlags = firstOCMDJSONDocument.payload.IF;
12121
+ const identificationType = firstOCMDJSONDocument.payload.IT;
12122
+ const identificationData = firstOCMDJSONDocument.payload.ID;
12123
+ const tariffText = firstOCMDJSONDocument.payload.TT;
12124
+ const controlerFirmwareVersion = firstOCMDJSONDocument.payload.CF;
12125
+ const lossCompensation = firstOCMDJSONDocument.payload.LC;
12126
+ const chargePointIdType = firstOCMDJSONDocument.payload.CT;
12127
+ const chargePointId = firstOCMDJSONDocument.payload.CI;
12128
+ if (isOptionalString(formatVersion) && isOptionalString(gatewayInformation) && isOptionalString(gatewaySerial) && isOptionalString(gatewayVersion) && isMandatoryString(paging) && isOptionalString(meterVendor) && isOptionalString(meterModel) && // OCMF 1.0 table 3 lists MS as 1..1, but the later "Relation of Serial Numbers,
12129
+ // Charge Point and Public Key" section makes the serial-number fields conditionally
12130
+ // mandatory. KEBA KCP30 records identify the signing gateway via GS and omit MS.
12131
+ // Therefore we keep meterSerial and gatewaySerial separate, but require at least one
12132
+ // usable serial number for the CTR meter identity.
12133
+ isMandatoryString(effectiveMeterSerial) && isOptionalString(meterFirmware) && // OCMF 1.x uses boolean IS values. OCMF 0.1 SAFE reference data used status strings
12134
+ // such as "VERIFIED", so accept both forms and preserve the original value in the CTR.
12135
+ (isMandatoryBoolean(identificationStatus) || isMandatoryString(identificationStatus)) && isOptionalString(identificationLevel) && //chargyLib.isMandatoryArrayOfStrings (identificationFlags) &&
12136
+ isOptionalArrayOfStrings(identificationFlags) && // Note: Some vendors do not use this MANDATORY field!
12137
+ // IT is 1..1 in the user-assignment table for transaction records. Some OCMF 1.0
12138
+ // implementations omit it when no user is assigned (IS=false, ID empty). We tolerate
12139
+ // this vendor compatibility case instead of rejecting otherwise valid signatures.
12140
+ isOptionalString(identificationType) && isOptionalString(identificationData) && isOptionalString(tariffText) && isOptionalString(controlerFirmwareVersion) && isOptionalJSONObject(lossCompensation) && isOptionalString(chargePointIdType) && isOptionalString(chargePointId)) {
12141
+ const paginationPrefix = paging.length > 0 ? paging.charAt(0).toLowerCase() : null;
12142
+ const transactionType = paginationPrefix === "t" ? "transaction" /* transaction */ : paginationPrefix === "f" ? "fiscal" /* fiscal */ : "undefined" /* undefined */;
12143
+ const pagination = paging.length > 1 ? parseNumber(paging.substring(1)) : null;
12144
+ if (transactionType === "undefined" /* undefined */) return {
12145
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12146
+ message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid transaction type!"),
12147
+ certainty: 0
12148
+ };
12149
+ if (!isMandatoryNumber(pagination)) return {
12150
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12151
+ message: this.chargy.GetMultilanguageText("The given OCMF data does not have a valid pagination counter!"),
12152
+ certainty: 0
12153
+ };
12154
+ if (firstOCMDJSONDocument.payload.RD.length == 0) return {
12155
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12156
+ message: this.chargy.GetMultilanguageText("Each OCMF data set must have at least one meter reading!"),
12157
+ certainty: 0
12158
+ };
12159
+ const CTR = {
12160
+ "@id": "?",
12161
+ "@context": "https://open.charging.cloud/contexts/CTR+json",
12162
+ //"@context": [ "https://open.charging.cloud/contexts/CTR+json", "https://open.charging.cloud/contexts/CTR_OCMF+json" ],
12163
+ "begin": "?",
12164
+ "end": "?",
12165
+ "description": {
12166
+ "de": "Alle OCMF-Ladevorg\xE4nge"
12167
+ },
12168
+ "contract": {
12169
+ "@id": identificationData ?? "?",
12170
+ "type": identificationType ?? "?"
12171
+ },
12172
+ "ocmf": {
12173
+ "formatVersion": formatVersion,
12174
+ "gatewayInformation": gatewayInformation,
12175
+ "gatewaySerial": gatewaySerial,
12176
+ "gatewayVersion": gatewayVersion
12177
+ },
12178
+ // "chargingStationOperators": [{
12179
+ "chargingPools": [{
12180
+ "@id": "DE*GEF*POOL*CHARGY*1",
12181
+ "description": { "en": "GraphDefined CHARGY Virtual Charging Pool 1" },
12182
+ "chargingStations": [{
12183
+ "@id": chargingStationId,
12184
+ "description": stationDescription && Object.keys(stationDescription).length > 0 ? stationDescription : { "en": "GraphDefined CHARGY Virtual Charging Station 1" },
12185
+ "firmwareVersion": asString(chargingStationInfo?.["softwareVersion"]) ?? asString(chargingStationInfo?.["firmwareVersion"]),
12186
+ "geoLocation": asJSONObject(chargingStationInfo?.["geoLocation"]),
12187
+ "address": asJSONObject(chargingStationInfo?.["address"]),
12188
+ "EVSEs": [{
12189
+ "@id": evseId,
12190
+ "description": evseDescription && Object.keys(evseDescription).length > 0 ? evseDescription : { "en": "GraphDefined CHARGY Virtual EVSE 1" },
12191
+ "connectors": connectorInfo ? [{
12192
+ "type": asString(connectorInfo["type"]) ?? "",
12193
+ "looses": asNumber(connectorInfo["looses"]) ?? 0
12194
+ }] : void 0,
12195
+ "meters": [{
12196
+ "@id": effectiveMeterSerial,
12197
+ // The signed OCMF payload values always win,
12198
+ // the container infos only fill the gaps!
12199
+ "manufacturer": meterVendor ?? asString(energyMeterInfo?.["manufacturer"]),
12200
+ "manufacturerURL": asString(energyMeterInfo?.["manufacturerURL"]),
12201
+ "model": meterModel ?? asString(energyMeterInfo?.["model"]),
12202
+ "modelURL": asString(energyMeterInfo?.["modelURL"]),
12203
+ "hardwareVersion": asString(energyMeterInfo?.["hardwareVersion"]),
12204
+ "firmwareVersion": meterFirmware ?? asString(energyMeterInfo?.["firmwareVersion"]),
12205
+ "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
12206
+ "publicKeys": [{
12207
+ "algorithm": "?",
12208
+ "encoding": "?",
12209
+ "format": "?",
12210
+ "value": "?"
12211
+ }]
12212
+ }]
12213
+ }]
12214
+ }]
12215
+ }],
12216
+ "chargingSessions": [{
12217
+ "@id": "1554181214441:-1965658344385548683:2",
12218
+ "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json",
12122
12219
  "begin": "?",
12123
12220
  "end": "?",
12124
- "description": {
12125
- "de": "Alle OCMF-Ladevorg\xE4nge"
12126
- },
12127
- "contract": {
12221
+ "EVSEId": evseId,
12222
+ "authorizationStart": {
12128
12223
  "@id": identificationData ?? "?",
12129
- "type": identificationType ?? "?"
12130
- },
12131
- "ocmf": {
12132
- "formatVersion": formatVersion,
12133
- "gatewayInformation": gatewayInformation,
12134
- "gatewaySerial": gatewaySerial,
12135
- "gatewayVersion": gatewayVersion
12224
+ "type": identificationType ?? "?",
12225
+ "identificationStatus": identificationStatus,
12226
+ "identificationLevel": identificationLevel,
12227
+ "identificationFlags": identificationFlags ?? []
12228
+ // Note: The OCMF documentation expects an empty array!
12136
12229
  },
12137
- // "chargingStationOperators": [{
12138
- "chargingPools": [{
12139
- "@id": "DE*GEF*POOL*CHARGY*1",
12140
- "description": { "en": "GraphDefined CHARGY Virtual Charging Pool 1" },
12141
- "chargingStations": [{
12142
- "@id": chargingStationId,
12143
- "description": stationDescription && Object.keys(stationDescription).length > 0 ? stationDescription : { "en": "GraphDefined CHARGY Virtual Charging Station 1" },
12144
- "firmwareVersion": asString(chargingStationInfo?.["softwareVersion"]) ?? asString(chargingStationInfo?.["firmwareVersion"]),
12145
- "geoLocation": asJSONObject(chargingStationInfo?.["geoLocation"]),
12146
- "address": asJSONObject(chargingStationInfo?.["address"]),
12147
- "EVSEs": [{
12148
- "@id": evseId,
12149
- "description": evseDescription && Object.keys(evseDescription).length > 0 ? evseDescription : { "en": "GraphDefined CHARGY Virtual EVSE 1" },
12150
- "connectors": connectorInfo ? [{
12151
- "type": asString(connectorInfo["type"]) ?? "",
12152
- "looses": asNumber(connectorInfo["looses"]) ?? 0
12153
- }] : void 0,
12154
- "meters": [{
12155
- "@id": effectiveMeterSerial,
12156
- // The signed OCMF payload values always win,
12157
- // the container infos only fill the gaps!
12158
- "manufacturer": meterVendor ?? asString(energyMeterInfo?.["manufacturer"]),
12159
- "manufacturerURL": asString(energyMeterInfo?.["manufacturerURL"]),
12160
- "model": meterModel ?? asString(energyMeterInfo?.["model"]),
12161
- "modelURL": asString(energyMeterInfo?.["modelURL"]),
12162
- "hardwareVersion": asString(energyMeterInfo?.["hardwareVersion"]),
12163
- "firmwareVersion": meterFirmware ?? asString(energyMeterInfo?.["firmwareVersion"]),
12164
- "signatureFormat": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
12165
- "publicKeys": [{
12166
- "algorithm": "?",
12167
- "encoding": "?",
12168
- "format": "?",
12169
- "value": "?"
12170
- }]
12171
- }]
12172
- }]
12173
- }]
12174
- }],
12175
- "chargingSessions": [{
12176
- "@id": "1554181214441:-1965658344385548683:2",
12177
- "@context": "https://open.charging.cloud/contexts/SessionSignatureFormats/OCMFv1.0+json",
12178
- "begin": "?",
12179
- "end": "?",
12180
- "EVSEId": evseId,
12181
- "authorizationStart": {
12182
- "@id": identificationData ?? "?",
12183
- "type": identificationType ?? "?",
12184
- "identificationStatus": identificationStatus,
12185
- "identificationLevel": identificationLevel,
12186
- "identificationFlags": identificationFlags ?? []
12187
- // Note: The OCMF documentation expects an empty array!
12188
- },
12189
- "measurements": []
12190
- }],
12191
- "certainty": 1
12192
- };
12193
- const measurementsByKey = /* @__PURE__ */ new Map();
12194
- for (const ocmfJSONDocument of OCMFJSONDocuments) {
12195
- let inheritedReading = {};
12196
- for (const reading of ocmfJSONDocument.payload.RD) {
12197
- const effectiveReading = { ...inheritedReading, ...reading };
12198
- const time = effectiveReading.TM;
12199
- const transaction = effectiveReading.TX;
12200
- const readingValue = effectiveReading.RV;
12201
- const readingIdentification = effectiveReading.RI;
12202
- const readingUnit = effectiveReading.RU;
12203
- const readingCurrentType = effectiveReading.RT;
12204
- const cumulatedLoss = effectiveReading.CL;
12205
- const errorFlags = effectiveReading.EF;
12206
- const status = effectiveReading.ST;
12207
- inheritedReading = effectiveReading;
12208
- if (isMandatoryString(time) && isOptionalString(transaction) && isMandatoryDecimal(readingValue) && // Note: Some vendors use a JSON string here!
12209
- isOptionalString(readingIdentification) && isMandatoryString(readingUnit) && isOptionalString(readingCurrentType) && isOptionalDecimal(cumulatedLoss) && isOptionalString(errorFlags) && isMandatoryString(status)) {
12210
- const timeSplit = time.split(" ");
12211
- if (timeSplit.length != 2) return {
12212
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12213
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time format!"),
12214
- certainty: 0
12215
- };
12216
- const timeRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{3}[+-]\d{4}$/;
12217
- const timeStamp = timeSplit[0];
12218
- if (!isMandatoryString(timeStamp) || !timeRegEx.test(timeStamp)) return {
12219
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12220
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
12221
- certainty: 0
12222
- };
12223
- const timeStampISO8601 = this.convertToISO8601(timeStamp);
12224
- const timeSyncText = timeSplit[1];
12225
- let timeSync = "unknown" /* unknown */;
12226
- if (!isMandatoryString(timeSyncText) || !["U", "I", "S", "R"].includes(timeSyncText)) return {
12227
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12228
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
12229
- certainty: 0
12230
- };
12231
- switch (timeSyncText) {
12232
- case "U":
12233
- timeSync = "unknown" /* unknown */;
12234
- break;
12235
- case "I":
12236
- timeSync = "informative" /* informative */;
12237
- break;
12238
- case "S":
12239
- timeSync = "syncronized" /* syncronized */;
12240
- break;
12241
- case "R":
12242
- timeSync = "relative" /* relative */;
12243
- break;
12244
- default:
12245
- return {
12246
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12247
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
12248
- certainty: 0
12249
- };
12250
- }
12251
- if (transaction && !["B", "C", "X", "E", "L", "R", "A", "P", "S", "T"].includes(transaction)) return {
12252
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12253
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid transaction type!"),
12254
- certainty: 0
12255
- };
12256
- if (!["kWh", "Wh", "mOhm", "uOhm"].includes(readingUnit)) return {
12257
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12258
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
12259
- certainty: 0
12260
- };
12261
- if (readingCurrentType && !["AC", "DC"].includes(readingCurrentType)) return {
12262
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12263
- message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
12264
- certainty: 0
12265
- };
12266
- if (CTR.chargingSessions?.[0]?.begin === "?")
12267
- CTR.chargingSessions[0].begin = timeStampISO8601;
12268
- CTR.chargingSessions[0].end = timeStampISO8601;
12269
- const measurementKey = [
12270
- readingIdentification ?? "?",
12271
- readingUnit,
12272
- readingCurrentType ?? ""
12273
- ].join("|");
12274
- let measurement = measurementsByKey.get(measurementKey);
12275
- if (measurement == null) {
12276
- measurement = {
12277
- "name": OBIS2MeasurementName(readingIdentification ?? ""),
12278
- "scale": 0,
12279
- "energyMeterId": effectiveMeterSerial,
12280
- "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
12281
- "obis": readingIdentification ?? "?",
12282
- // OBIS: "1-b:1.8.0"
12283
- "unit": readingUnit,
12284
- // "kWh"
12285
- "currentType": readingCurrentType,
12286
- // "AC"
12287
- "values": []
12230
+ "measurements": []
12231
+ }],
12232
+ "certainty": 1
12233
+ };
12234
+ const measurementsByKey = /* @__PURE__ */ new Map();
12235
+ for (const ocmfJSONDocument of OCMFJSONDocuments) {
12236
+ let inheritedReading = {};
12237
+ for (const reading of ocmfJSONDocument.payload.RD) {
12238
+ const effectiveReading = { ...inheritedReading, ...reading };
12239
+ const time = effectiveReading.TM;
12240
+ const transaction = effectiveReading.TX;
12241
+ const readingValue = effectiveReading.RV;
12242
+ const readingIdentification = effectiveReading.RI;
12243
+ const readingUnit = effectiveReading.RU;
12244
+ const readingCurrentType = effectiveReading.RT;
12245
+ const cumulatedLoss = effectiveReading.CL;
12246
+ const errorFlags = effectiveReading.EF;
12247
+ const status = effectiveReading.ST;
12248
+ inheritedReading = effectiveReading;
12249
+ if (isMandatoryString(time) && isOptionalString(transaction) && isMandatoryDecimal(readingValue) && // Note: Some vendors use a JSON string here!
12250
+ isOptionalString(readingIdentification) && isMandatoryString(readingUnit) && isOptionalString(readingCurrentType) && // chargyLib.isOptionalDecimal (cumulatedLoss) &&
12251
+ isOptionalString(errorFlags) && isMandatoryString(status)) {
12252
+ const timeSplit = time.split(" ");
12253
+ if (timeSplit.length != 2) return {
12254
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12255
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time format!"),
12256
+ certainty: 0
12257
+ };
12258
+ const timeRegEx = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2},\d{3}[+-]\d{4}$/;
12259
+ const timeStamp = timeSplit[0];
12260
+ if (!isMandatoryString(timeStamp) || !timeRegEx.test(timeStamp)) return {
12261
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12262
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
12263
+ certainty: 0
12264
+ };
12265
+ const timeStampISO8601 = this.convertToISO8601(timeStamp);
12266
+ const timeSyncText = timeSplit[1];
12267
+ let timeSync = "unknown" /* unknown */;
12268
+ if (!isMandatoryString(timeSyncText) || !["U", "I", "S", "R"].includes(timeSyncText)) return {
12269
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12270
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
12271
+ certainty: 0
12272
+ };
12273
+ switch (timeSyncText) {
12274
+ case "U":
12275
+ timeSync = "unknown" /* unknown */;
12276
+ break;
12277
+ case "I":
12278
+ timeSync = "informative" /* informative */;
12279
+ break;
12280
+ case "S":
12281
+ timeSync = "syncronized" /* syncronized */;
12282
+ break;
12283
+ case "R":
12284
+ timeSync = "relative" /* relative */;
12285
+ break;
12286
+ default:
12287
+ return {
12288
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12289
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid time sync format!"),
12290
+ certainty: 0
12288
12291
  };
12289
- measurementsByKey.set(measurementKey, measurement);
12290
- CTR.chargingSessions[0].measurements.push(measurement);
12291
- }
12292
- measurement.values.push({
12293
- "timestamp": timeStampISO8601,
12294
- // "2019-06-26T08:57:44,337+0000"
12295
- "timeSync": timeSync,
12296
- // "U"|"I"|"S"|"R"
12297
- "transaction": transaction,
12298
- // "B"|"C"|"X"|"E"|"L"|"R"|"A"|"P"|"S"|"T"|null
12299
- "value": new Decimal(readingValue),
12300
- // 2935.6
12301
- "transactionType": transactionType,
12302
- // "T" ToDo: Serialize this to a string!
12303
- "pagination": pagination,
12304
- // "9289"
12305
- "errorFlags": errorFlags,
12306
- // ""
12307
- "cumulatedLoss": cumulatedLoss ? new Decimal(cumulatedLoss) : void 0,
12308
- "status": status,
12309
- // "G"
12310
- // "signatures": [{
12311
- // "value": ocmfJSONDocument.signature["SD"]
12312
- // }],
12313
- "result": {
12314
- "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
12315
- },
12316
- "ocmfDocument": ocmfJSONDocument
12317
- });
12318
12292
  }
12293
+ if (transaction != null && transaction.length > 0 && !["B", "C", "X", "E", "L", "R", "A", "P", "S", "T"].includes(transaction)) return {
12294
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12295
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid transaction type!"),
12296
+ certainty: 0
12297
+ };
12298
+ if (!["kWh", "Wh", "mOhm", "uOhm"].includes(readingUnit)) return {
12299
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12300
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
12301
+ certainty: 0
12302
+ };
12303
+ if (readingCurrentType != null && readingCurrentType.length > 0 && !["AC", "DC"].includes(readingCurrentType)) return {
12304
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
12305
+ message: this.chargy.GetMultilanguageText("The given OCMF meter value does not have a valid current type!"),
12306
+ certainty: 0
12307
+ };
12308
+ if (CTR.chargingSessions?.[0]?.begin === "?")
12309
+ CTR.chargingSessions[0].begin = timeStampISO8601;
12310
+ if (CTR.chargingSessions?.[0] !== void 0)
12311
+ CTR.chargingSessions[0].end = timeStampISO8601;
12312
+ const measurementKey = [
12313
+ readingIdentification ?? "?",
12314
+ readingUnit,
12315
+ readingCurrentType ?? ""
12316
+ ].join("|");
12317
+ let measurement = measurementsByKey.get(measurementKey);
12318
+ if (measurement == null) {
12319
+ measurement = {
12320
+ "name": OBIS2MeasurementName(readingIdentification ?? ""),
12321
+ "scale": 0,
12322
+ "energyMeterId": effectiveMeterSerial,
12323
+ "@context": "https://open.charging.cloud/contexts/EnergyMeterSignatureFormats/OCMFv1.0+json",
12324
+ "obis": readingIdentification ?? "?",
12325
+ // OBIS: "1-b:1.8.0"
12326
+ "unit": readingUnit,
12327
+ // "kWh"
12328
+ "currentType": readingCurrentType,
12329
+ // "AC"
12330
+ "values": []
12331
+ };
12332
+ measurementsByKey.set(measurementKey, measurement);
12333
+ const firstChargingSession = CTR.chargingSessions?.[0];
12334
+ if (firstChargingSession !== void 0)
12335
+ firstChargingSession.measurements.push(measurement);
12336
+ }
12337
+ measurement.values.push({
12338
+ "timestamp": timeStampISO8601,
12339
+ // "2019-06-26T08:57:44,337+0000"
12340
+ "timeSync": timeSync,
12341
+ // "U"|"I"|"S"|"R"
12342
+ "transaction": transaction,
12343
+ // "B"|"C"|"X"|"E"|"L"|"R"|"A"|"P"|"S"|"T"|null
12344
+ "value": new Decimal(readingValue),
12345
+ // 2935.6
12346
+ "transactionType": transactionType,
12347
+ // "T" ToDo: Serialize this to a string!
12348
+ "pagination": pagination,
12349
+ // "9289"
12350
+ "errorFlags": errorFlags,
12351
+ // ""
12352
+ "cumulatedLoss": cumulatedLoss != null && cumulatedLoss !== 0 ? new Decimal(cumulatedLoss) : void 0,
12353
+ "status": status,
12354
+ // "G"
12355
+ // "signatures": [{
12356
+ // "value": ocmfJSONDocument.signature["SD"]
12357
+ // }],
12358
+ "result": {
12359
+ "status": ocmfJSONDocument.validationStatus ?? "Unvalidated" /* Unvalidated */
12360
+ },
12361
+ "ocmfDocument": ocmfJSONDocument
12362
+ });
12319
12363
  }
12320
12364
  }
12321
- CTR.status = OCMFJSONDocuments.every((ocmfJSONDocument) => ocmfJSONDocument.validationStatus === "ValidSignature" /* ValidSignature */) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
12322
- if (CTR.chargingSessions != null && CTR.chargingSessions.length > 0 && CTR.chargingSessions[0] != null) {
12323
- CTR.begin = CTR.chargingSessions[0].begin;
12324
- CTR.end = CTR.chargingSessions[0].end;
12325
- return CTR;
12326
- }
12365
+ }
12366
+ CTR.status = OCMFJSONDocuments.every((ocmfJSONDocument) => ocmfJSONDocument.validationStatus === "ValidSignature" /* ValidSignature */) ? "ValidSignature" /* ValidSignature */ : "InvalidSignature" /* InvalidSignature */;
12367
+ if (CTR.chargingSessions != null && CTR.chargingSessions.length > 0 && CTR.chargingSessions[0]) {
12368
+ CTR.begin = CTR.chargingSessions[0].begin;
12369
+ CTR.end = CTR.chargingSessions[0].end;
12370
+ return CTR;
12327
12371
  }
12328
12372
  }
12329
12373
  } catch (exception) {
@@ -12340,113 +12384,121 @@ var OCMF = class {
12340
12384
  }
12341
12385
  //#endregion
12342
12386
  //#region (private) mergeOCMFSessions(CTRs)
12343
- mergeOCMFSessions(CTRs) {
12344
- const mergedCTR = {
12345
- "@id": "",
12346
- "@context": "",
12347
- certainty: 1
12348
- };
12349
- for (const ctr of CTRs) {
12350
- if (mergedCTR["@id"] === "")
12351
- mergedCTR["@id"] = ctr["@id"];
12352
- if (mergedCTR["@context"] === "")
12353
- mergedCTR["@context"] = ctr["@context"];
12354
- if (!mergedCTR.begin || mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin)
12355
- mergedCTR.begin = ctr.begin;
12356
- if (!mergedCTR.end || mergedCTR.end && ctr.end && mergedCTR.end < ctr.end)
12357
- mergedCTR.end = ctr.end;
12358
- if (!mergedCTR.description)
12359
- mergedCTR.description = ctr.description;
12360
- if (!mergedCTR.contract)
12361
- mergedCTR.contract = ctr.contract;
12362
- if (!mergedCTR.chargingStationOperators)
12363
- mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
12364
- else if (ctr.chargingStationOperators)
12365
- for (const chargingStationOperator of ctr.chargingStationOperators)
12366
- mergedCTR.chargingStationOperators.push(chargingStationOperator);
12367
- if (!mergedCTR.chargingPools)
12368
- mergedCTR.chargingPools = ctr.chargingPools;
12369
- else if (ctr.chargingPools)
12370
- for (const chargingPool of ctr.chargingPools)
12371
- mergedCTR.chargingPools.push(chargingPool);
12372
- if (!mergedCTR.chargingStations)
12373
- mergedCTR.chargingStations = ctr.chargingStations;
12374
- else if (ctr.chargingStations)
12375
- for (const chargingStation of ctr.chargingStations)
12376
- mergedCTR.chargingStations.push(chargingStation);
12377
- if (!mergedCTR.chargingSessions)
12378
- mergedCTR.chargingSessions = ctr.chargingSessions;
12379
- else if (ctr.chargingSessions)
12380
- for (const chargingSession of ctr.chargingSessions)
12381
- mergedCTR.chargingSessions.push(chargingSession);
12382
- if (!mergedCTR.eMobilityProviders)
12383
- mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
12384
- else if (ctr.eMobilityProviders)
12385
- for (const eMobilityProvider of ctr.eMobilityProviders)
12386
- mergedCTR.eMobilityProviders.push(eMobilityProvider);
12387
- if (!mergedCTR.mediationServices)
12388
- mergedCTR.mediationServices = ctr.mediationServices;
12389
- else if (ctr.mediationServices)
12390
- for (const mediationService of ctr.mediationServices)
12391
- mergedCTR.mediationServices.push(mediationService);
12392
- }
12393
- return mergedCTR;
12394
- }
12387
+ // private mergeOCMFSessions(CTRs: Array<IOCMFChargeTransparencyRecord>): IOCMFChargeTransparencyRecord
12388
+ // {
12389
+ // const mergedCTR:IOCMFChargeTransparencyRecord = {
12390
+ // "@id": "",
12391
+ // "@context": "",
12392
+ // certainty: 1
12393
+ // };
12394
+ // for (const ctr of CTRs)
12395
+ // {
12396
+ // if (mergedCTR["@id"] === "")
12397
+ // mergedCTR["@id"] = ctr["@id"];
12398
+ // if (mergedCTR["@context"] === "")
12399
+ // mergedCTR["@context"] = ctr["@context"];
12400
+ // if (!mergedCTR.begin || (mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin))
12401
+ // mergedCTR.begin = ctr.begin;
12402
+ // if (!mergedCTR.end || (mergedCTR.end && ctr.end && mergedCTR.end < ctr.end))
12403
+ // mergedCTR.end = ctr.end;
12404
+ // if (!mergedCTR.description)
12405
+ // mergedCTR.description = ctr.description;
12406
+ // //ToDo: Is this a really good idea? Or should we fail, whenever this information is different?
12407
+ // if (!mergedCTR.contract)
12408
+ // mergedCTR.contract = ctr.contract;
12409
+ // if (!mergedCTR.chargingStationOperators)
12410
+ // mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
12411
+ // else if (ctr.chargingStationOperators)
12412
+ // for (const chargingStationOperator of ctr.chargingStationOperators)
12413
+ // mergedCTR.chargingStationOperators.push(chargingStationOperator);
12414
+ // if (!mergedCTR.chargingPools)
12415
+ // mergedCTR.chargingPools = ctr.chargingPools;
12416
+ // else if (ctr.chargingPools)
12417
+ // for (const chargingPool of ctr.chargingPools)
12418
+ // mergedCTR.chargingPools.push(chargingPool);
12419
+ // if (!mergedCTR.chargingStations)
12420
+ // mergedCTR.chargingStations = ctr.chargingStations;
12421
+ // else if (ctr.chargingStations)
12422
+ // for (const chargingStation of ctr.chargingStations)
12423
+ // mergedCTR.chargingStations.push(chargingStation);
12424
+ // // publicKeys
12425
+ // if (!mergedCTR.chargingSessions)
12426
+ // mergedCTR.chargingSessions = ctr.chargingSessions;
12427
+ // else if (ctr.chargingSessions)
12428
+ // for (const chargingSession of ctr.chargingSessions)
12429
+ // mergedCTR.chargingSessions.push(chargingSession);
12430
+ // if (!mergedCTR.eMobilityProviders)
12431
+ // mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
12432
+ // else if (ctr.eMobilityProviders)
12433
+ // for (const eMobilityProvider of ctr.eMobilityProviders)
12434
+ // mergedCTR.eMobilityProviders.push(eMobilityProvider);
12435
+ // if (!mergedCTR.mediationServices)
12436
+ // mergedCTR.mediationServices = ctr.mediationServices;
12437
+ // else if (ctr.mediationServices)
12438
+ // for (const mediationService of ctr.mediationServices)
12439
+ // mergedCTR.mediationServices.push(mediationService);
12440
+ // }
12441
+ // return mergedCTR;
12442
+ // }
12395
12443
  //#endregion
12396
12444
  //#region (private) mergeChargeTransparencyRecords(CTRs)
12397
- mergeChargeTransparencyRecords(CTRs) {
12398
- const mergedCTR = {
12399
- "@id": "",
12400
- "@context": "",
12401
- certainty: 1
12402
- };
12403
- for (const ctr of CTRs) {
12404
- if (mergedCTR["@id"] === "")
12405
- mergedCTR["@id"] = ctr["@id"];
12406
- if (mergedCTR["@context"] === "")
12407
- mergedCTR["@context"] = ctr["@context"];
12408
- if (!mergedCTR.begin || mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin)
12409
- mergedCTR.begin = ctr.begin;
12410
- if (!mergedCTR.end || mergedCTR.end && ctr.end && mergedCTR.end < ctr.end)
12411
- mergedCTR.end = ctr.end;
12412
- if (!mergedCTR.description)
12413
- mergedCTR.description = ctr.description;
12414
- if (!mergedCTR.contract)
12415
- mergedCTR.contract = ctr.contract;
12416
- if (!mergedCTR.chargingStationOperators)
12417
- mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
12418
- else if (ctr.chargingStationOperators)
12419
- for (const chargingStationOperator of ctr.chargingStationOperators)
12420
- mergedCTR.chargingStationOperators.push(chargingStationOperator);
12421
- if (!mergedCTR.chargingPools)
12422
- mergedCTR.chargingPools = ctr.chargingPools;
12423
- else if (ctr.chargingPools)
12424
- for (const chargingPool of ctr.chargingPools)
12425
- mergedCTR.chargingPools.push(chargingPool);
12426
- if (!mergedCTR.chargingStations)
12427
- mergedCTR.chargingStations = ctr.chargingStations;
12428
- else if (ctr.chargingStations)
12429
- for (const chargingStation of ctr.chargingStations)
12430
- mergedCTR.chargingStations.push(chargingStation);
12431
- if (!mergedCTR.chargingSessions)
12432
- mergedCTR.chargingSessions = ctr.chargingSessions;
12433
- else if (ctr.chargingSessions)
12434
- for (const chargingSession of ctr.chargingSessions)
12435
- mergedCTR.chargingSessions.push(chargingSession);
12436
- if (!mergedCTR.eMobilityProviders)
12437
- mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
12438
- else if (ctr.eMobilityProviders)
12439
- for (const eMobilityProvider of ctr.eMobilityProviders)
12440
- mergedCTR.eMobilityProviders.push(eMobilityProvider);
12441
- if (!mergedCTR.mediationServices)
12442
- mergedCTR.mediationServices = ctr.mediationServices;
12443
- else if (ctr.mediationServices)
12444
- for (const mediationService of ctr.mediationServices)
12445
- mergedCTR.mediationServices.push(mediationService);
12446
- }
12447
- return mergedCTR;
12448
- }
12449
- //#endregion
12445
+ // private mergeChargeTransparencyRecords(CTRs: Array<IOCMFChargeTransparencyRecord>): IOCMFChargeTransparencyRecord
12446
+ // {
12447
+ // const mergedCTR:IOCMFChargeTransparencyRecord = {
12448
+ // "@id": "",
12449
+ // "@context": "",
12450
+ // certainty: 1
12451
+ // };
12452
+ // for (const ctr of CTRs)
12453
+ // {
12454
+ // if (mergedCTR["@id"] === "")
12455
+ // mergedCTR["@id"] = ctr["@id"];
12456
+ // if (mergedCTR["@context"] === "")
12457
+ // mergedCTR["@context"] = ctr["@context"];
12458
+ // if (!mergedCTR.begin || (mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin))
12459
+ // mergedCTR.begin = ctr.begin;
12460
+ // if (!mergedCTR.end || (mergedCTR.end && ctr.end && mergedCTR.end < ctr.end))
12461
+ // mergedCTR.end = ctr.end;
12462
+ // if (!mergedCTR.description)
12463
+ // mergedCTR.description = ctr.description;
12464
+ // //ToDo: Is this a really good idea? Or should we fail, whenever this information is different?
12465
+ // if (!mergedCTR.contract)
12466
+ // mergedCTR.contract = ctr.contract;
12467
+ // if (!mergedCTR.chargingStationOperators)
12468
+ // mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
12469
+ // else if (ctr.chargingStationOperators)
12470
+ // for (const chargingStationOperator of ctr.chargingStationOperators)
12471
+ // mergedCTR.chargingStationOperators.push(chargingStationOperator);
12472
+ // if (!mergedCTR.chargingPools)
12473
+ // mergedCTR.chargingPools = ctr.chargingPools;
12474
+ // else if (ctr.chargingPools)
12475
+ // for (const chargingPool of ctr.chargingPools)
12476
+ // mergedCTR.chargingPools.push(chargingPool);
12477
+ // if (!mergedCTR.chargingStations)
12478
+ // mergedCTR.chargingStations = ctr.chargingStations;
12479
+ // else if (ctr.chargingStations)
12480
+ // for (const chargingStation of ctr.chargingStations)
12481
+ // mergedCTR.chargingStations.push(chargingStation);
12482
+ // // publicKeys
12483
+ // if (!mergedCTR.chargingSessions)
12484
+ // mergedCTR.chargingSessions = ctr.chargingSessions;
12485
+ // else if (ctr.chargingSessions)
12486
+ // for (const chargingSession of ctr.chargingSessions)
12487
+ // mergedCTR.chargingSessions.push(chargingSession);
12488
+ // if (!mergedCTR.eMobilityProviders)
12489
+ // mergedCTR.eMobilityProviders = ctr.eMobilityProviders;
12490
+ // else if (ctr.eMobilityProviders)
12491
+ // for (const eMobilityProvider of ctr.eMobilityProviders)
12492
+ // mergedCTR.eMobilityProviders.push(eMobilityProvider);
12493
+ // if (!mergedCTR.mediationServices)
12494
+ // mergedCTR.mediationServices = ctr.mediationServices;
12495
+ // else if (ctr.mediationServices)
12496
+ // for (const mediationService of ctr.mediationServices)
12497
+ // mergedCTR.mediationServices.push(mediationService);
12498
+ // }
12499
+ // return mergedCTR;
12500
+ // }
12501
+ // //#endregion
12450
12502
  //#region (private) validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding?)
12451
12503
  async validateOCMFSignature(OCMFJSONDocument, PublicKey, PublicKeyEncoding) {
12452
12504
  try {
@@ -12505,7 +12557,7 @@ var OCMF = class {
12505
12557
  this.key("pubKey").bitstr()
12506
12558
  );
12507
12559
  });
12508
- if (PublicKeyEncoding) {
12560
+ if (PublicKeyEncoding != null && PublicKeyEncoding.length > 0) {
12509
12561
  switch (PublicKeyEncoding.toLowerCase()) {
12510
12562
  case "hex":
12511
12563
  publicKeyBytes = Buffer.from(OCMFJSONDocument.publicKey, "hex");
@@ -12533,11 +12585,12 @@ var OCMF = class {
12533
12585
  publicKeyBytes = Buffer.from(OCMFJSONDocument.publicKey, "base64");
12534
12586
  }
12535
12587
  }
12536
- if (!publicKeyBytes) {
12588
+ if (publicKeyBytes == null) {
12537
12589
  OCMFJSONDocument.validationStatus = "UnknownPublicKeyFormat" /* UnknownPublicKeyFormat */;
12538
12590
  return OCMFJSONDocument.validationStatus;
12539
12591
  }
12540
- const publicKeyASN1 = ECPoint.decode(publicKeyBytes, "der");
12592
+ const decodedPublicKeyASN1 = ECPoint.decode(publicKeyBytes, "der");
12593
+ const publicKeyASN1 = decodedPublicKeyASN1;
12541
12594
  const coordinates = publicKeyASN1.pubKey.data.subarray(1);
12542
12595
  const halfLength = coordinates.length / 2;
12543
12596
  const publicKeyXY = {
@@ -12546,7 +12599,7 @@ var OCMF = class {
12546
12599
  };
12547
12600
  publicKey = curve.keyFromPublic(publicKeyXY, "hex");
12548
12601
  OCMFJSONDocument.publicKey = {
12549
- algorithm: OCMFJSONDocument.signature.SA ? OCMFJSONDocument.signature.SA.substring(
12602
+ algorithm: OCMFJSONDocument.signature.SA != null && OCMFJSONDocument.signature.SA.length > 0 ? OCMFJSONDocument.signature.SA.substring(
12550
12603
  OCMFJSONDocument.signature.SA.indexOf("-") + 1,
12551
12604
  OCMFJSONDocument.signature.SA.lastIndexOf("-")
12552
12605
  ) : "secp256r1",
@@ -12697,7 +12750,7 @@ var OCMF = class {
12697
12750
  hashValue,
12698
12751
  publicKey: PublicKey,
12699
12752
  publicKeyEncoding: PublicKeyEncoding,
12700
- validationStatus: validationStatus ? validationStatus : PublicKey ? "Unvalidated" /* Unvalidated */ : "PublicKeyNotFound" /* PublicKeyNotFound */
12753
+ validationStatus: validationStatus ?? (PublicKey != null ? "Unvalidated" /* Unvalidated */ : "PublicKeyNotFound" /* PublicKeyNotFound */)
12701
12754
  };
12702
12755
  try {
12703
12756
  const ECDSASignature = this.chargy.asn1.define("ECDSASignature", function() {
@@ -12719,7 +12772,8 @@ var OCMF = class {
12719
12772
  default:
12720
12773
  ocmfJSONDocument.validationStatus = "UnknownSignatureFormat" /* UnknownSignatureFormat */;
12721
12774
  }
12722
- const signatureObj = ECDSASignature.decode(Buffer.from(ocmfJSONDocument.signature.SD, bufferEncoding), "der");
12775
+ const decodedSignatureObj = ECDSASignature.decode(Buffer.from(ocmfJSONDocument.signature.SD, bufferEncoding), "der");
12776
+ const signatureObj = decodedSignatureObj;
12723
12777
  ocmfJSONDocument.signatureRS = {
12724
12778
  value: ocmfJSONDocument.signature.SD,
12725
12779
  r: signatureObj.r.toString(16),
@@ -12728,7 +12782,7 @@ var OCMF = class {
12728
12782
  } catch {
12729
12783
  ocmfJSONDocument.validationStatus = "InvalidSignature" /* InvalidSignature */;
12730
12784
  }
12731
- if (PublicKey && ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
12785
+ if (PublicKey != null && ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
12732
12786
  await this.validateOCMFSignature(
12733
12787
  ocmfJSONDocument,
12734
12788
  PublicKey,
@@ -12757,7 +12811,7 @@ var OCMF = class {
12757
12811
  //#endregion
12758
12812
  //#region TryToParseOCMFDocument (OCMFDocument, PublicKey?, PublicKeyEncoding?, ContainerInfos?)
12759
12813
  async TryToParseOCMFDocument(OCMFDocument, PublicKey, PublicKeyEncoding, ContainerInfos) {
12760
- return await this.TryToParseOCMFDocuments([OCMFDocument], PublicKey, PublicKeyEncoding, ContainerInfos);
12814
+ return this.TryToParseOCMFDocuments([OCMFDocument], PublicKey, PublicKeyEncoding, ContainerInfos);
12761
12815
  }
12762
12816
  //#endregion
12763
12817
  //#region TryToParseOCMFDocuments(OCMFDocuments, PublicKey?, PublicKeyEncoding?, ContainerInfos?)
@@ -12777,7 +12831,8 @@ var OCMF = class {
12777
12831
  if (typeof ocmfJSONDocuments !== "string") {
12778
12832
  for (const ocmfJSONDocument of ocmfJSONDocuments) {
12779
12833
  try {
12780
- const groupingKey = (ocmfJSONDocument.payload.FV ?? "") + "|" + (ocmfJSONDocument.payload.GI ?? "") + "|" + (ocmfJSONDocument.payload.GS ?? "") + "|" + (ocmfJSONDocument.payload.GV ?? "") + "|" + (ocmfJSONDocument.payload.MV ?? "") + "|" + (ocmfJSONDocument.payload.MM ?? "") + "|" + (ocmfJSONDocument.payload.MS ?? "") + "|" + (ocmfJSONDocument.payload.MF ?? "") + "|" + (ocmfJSONDocument.payload.IS ? "1|" : "0|") + (ocmfJSONDocument.payload.IL ?? "") + "|" + (ocmfJSONDocument.payload.IF ?? "") + "|" + (ocmfJSONDocument.payload.IT ?? "") + "|" + (ocmfJSONDocument.payload.ID ?? "") + "|" + (ocmfJSONDocument.payload.TT ?? "") + "|" + (ocmfJSONDocument.payload.CF ?? "") + "|" + (ocmfJSONDocument.payload.CT ?? "") + "|" + (ocmfJSONDocument.payload.CI ?? "");
12834
+ const groupingKey = (ocmfJSONDocument.payload.FV ?? "") + "|" + (ocmfJSONDocument.payload.GI ?? "") + "|" + (ocmfJSONDocument.payload.GS ?? "") + "|" + (ocmfJSONDocument.payload.GV ?? "") + "|" + (ocmfJSONDocument.payload.MV ?? "") + "|" + (ocmfJSONDocument.payload.MM ?? "") + "|" + (ocmfJSONDocument.payload.MS ?? "") + "|" + (ocmfJSONDocument.payload.MF ?? "") + "|" + (ocmfJSONDocument.payload.IS === true ? "1|" : "0|") + (ocmfJSONDocument.payload.IL ?? "") + "|" + //(ocmfJSONDocument.payload.IF ?? "") + "|" +
12835
+ (ocmfJSONDocument.payload.IT ?? "") + "|" + (ocmfJSONDocument.payload.ID ?? "") + "|" + (ocmfJSONDocument.payload.TT ?? "") + "|" + (ocmfJSONDocument.payload.CF ?? "") + "|" + (ocmfJSONDocument.payload.CT ?? "") + "|" + (ocmfJSONDocument.payload.CI ?? "");
12781
12836
  if (!ocmfJSONDocumentGroups.has(groupingKey))
12782
12837
  ocmfJSONDocumentGroups.set(groupingKey, new Array());
12783
12838
  ocmfJSONDocumentGroups.get(groupingKey)?.push(ocmfJSONDocument);
@@ -12790,7 +12845,7 @@ var OCMF = class {
12790
12845
  }
12791
12846
  }
12792
12847
  for (const ocmfJSONDocumentGroup of ocmfJSONDocumentGroups.values()) {
12793
- if (PublicKey) {
12848
+ if (PublicKey != null) {
12794
12849
  for (const ocmfJSONDocument of ocmfJSONDocumentGroup)
12795
12850
  if (ocmfJSONDocument.validationStatus === "Unvalidated" /* Unvalidated */)
12796
12851
  await this.validateOCMFSignature(ocmfJSONDocument, PublicKey);
@@ -12842,12 +12897,6 @@ var OCPI = class {
12842
12897
  constructor(chargy) {
12843
12898
  this.chargy = chargy;
12844
12899
  }
12845
- bufferToHex(buffer, Reverse) {
12846
- return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
12847
- }
12848
- bufferToNumber(buffer) {
12849
- return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
12850
- }
12851
12900
  //#region tryToParseChargeITContainerFormat(SomeJSON)
12852
12901
  // The chargeIT mobility data format does not always provide context information or format identifiers!
12853
12902
  async tryToParseOCPIFormat(SomeJSON) {
@@ -12881,7 +12930,7 @@ var OCPI = class {
12881
12930
  };
12882
12931
  if (encoding_method === "OCMF" && isMandatoryJSONArray(signed_values) && signed_values.length > 0) {
12883
12932
  const firstSignedData = asString(asJSONObject(signed_values[0])?.["signed_data"]);
12884
- if (firstSignedData) {
12933
+ if (firstSignedData != null && firstSignedData.length > 0) {
12885
12934
  const placeInfo = asJSONObject(SomeJSON["placeInfo"]);
12886
12935
  const geoLocation = asJSONObject(placeInfo?.["geoLocation"]);
12887
12936
  const address = asJSONObject(placeInfo?.["address"]);
@@ -12900,7 +12949,7 @@ var OCPI = class {
12900
12949
  },
12901
12950
  energyMeter: asJSONObject(SomeJSON["meterInfo"])
12902
12951
  };
12903
- return await new OCMF(this.chargy).TryToParseOCMFDocument(
12952
+ return new OCMF(this.chargy).TryToParseOCMFDocument(
12904
12953
  firstSignedData,
12905
12954
  asString(public_key),
12906
12955
  encoding_method,
@@ -13218,9 +13267,9 @@ var OCPI = class {
13218
13267
  ],
13219
13268
  certainty: 0
13220
13269
  };
13221
- if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json"))
13270
+ if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json") === true)
13222
13271
  return new BSMCrypt01(this.chargy).tryToParseBSM_WS36aMeasurements(CTR, evseIdStr, asString(chargingStation_controllerSoftwareVersion) ?? null, signedMeterValues);
13223
- if (smvContext?.startsWith("ALFEN"))
13272
+ if (smvContext?.startsWith("ALFEN") === true)
13224
13273
  return new Alfen(this.chargy).TryToParseALFENFormat(
13225
13274
  signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
13226
13275
  {
@@ -13367,9 +13416,9 @@ function parsePCDFDocument(input) {
13367
13416
  }
13368
13417
  const fields = {};
13369
13418
  for (let i = 0; i < PCDF_FIELD_ORDER.length; i++) {
13370
- const value = match[i + 1];
13371
- const field = PCDF_FIELD_ORDER[i];
13372
- if (field == null || value == null)
13419
+ const value = getArrayElement(match, i + 1, "Missing PCDF field value");
13420
+ const field = getArrayElement(PCDF_FIELD_ORDER, i, "Missing PCDF field name");
13421
+ if (value.length === 0)
13373
13422
  throw new PCDFParseError("MISSING_FIELDS", "Missing fields in the data tuple", field);
13374
13423
  fields[field] = value;
13375
13424
  }
@@ -13741,8 +13790,10 @@ function parsePCDFReadingValue(value, errors) {
13741
13790
  errors.push("Session information is invalid");
13742
13791
  return void 0;
13743
13792
  }
13793
+ const integralPart = getArrayElement(match, 1, "Missing PCDF reading integral part");
13794
+ const fractionalPart = getArrayElement(match, 2, "Missing PCDF reading fractional part");
13744
13795
  return {
13745
- value: new Decimal(String(match[1]) + "." + String(match[2])),
13796
+ value: new Decimal(integralPart + "." + fractionalPart),
13746
13797
  unit: "kWh"
13747
13798
  };
13748
13799
  }
@@ -13777,9 +13828,9 @@ function hexToBytes2(hex, errorMessage) {
13777
13828
  }
13778
13829
  function readDERLength(bytes, getOffset, setOffset) {
13779
13830
  let offset = getOffset();
13780
- const b = bytes[offset++];
13781
- if (b == null)
13831
+ if (offset >= bytes.length)
13782
13832
  throw new Error("Invalid signature");
13833
+ const b = getArrayElement(bytes, offset++, "Invalid signature");
13783
13834
  if ((b & 128) === 0) {
13784
13835
  setOffset(offset);
13785
13836
  return b;
@@ -13789,9 +13840,9 @@ function readDERLength(bytes, getOffset, setOffset) {
13789
13840
  throw new Error("Invalid signature");
13790
13841
  let length = 0;
13791
13842
  for (let i = 0; i < octets; i++) {
13792
- const value = bytes[offset++];
13793
- if (value == null)
13843
+ if (offset >= bytes.length)
13794
13844
  throw new Error("Invalid signature");
13845
+ const value = getArrayElement(bytes, offset++, "Invalid signature");
13795
13846
  length = (length << 8) + value;
13796
13847
  }
13797
13848
  setOffset(offset);
@@ -13820,30 +13871,33 @@ var SAFEXML = class _SAFEXML {
13820
13871
  this.chargy = chargy;
13821
13872
  }
13822
13873
  static ParseChargingStationContext(XMLDocument) {
13823
- const chargingStationElement = getElementsByLocalName(XMLDocument, "chargingStation")[0];
13824
- if (!chargingStationElement)
13874
+ const chargingStationElement = getElementsByLocalName(XMLDocument, "chargingStation").at(0);
13875
+ if (chargingStationElement === void 0)
13825
13876
  return {};
13826
- const chargingStationId = chargingStationElement.getAttribute("id")?.trim() || getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "id"));
13877
+ const chargingStationAttributeId = chargingStationElement.getAttribute("id")?.trim();
13878
+ const chargingStationId = chargingStationAttributeId != null && chargingStationAttributeId.length > 0 ? chargingStationAttributeId : getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "id"));
13827
13879
  const softwareVersion = getTrimmedTextContent(getDirectChildByLocalName(chargingStationElement, "softwareVersion"));
13828
13880
  const geoLocationElement = getDirectChildByLocalName(chargingStationElement, "geoLocation");
13829
13881
  const latitude = Number.parseFloat(getTrimmedTextContent(getDirectChildByLocalName(geoLocationElement ?? chargingStationElement, "latitude")) ?? "");
13830
13882
  const longitude = Number.parseFloat(getTrimmedTextContent(getDirectChildByLocalName(geoLocationElement ?? chargingStationElement, "longitude")) ?? "");
13831
13883
  const geoLocation = Number.isFinite(latitude) && Number.isFinite(longitude) ? { lat: latitude, lng: longitude } : void 0;
13832
- if (getDirectChildByLocalName(chargingStationElement, "EVSEs"))
13884
+ if (getDirectChildByLocalName(chargingStationElement, "EVSEs") !== void 0)
13833
13885
  throw new Error("The SAFE chargingStation XML element must contain EVSE directly and no EVSEs container element!");
13834
13886
  const evseElements = getDirectChildrenByLocalName(chargingStationElement, "EVSE");
13835
13887
  if (evseElements.length > 1)
13836
13888
  throw new Error("The SAFE chargingStation XML element must not contain more than one EVSE element!");
13837
- const evseElement = evseElements[0];
13838
- const evseId = evseElement?.getAttribute("id")?.trim() || getTrimmedTextContent(getDirectChildByLocalName(evseElement ?? chargingStationElement, "id")) || "";
13839
- const connectorElements = evseElement ? getDirectChildrenByLocalName(evseElement, "connector") : [];
13889
+ const evseElement = evseElements.at(0);
13890
+ const evseAttributeId = evseElement?.getAttribute("id")?.trim();
13891
+ const evseTextId = getTrimmedTextContent(getDirectChildByLocalName(evseElement ?? chargingStationElement, "id"));
13892
+ const evseId = evseAttributeId != null && evseAttributeId.length > 0 ? evseAttributeId : evseTextId ?? "";
13893
+ const connectorElements = evseElement !== void 0 ? getDirectChildrenByLocalName(evseElement, "connector") : [];
13840
13894
  if (connectorElements.length > 1)
13841
13895
  throw new Error("The SAFE EVSE XML element must not contain more than one connector element!");
13842
- const connectorElement = connectorElements[0];
13896
+ const connectorElement = connectorElements.at(0);
13843
13897
  const connectorId = connectorElement?.getAttribute("id")?.trim();
13844
13898
  const connectorType = getTrimmedTextContent(getDirectChildByLocalName(connectorElement ?? evseElement ?? chargingStationElement, "type"));
13845
- const connector = connectorType ? { "@id": connectorId, type: connectorType, looses: 0 } : void 0;
13846
- const parsedEVSE = evseElement ? {
13899
+ const connector = connectorType != null && connectorType.length > 0 ? { "@id": connectorId, type: connectorType, looses: 0 } : void 0;
13900
+ const parsedEVSE = evseElement !== void 0 ? {
13847
13901
  "@id": evseId,
13848
13902
  "description": parseDescription(evseElement),
13849
13903
  "meters": [],
@@ -14008,8 +14062,8 @@ var XMLContainer = class {
14008
14062
  if (values.length == 1) {
14009
14063
  const valueList = values[0]?.querySelectorAll("signedMeterValue");
14010
14064
  if (valueList != null && valueList.length >= 1) {
14011
- for (let i = 0; i < valueList.length; i++) {
14012
- const publicKey = valueList[i]?.querySelector("publicKey");
14065
+ for (const valueElement of valueList) {
14066
+ const publicKey = valueElement.querySelector("publicKey");
14013
14067
  if (publicKey != null) {
14014
14068
  const publicKeyEncoding = publicKey.attributes.getNamedItem("encoding")?.value.trim().toLowerCase() ?? "";
14015
14069
  let publicKeyValue = publicKey.textContent.trim();
@@ -14049,7 +14103,7 @@ var XMLContainer = class {
14049
14103
  certainty: 0
14050
14104
  };
14051
14105
  }
14052
- const meterValueSignature = valueList[i]?.querySelector("meterValueSignature");
14106
+ const meterValueSignature = valueElement.querySelector("meterValueSignature");
14053
14107
  if (meterValueSignature != null) {
14054
14108
  const meterValueSignatureEncoding = meterValueSignature.attributes.getNamedItem("encoding")?.value.trim().toLowerCase() ?? "";
14055
14109
  let meterValueSignatureValue = meterValueSignature.textContent.trim();
@@ -14082,7 +14136,7 @@ var XMLContainer = class {
14082
14136
  };
14083
14137
  common.meterValueSignatures.push(meterValueSignatureValue);
14084
14138
  }
14085
- const signatureMethod = valueList[i]?.querySelector("signatureMethod")?.textContent.trim().toLowerCase() ?? "";
14139
+ const signatureMethod = valueElement.querySelector("signatureMethod")?.textContent.trim().toLowerCase() ?? "";
14086
14140
  if (common.signatureMethod == "")
14087
14141
  common.signatureMethod = signatureMethod;
14088
14142
  else if (common.signatureMethod != signatureMethod)
@@ -14091,7 +14145,7 @@ var XMLContainer = class {
14091
14145
  message: this.chargy.GetMultilanguageText("Invalid mixture of different signature methods within the given XML container!"),
14092
14146
  certainty: 0
14093
14147
  };
14094
- const encodingMethod = valueList[i]?.querySelector("encodingMethod")?.textContent.trim().toLowerCase() ?? "";
14148
+ const encodingMethod = valueElement.querySelector("encodingMethod")?.textContent.trim().toLowerCase() ?? "";
14095
14149
  if (common.encodingMethod == "")
14096
14150
  common.encodingMethod = encodingMethod;
14097
14151
  else if (common.encodingMethod != encodingMethod)
@@ -14100,7 +14154,7 @@ var XMLContainer = class {
14100
14154
  message: this.chargy.GetMultilanguageText("Invalid mixture of different signed data formats within the given XML container!"),
14101
14155
  certainty: 0
14102
14156
  };
14103
- const encodedMeterValue = valueList[i]?.querySelector("encodedMeterValue");
14157
+ const encodedMeterValue = valueElement.querySelector("encodedMeterValue");
14104
14158
  if (encodedMeterValue != null) {
14105
14159
  const signedDataEncoding = encodedMeterValue.attributes.getNamedItem("encoding")?.value.trim() ?? "";
14106
14160
  let signedDataValue = encodedMeterValue.textContent.trim();
@@ -14161,12 +14215,6 @@ var ChargeIT = class {
14161
14215
  constructor(chargy) {
14162
14216
  this.chargy = chargy;
14163
14217
  }
14164
- bufferToHex(buffer, Reverse) {
14165
- return (Reverse ? Array.from(new Uint8Array(buffer)).reverse() : Array.from(new Uint8Array(buffer))).map((b) => b.toString(16).padStart(2, "0")).join("");
14166
- }
14167
- bufferToNumber(buffer) {
14168
- return parseInt(Array.from(new Uint8Array(buffer)).map((b) => b.toString(16).padStart(2, "0")).join(""), 16);
14169
- }
14170
14218
  //#region TryToParseOldChargeITMeterValuesFormat(CTR, evseId, address, geoLocation, signedMeterValues)
14171
14219
  TryToParseOldChargeITMeterValuesFormat(CTR, evseId, address, geoLocation, signedMeterValues) {
14172
14220
  const CTRArray = new Array();
@@ -14266,14 +14314,8 @@ var ChargeIT = class {
14266
14314
  });
14267
14315
  }
14268
14316
  }
14269
- const firstMeterValue = CTRArray[0];
14270
- const lastMeterValue = CTRArray[CTRArray.length - 1];
14271
- if (firstMeterValue === void 0 || lastMeterValue === void 0)
14272
- return {
14273
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
14274
- message: this.chargy.GetMultilanguageText("UnknownOrInvalidChargingSessionFormat"),
14275
- certainty: 0
14276
- };
14317
+ const firstMeterValue = getFirstArrayElement(CTRArray, "Missing first chargeIT meter value");
14318
+ const lastMeterValue = getLastArrayElement(CTRArray, "Missing last chargeIT meter value");
14277
14319
  CTR["@id"] = lastMeterValue["transactionId"];
14278
14320
  CTR.begin = this.chargy.moment.unix(firstMeterValue["measuredValue"]["timestampLocal"]["timestamp"]).utc().format();
14279
14321
  CTR.end = this.chargy.moment.unix(lastMeterValue["measuredValue"]["timestampLocal"]["timestamp"]).utc().format();
@@ -14503,7 +14545,6 @@ var ChargeIT = class {
14503
14545
  if (consistent) {
14504
14546
  if (signedMeterValueContext === "https://www.lichtblick.de/contexts/bsm-ws36a-json-v0" || signedMeterValueContext === "https://www.lichtblick.de/contexts/bsm-ws36a-json-v1" || signedMeterValueContext === "https://www.eneco.com/contexts/bsm-ws36a-json-v0" || signedMeterValueContext === "https://www.eneco.com/contexts/bsm-ws36a-json-v1" || signedMeterValueContext === "https://www.chargeit-mobility.com/contexts/bsm-ws36a-json-v0" || signedMeterValueContext === "https://www.chargeit-mobility.com/contexts/bsm-ws36a-json-v1") {
14505
14547
  } else if (signedMeterValueContext.startsWith("ALFEN")) {
14506
- } else if (containerFormat === oldChargeITContainerFormat) {
14507
14548
  } else if (signedMeterValueContext === oldChargeITMeterValueFormat) {
14508
14549
  let measurementCounter = 0;
14509
14550
  for (const signedMeterValue of signedMeterValues) {
@@ -14619,10 +14660,10 @@ var ChargeIT = class {
14619
14660
  }
14620
14661
  }
14621
14662
  const chargePoint = signedMeterValue["chargePoint"];
14622
- if (!isMandatoryJSONObject(chargePoint)) {
14663
+ if (chargePoint !== void 0 && !isMandatoryJSONObject(chargePoint)) {
14623
14664
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_ChargePointInformationP", measurementCounter)));
14624
14665
  secondaryErrors += 1;
14625
- } else {
14666
+ } else if (isMandatoryJSONObject(chargePoint)) {
14626
14667
  if (!isMandatoryString(chargePoint["softwareVersion"]))
14627
14668
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_ChargePointInformation_SoftwareVersionP", measurementCounter)));
14628
14669
  }
@@ -14770,19 +14811,17 @@ var ChargeIT = class {
14770
14811
  }
14771
14812
  );
14772
14813
  }
14773
- if (containerFormat === oldChargeITContainerFormat) {
14774
- if (asJSONObject(signedMeterValues[0])?.["format"] == "ALFEN")
14775
- return new Alfen(this.chargy).TryToParseALFENFormat(
14776
- signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
14777
- {
14778
- EVSEId: evseId,
14779
- chargingStation: {
14780
- geoLocation: { "lat": geoLocation_lat, "lng": geoLocation_lon },
14781
- address: { "street": address_street, "postalCode": address_zipCode, "city": address_town, "country": address_country }
14782
- }
14814
+ if (asJSONObject(signedMeterValues[0])?.["format"] == "ALFEN")
14815
+ return new Alfen(this.chargy).TryToParseALFENFormat(
14816
+ signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
14817
+ {
14818
+ EVSEId: evseId,
14819
+ chargingStation: {
14820
+ geoLocation: { "lat": geoLocation_lat, "lng": geoLocation_lon },
14821
+ address: { "street": address_street, "postalCode": address_zipCode, "city": address_town, "country": address_country }
14783
14822
  }
14784
- );
14785
- }
14823
+ }
14824
+ );
14786
14825
  if (signedMeterValueContext === oldChargeITMeterValueFormat)
14787
14826
  return this.TryToParseOldChargeITMeterValuesFormat(
14788
14827
  CTR,
@@ -14972,8 +15011,6 @@ var ChargeIT = class {
14972
15011
  errors.push(CreateError(this.chargy.GetMultilanguageTextWithParameter("MissingOrInvalid_SignedMeterValue_MeterInfo_MeterIdP", 1)));
14973
15012
  }
14974
15013
  if (isMandatoryJSONArray(chargingTariffs)) {
14975
- for (let i = 0; i < chargingTariffs.length; i++) {
14976
- }
14977
15014
  }
14978
15015
  if (totalCosts) {
14979
15016
  if (!isMandatoryNumber(totalCosts_total))
@@ -15126,9 +15163,9 @@ var ChargeIT = class {
15126
15163
  ],
15127
15164
  certainty: 0
15128
15165
  };
15129
- if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json"))
15166
+ if (smvContext?.startsWith("https://www.chargeit-mobility.com/contexts/bsm-ws36a-json") === true)
15130
15167
  return new BSMCrypt01(this.chargy).tryToParseBSM_WS36aMeasurements(CTR, evseIdStr, asString(chargingStation_controllerSoftwareVersion) ?? null, signedMeterValues);
15131
- if (smvContext?.startsWith("ALFEN"))
15168
+ if (smvContext?.startsWith("ALFEN") === true)
15132
15169
  return new Alfen(this.chargy).TryToParseALFENFormat(
15133
15170
  signedMeterValues.map((value) => asString(asJSONObject(value)?.["payload"]) ?? ""),
15134
15171
  {
@@ -15231,10 +15268,8 @@ var ChargePoint = class {
15231
15268
  if (startTimeUTC !== void 0 && (parkingEnd === void 0 || startTimeUTC > parkingEnd))
15232
15269
  parkingEnd = endTimeUTC;
15233
15270
  }
15234
- if (chargingStart === void 0)
15235
- chargingStart = parkingStart;
15236
- if (chargingEnd === void 0)
15237
- chargingEnd = parkingEnd;
15271
+ chargingStart ??= parkingStart;
15272
+ chargingEnd ??= parkingEnd;
15238
15273
  let sessionStart = parkingStart !== void 0 && (chargingStart === void 0 || parkingStart < chargingStart) ? parkingStart : chargingStart;
15239
15274
  if (sessionStart === void 0 && parkingStart !== void 0)
15240
15275
  sessionStart = parkingStart;
@@ -15383,7 +15418,7 @@ var ChargePoint = class {
15383
15418
  "status": "Unvalidated" /* Unvalidated */
15384
15419
  };
15385
15420
  if (parking && parking.length > 0 && CTR.chargingSessions && CTR.chargingSessions.length > 0) {
15386
- const chargingSession = CTR.chargingSessions[0];
15421
+ const chargingSession = getFirstArrayElement(CTR.chargingSessions, "Missing ChargePoint charging session");
15387
15422
  chargingSession.parking = [];
15388
15423
  for (const parkingItem of parking) {
15389
15424
  const parkingObj = asJSONObject(parkingItem);
@@ -15679,6 +15714,8 @@ var ChargePointCrypt01 = class extends ACrypt {
15679
15714
  case "InvalidSignature" /* InvalidSignature */:
15680
15715
  currentResult.status = "InvalidStartValue" /* InvalidStartValue */;
15681
15716
  break;
15717
+ default:
15718
+ break;
15682
15719
  }
15683
15720
  } else if (i == measurement.values.length - 1) {
15684
15721
  switch (currentResult.status) {
@@ -15691,6 +15728,8 @@ var ChargePointCrypt01 = class extends ACrypt {
15691
15728
  case "InvalidSignature" /* InvalidSignature */:
15692
15729
  currentResult.status = "InvalidStopValue" /* InvalidStopValue */;
15693
15730
  break;
15731
+ default:
15732
+ break;
15694
15733
  }
15695
15734
  } else {
15696
15735
  switch (currentResult.status) {
@@ -15703,6 +15742,8 @@ var ChargePointCrypt01 = class extends ACrypt {
15703
15742
  case "InvalidSignature" /* InvalidSignature */:
15704
15743
  currentResult.status = "InvalidStopValue" /* InvalidStopValue */;
15705
15744
  break;
15745
+ default:
15746
+ break;
15706
15747
  }
15707
15748
  }
15708
15749
  }
@@ -15732,9 +15773,9 @@ var ChargePointCrypt01 = class extends ACrypt {
15732
15773
  const cryptoResult = {
15733
15774
  status: "NoOperation" /* NoOperation */
15734
15775
  };
15735
- return await Promise.resolve(setResult("NoOperation" /* NoOperation */));
15776
+ return Promise.resolve(setResult("NoOperation" /* NoOperation */));
15736
15777
  }
15737
- async ViewMeasurement(measurementValue, errorDiv, introDiv, infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
15778
+ async ViewMeasurement(measurementValue, _errorDiv, introDiv, _infoDiv, PlainTextDiv, HashedPlainTextDiv, PublicKeyDiv, SignatureExpectedDiv, SignatureCheckDiv) {
15738
15779
  if (measurementValue.measurement?.chargingSession === void 0)
15739
15780
  return new Error("Invalid measurement!");
15740
15781
  const chargingSession = measurementValue.measurement.chargingSession;
@@ -15742,8 +15783,8 @@ var ChargePointCrypt01 = class extends ACrypt {
15742
15783
  const algorithmName = typeof chargingSession.publicKey?.algorithm === "object" ? chargingSession.publicKey.algorithm.name : chargingSession.publicKey?.algorithm ?? "";
15743
15784
  const algorithmType = typeof chargingSession.publicKey?.type === "object" ? chargingSession.publicKey.type.name : chargingSession.publicKey?.type;
15744
15785
  introDiv.innerHTML = this.chargy.GetLocalizedMessage("The following data of the charging session is relevant for metrological and legal metrological purposes and therefore part of the digital signature").replace("{methodName}", "ChargePointCrypt01").replace("{cryptoAlgorithm}", algorithmName);
15745
- if (PlainTextDiv.parentElement != void 0 && PlainTextDiv.parentElement.children[0] != void 0) {
15746
- PlainTextDiv.parentElement.children[0].innerHTML = "Plain text (secrrct)";
15786
+ if (PlainTextDiv.parentElement) {
15787
+ getArrayLikeElement(PlainTextDiv.parentElement.children, 0, "Missing plain text header").innerHTML = "Plain text (secrrct)";
15747
15788
  }
15748
15789
  PlainTextDiv.innerText = atob(chargingSession.original ?? "");
15749
15790
  PlainTextDiv.style.fontFamily = "monospace";
@@ -15765,22 +15806,23 @@ var ChargePointCrypt01 = class extends ACrypt {
15765
15806
  hashInfo = "(SHA512, 512 Bits, hex)";
15766
15807
  break;
15767
15808
  }
15768
- if (HashedPlainTextDiv.parentElement != void 0 && HashedPlainTextDiv.parentElement.children[0] != void 0) {
15769
- HashedPlainTextDiv.parentElement.children[0].innerHTML = "Hashed plain text " + hashInfo;
15809
+ if (HashedPlainTextDiv.parentElement) {
15810
+ getArrayLikeElement(HashedPlainTextDiv.parentElement.children, 0, "Missing hashed plain text header").innerHTML = "Hashed plain text " + hashInfo;
15770
15811
  }
15771
15812
  HashedPlainTextDiv.innerHTML = chargingSession.hashValue?.match(/.{1,8}/g)?.join(" ") ?? "0x00000000000000000000000000000000000";
15772
15813
  if (chargingSession.publicKey != null) {
15773
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[0] != void 0) {
15774
- PublicKeyDiv.parentElement.children[0].innerHTML = "Public Key (" + (algorithmType ? algorithmType + ", " : "") + (algorithmName ? algorithmName + ", " : "") + "hex)";
15814
+ if (PublicKeyDiv.parentElement) {
15815
+ getArrayLikeElement(PublicKeyDiv.parentElement.children, 0, "Missing public key header").innerHTML = "Public Key (" + (algorithmType != null && algorithmType.length > 0 ? algorithmType + ", " : "") + (algorithmName.length > 0 ? algorithmName + ", " : "") + "hex)";
15775
15816
  }
15776
15817
  PublicKeyDiv.innerHTML = chargingSession.publicKey.value.startsWith("04") ? '<span class="leadingFour">04</span> ' + (chargingSession.publicKey.value.substring(2).match(/.{1,8}/g)?.join(" ") ?? "") : chargingSession.publicKey.value.match(/.{1,8}/g)?.join(" ") ?? "";
15777
- if (PublicKeyDiv.parentElement != void 0 && PublicKeyDiv.parentElement.children[3] != void 0) {
15778
- PublicKeyDiv.parentElement.children[3].innerHTML = "";
15818
+ const publicKeySignatureContainer = PublicKeyDiv.parentElement?.children[3];
15819
+ if (publicKeySignatureContainer !== void 0) {
15820
+ publicKeySignatureContainer.innerHTML = "";
15779
15821
  }
15780
15822
  if (result.publicKeySignatures) {
15781
15823
  for (const signature of result.publicKeySignatures) {
15782
15824
  try {
15783
- const signatureDiv = PublicKeyDiv.parentElement?.children[3]?.appendChild(document.createElement("div"));
15825
+ const signatureDiv = publicKeySignatureContainer?.appendChild(document.createElement("div"));
15784
15826
  if (signatureDiv != null)
15785
15827
  signatureDiv.innerHTML = await this.chargy.CheckMeterPublicKeySignature(
15786
15828
  measurementValue.measurement.chargingSession.chargingStation,
@@ -15795,8 +15837,8 @@ var ChargePointCrypt01 = class extends ACrypt {
15795
15837
  }
15796
15838
  }
15797
15839
  if (chargingSession.signature != null) {
15798
- if (SignatureExpectedDiv.parentElement != void 0 && SignatureExpectedDiv.parentElement.children[0] != void 0) {
15799
- SignatureExpectedDiv.parentElement.children[0].innerHTML = "Erwartete Signatur (secrrct.sign, rs, hex)";
15840
+ if (SignatureExpectedDiv.parentElement) {
15841
+ getArrayLikeElement(SignatureExpectedDiv.parentElement.children, 0, "Missing expected signature header").innerHTML = "Erwartete Signatur (secrrct.sign, rs, hex)";
15800
15842
  }
15801
15843
  if (typeof chargingSession.signature != "string")
15802
15844
  SignatureExpectedDiv.innerHTML = "r: " + (chargingSession.signature.r?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "") + "<br />s: " + (chargingSession.signature.s?.toLowerCase().padStart(56, "0").match(/.{1,8}/g)?.join(" ") ?? "");
@@ -15828,6 +15870,7 @@ var ChargePointCrypt01 = class extends ACrypt {
15828
15870
  break;
15829
15871
  }
15830
15872
  }
15873
+ return void 0;
15831
15874
  }
15832
15875
  };
15833
15876
 
@@ -15848,8 +15891,7 @@ function IsAChargeTransparencyRecord(data) {
15848
15891
  function IsASessionCryptoResult(data) {
15849
15892
  if (!isMandatoryJSONObject(data))
15850
15893
  return false;
15851
- const sessionCryptoResult = data;
15852
- return sessionCryptoResult.status !== void 0;
15894
+ return true;
15853
15895
  }
15854
15896
  function CloneCTR(CTR) {
15855
15897
  const clonedCTR = JSON.parse(JSON.stringify(CTR));
@@ -16025,8 +16067,10 @@ async function imageDataFromNodeCanvas(data) {
16025
16067
  if (!isCanvasModule(canvasLib))
16026
16068
  return void 0;
16027
16069
  const image = await canvasLib.loadImage(Buffer$1.from(toUint8Array(data)));
16028
- const width = image.naturalWidth || image.width;
16029
- const height = image.naturalHeight || image.height;
16070
+ const naturalWidth = image.naturalWidth ?? 0;
16071
+ const naturalHeight = image.naturalHeight ?? 0;
16072
+ const width = naturalWidth > 0 ? naturalWidth : image.width;
16073
+ const height = naturalHeight > 0 ? naturalHeight : image.height;
16030
16074
  if (width <= 0 || height <= 0)
16031
16075
  return void 0;
16032
16076
  const canvas = canvasLib.createCanvas(width, height);
@@ -16097,22 +16141,22 @@ async function importOptionalNodeModule(moduleName) {
16097
16141
  }
16098
16142
  async function readQRCodeTextFromImage(data, mimeType) {
16099
16143
  const imageDataSources = typeof document === "undefined" ? [
16100
- () => imageDataFromNodeCanvas(data),
16101
- () => imageDataFromPNGOrJPEG(data, mimeType),
16102
- () => imageDataFromBrowserCanvas(data, mimeType),
16103
- () => imageDataFromBrowserImageElement(data, mimeType)
16144
+ async () => imageDataFromNodeCanvas(data),
16145
+ async () => imageDataFromPNGOrJPEG(data, mimeType),
16146
+ async () => imageDataFromBrowserCanvas(data, mimeType),
16147
+ async () => imageDataFromBrowserImageElement(data, mimeType)
16104
16148
  ] : [
16105
- () => imageDataFromBrowserCanvas(data, mimeType),
16106
- () => imageDataFromBrowserImageElement(data, mimeType),
16107
- () => imageDataFromNodeCanvas(data),
16108
- () => imageDataFromPNGOrJPEG(data, mimeType)
16149
+ async () => imageDataFromBrowserCanvas(data, mimeType),
16150
+ async () => imageDataFromBrowserImageElement(data, mimeType),
16151
+ async () => imageDataFromNodeCanvas(data),
16152
+ async () => imageDataFromPNGOrJPEG(data, mimeType)
16109
16153
  ];
16110
16154
  for (const imageDataSource of imageDataSources) {
16111
16155
  const imageData = await imageDataSource();
16112
16156
  if (imageData == null)
16113
16157
  continue;
16114
16158
  const qrText = readQRCodeTextFromImageData(imageData);
16115
- if (qrText && qrText.length > 0)
16159
+ if (qrText != null && qrText.length > 0)
16116
16160
  return qrText;
16117
16161
  }
16118
16162
  return void 0;
@@ -16125,7 +16169,7 @@ function readQRCodeTextFromImageData(imageData) {
16125
16169
  { inversionAttempts: "attemptBoth" }
16126
16170
  );
16127
16171
  const qrText = qrCode?.data.trim();
16128
- return qrText && qrText.length > 0 ? qrText : void 0;
16172
+ return qrText != null && qrText.length > 0 ? qrText : void 0;
16129
16173
  }
16130
16174
 
16131
16175
  // src/pdfjs/node.ts
@@ -16146,6 +16190,11 @@ var validationRules_default = {
16146
16190
  }
16147
16191
  }
16148
16192
  };
16193
+ function isPdfAttachment(value) {
16194
+ if (!isMandatoryJSONObject(value))
16195
+ return false;
16196
+ return typeof value["filename"] === "string" && (value["content"] instanceof ArrayBuffer || ArrayBuffer.isView(value["content"]));
16197
+ }
16149
16198
  var Chargy = class {
16150
16199
  //#region Data
16151
16200
  i18n;
@@ -16162,8 +16211,6 @@ var Chargy = class {
16162
16211
  EVSEs = new Array();
16163
16212
  meters = new Array();
16164
16213
  chargingSessions = new Array();
16165
- eMobilityProviders = new Array();
16166
- mediationServices = new Array();
16167
16214
  currentCTR = {};
16168
16215
  internalCTR = {};
16169
16216
  //#endregion
@@ -16177,41 +16224,55 @@ var Chargy = class {
16177
16224
  this.showPKIDetails = ShowPKIDetails;
16178
16225
  this.validationRules = validationRules;
16179
16226
  }
16180
- SetUILanguages(UILanguages) {
16181
- this.uiLanguages = this.NormalizeUILanguages(UILanguages);
16227
+ fileNameWithoutExtension(fileName) {
16228
+ const lastSeparator = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
16229
+ const lastDot = fileName.lastIndexOf(".");
16230
+ if (lastDot > lastSeparator)
16231
+ return fileName.substring(0, lastDot);
16232
+ return fileName;
16182
16233
  }
16183
- NormalizeUILanguages(UILanguages) {
16184
- const languages = new Array();
16185
- for (const language of UILanguages) {
16186
- const normalized = language.trim();
16187
- if (normalized.length > 0 && !languages.includes(normalized)) {
16188
- languages.push(normalized);
16234
+ tryExtractChargeTransparencyTextFromURL(qrText) {
16235
+ if (!qrText.startsWith("http://") && !qrText.startsWith("https://"))
16236
+ return qrText;
16237
+ try {
16238
+ const url = new URL(qrText);
16239
+ const candidates = [
16240
+ url.hash.startsWith("#") ? url.hash.substring(1) : url.hash,
16241
+ url.searchParams.get("data"),
16242
+ url.searchParams.get("content"),
16243
+ url.searchParams.get("ctr"),
16244
+ url.searchParams.get("record"),
16245
+ url.searchParams.get("payload"),
16246
+ url.searchParams.get("q")
16247
+ ];
16248
+ for (const candidate of candidates) {
16249
+ const decodedCandidate = candidate != null ? decodeURIComponent(candidate).trim() : "";
16250
+ if (decodedCandidate.startsWith("<?xml") || decodedCandidate.startsWith("<values") || decodedCandidate.startsWith("{") || decodedCandidate.startsWith("[") || decodedCandidate.startsWith("OCMF") || decodedCandidate.startsWith("AP;")) {
16251
+ return decodedCandidate;
16252
+ }
16189
16253
  }
16254
+ } catch {
16255
+ console.log("Invalid URL in QR code: " + qrText);
16190
16256
  }
16191
- return languages.length > 0 ? languages : ["en"];
16257
+ return qrText;
16192
16258
  }
16193
- FindBestMultilanguageText(Text) {
16194
- for (const language of this.uiLanguages) {
16195
- const localLanguage = Text[language];
16196
- if (localLanguage !== void 0)
16197
- return localLanguage;
16259
+ tryExtractSignedDataTextFromXML(qrText) {
16260
+ const trimmedQRCodeText = qrText.trim();
16261
+ if (!trimmedQRCodeText.startsWith("<?xml") && !trimmedQRCodeText.startsWith("<"))
16262
+ return qrText;
16263
+ try {
16264
+ const xmlDocument = new DOMParser().parseFromString(trimmedQRCodeText, "text/xml");
16265
+ const signedDataValues = getElementsByLocalName(xmlDocument, "signedData").filter((signedData) => (signedData.getAttribute("format") ?? "").trim().toLowerCase() === "alfen").map((signedData) => signedData.textContent.trim()).filter((signedData) => signedData.startsWith("AP;"));
16266
+ if (signedDataValues.length > 0)
16267
+ return signedDataValues.join("\n");
16268
+ } catch {
16269
+ console.log("Error parsing XML content from QR code: " + qrText);
16198
16270
  }
16199
- const english = Text["en"];
16200
- if (english !== void 0)
16201
- return english;
16202
- return Object.values(Text).find((value) => value !== void 0);
16203
- }
16204
- CompleteMultilanguageText(Text, fallbackText) {
16205
- const result = {
16206
- ...Text ?? {}
16207
- };
16208
- const fallback = this.FindBestMultilanguageText(result) ?? fallbackText;
16209
- for (const language of this.uiLanguages)
16210
- result[language] ??= fallback;
16211
- return result;
16271
+ return qrText;
16212
16272
  }
16273
+ //#region Public key methods...
16213
16274
  PublicKeyIdFromFileName(fileName) {
16214
- return (fileName.indexOf(".") > -1 ? fileName.substring(0, fileName.indexOf(".")) : fileName).replace(/[-_]?public[-_]?key/i, "");
16275
+ return (fileName.includes(".") ? fileName.substring(0, fileName.indexOf(".")) : fileName).replace(/[-_]?public[-_]?key/i, "");
16215
16276
  }
16216
16277
  TryToParseDERPublicKey(keyId, publicKeyBuffer) {
16217
16278
  const ASN1_OIDs = this.asn1.define("OIDs", function() {
@@ -16292,66 +16353,13 @@ var Chargy = class {
16292
16353
  return textContent.replace(/\s+/g, "");
16293
16354
  return void 0;
16294
16355
  }
16356
+ //#endregion
16357
+ //#region QR code image files...
16295
16358
  isSupportedQRCodeImageFile(fileInfo, mimeType) {
16296
16359
  const mimeTypeToCheck = (mimeType ?? fileInfo.type ?? "").toLowerCase();
16297
16360
  const fileName = fileInfo.name.toLowerCase();
16298
16361
  return mimeTypeToCheck === "image/png" || mimeTypeToCheck === "image/jpeg" || mimeTypeToCheck === "image/jpg" || mimeTypeToCheck === "image/gif" || mimeTypeToCheck === "image/webp" || mimeTypeToCheck === "image/bmp" || mimeTypeToCheck === "image/svg+xml" || fileName.endsWith(".png") || fileName.endsWith(".jpg") || fileName.endsWith(".jpeg") || fileName.endsWith(".gif") || fileName.endsWith(".webp") || fileName.endsWith(".bmp") || fileName.endsWith(".svg");
16299
16362
  }
16300
- fileNameWithoutExtension(fileName) {
16301
- const lastSeparator = Math.max(fileName.lastIndexOf("/"), fileName.lastIndexOf("\\"));
16302
- const lastDot = fileName.lastIndexOf(".");
16303
- if (lastDot > lastSeparator)
16304
- return fileName.substring(0, lastDot);
16305
- return fileName;
16306
- }
16307
- textFileNameForQRCodeContent(fileName, qrText) {
16308
- const trimmedQRCodeText = qrText.trimStart();
16309
- const baseFileName = this.fileNameWithoutExtension(fileName);
16310
- if (trimmedQRCodeText.startsWith("<?xml") || trimmedQRCodeText.startsWith("<"))
16311
- return baseFileName + ".xml";
16312
- if (trimmedQRCodeText.startsWith("{") || trimmedQRCodeText.startsWith("["))
16313
- return baseFileName + ".json";
16314
- return baseFileName + ".txt";
16315
- }
16316
- tryExtractChargeTransparencyTextFromURL(qrText) {
16317
- if (!qrText.startsWith("http://") && !qrText.startsWith("https://"))
16318
- return qrText;
16319
- try {
16320
- const url = new URL(qrText);
16321
- const candidates = [
16322
- url.hash.startsWith("#") ? url.hash.substring(1) : url.hash,
16323
- url.searchParams.get("data"),
16324
- url.searchParams.get("content"),
16325
- url.searchParams.get("ctr"),
16326
- url.searchParams.get("record"),
16327
- url.searchParams.get("payload"),
16328
- url.searchParams.get("q")
16329
- ];
16330
- for (const candidate of candidates) {
16331
- const decodedCandidate = candidate != null ? decodeURIComponent(candidate).trim() : "";
16332
- if (decodedCandidate.startsWith("<?xml") || decodedCandidate.startsWith("<values") || decodedCandidate.startsWith("{") || decodedCandidate.startsWith("[") || decodedCandidate.startsWith("OCMF") || decodedCandidate.startsWith("AP;")) {
16333
- return decodedCandidate;
16334
- }
16335
- }
16336
- } catch {
16337
- console.log("Invalid URL in QR code: " + qrText);
16338
- }
16339
- return qrText;
16340
- }
16341
- tryExtractSignedDataTextFromXML(qrText) {
16342
- const trimmedQRCodeText = qrText.trim();
16343
- if (!trimmedQRCodeText.startsWith("<?xml") && !trimmedQRCodeText.startsWith("<"))
16344
- return qrText;
16345
- try {
16346
- const xmlDocument = new DOMParser().parseFromString(trimmedQRCodeText, "text/xml");
16347
- const signedDataValues = getElementsByLocalName(xmlDocument, "signedData").filter((signedData) => (signedData.getAttribute("format") ?? "").trim().toLowerCase() === "alfen").map((signedData) => signedData.textContent.trim()).filter((signedData) => signedData.startsWith("AP;"));
16348
- if (signedDataValues.length > 0)
16349
- return signedDataValues.join("\n");
16350
- } catch {
16351
- console.log("Error parsing XML content from QR code: " + qrText);
16352
- }
16353
- return qrText;
16354
- }
16355
16363
  async expandQRCodeImageFiles(FileInfos) {
16356
16364
  const expandedFileInfos = new Array();
16357
16365
  for (const fileInfo of FileInfos) {
@@ -16383,7 +16391,50 @@ var Chargy = class {
16383
16391
  }
16384
16392
  return expandedFileInfos;
16385
16393
  }
16386
- //#region GetLocalizedMessages...
16394
+ textFileNameForQRCodeContent(fileName, qrText) {
16395
+ const trimmedQRCodeText = qrText.trimStart();
16396
+ const baseFileName = this.fileNameWithoutExtension(fileName);
16397
+ if (trimmedQRCodeText.startsWith("<?xml") || trimmedQRCodeText.startsWith("<"))
16398
+ return baseFileName + ".xml";
16399
+ if (trimmedQRCodeText.startsWith("{") || trimmedQRCodeText.startsWith("["))
16400
+ return baseFileName + ".json";
16401
+ return baseFileName + ".txt";
16402
+ }
16403
+ //#endregion
16404
+ //#region i18n...
16405
+ SetUILanguages(UILanguages) {
16406
+ this.uiLanguages = this.NormalizeUILanguages(UILanguages);
16407
+ }
16408
+ NormalizeUILanguages(UILanguages) {
16409
+ const languages = new Array();
16410
+ for (const language of UILanguages) {
16411
+ const normalized = language.trim();
16412
+ if (normalized.length > 0 && !languages.includes(normalized)) {
16413
+ languages.push(normalized);
16414
+ }
16415
+ }
16416
+ return languages.length > 0 ? languages : ["en"];
16417
+ }
16418
+ FindBestMultilanguageText(Text) {
16419
+ for (const language of this.uiLanguages) {
16420
+ const localLanguage = Text[language];
16421
+ if (localLanguage !== void 0)
16422
+ return localLanguage;
16423
+ }
16424
+ const english = Text["en"];
16425
+ if (english !== void 0)
16426
+ return english;
16427
+ return Object.values(Text).find((value) => value !== void 0);
16428
+ }
16429
+ CompleteMultilanguageText(Text, fallbackText) {
16430
+ const result = {
16431
+ ...Text ?? {}
16432
+ };
16433
+ const fallback = this.FindBestMultilanguageText(result) ?? fallbackText;
16434
+ for (const language of this.uiLanguages)
16435
+ result[language] ??= fallback;
16436
+ return result;
16437
+ }
16387
16438
  GetLocalizedMessage(Text) {
16388
16439
  const multiLanguage = this.i18n[Text];
16389
16440
  if (multiLanguage !== void 0) {
@@ -16417,6 +16468,14 @@ var Chargy = class {
16417
16468
  }
16418
16469
  return this.CompleteMultilanguageText(parameterizedText, Text.replace("%p", String(Parameter)));
16419
16470
  }
16471
+ getLocalizedText(data) {
16472
+ if (data == null)
16473
+ return void 0;
16474
+ const bestLanguage = this.FindBestMultilanguageText(data);
16475
+ if (bestLanguage == null)
16476
+ return void 0;
16477
+ return data[bestLanguage];
16478
+ }
16420
16479
  //#endregion
16421
16480
  //#region GetDevices...
16422
16481
  GetChargingPool = (Id) => {
@@ -16567,7 +16626,7 @@ var Chargy = class {
16567
16626
  if (compressedFiles.length == 0)
16568
16627
  continue;
16569
16628
  archiveFound = true;
16570
- if (compressedFiles.length == 1 && compressedFiles[0]?.path == null) {
16629
+ if (compressedFiles.length == 1) {
16571
16630
  expandedFileInfos.push({
16572
16631
  name: FileInfo.name.substring(0, FileInfo.name.lastIndexOf(".")),
16573
16632
  data: compressedFiles[0]?.data
@@ -16604,9 +16663,12 @@ var Chargy = class {
16604
16663
  }
16605
16664
  if (dataFile.length > 0 && signatureFile.length > 0) {
16606
16665
  try {
16607
- CTRfile = JSON.parse(dataFile);
16608
- CTRfile.original = btoa(dataFile);
16609
- CTRfile.signature = signatureFile;
16666
+ const parsedCTRFile = JSON.parse(dataFile);
16667
+ if (!isMandatoryJSONObject(parsedCTRFile))
16668
+ throw new Error("Invalid chargepoint 'secrrct' JSON file!");
16669
+ CTRfile = parsedCTRFile;
16670
+ CTRfile["original"] = btoa(dataFile);
16671
+ CTRfile["signature"] = signatureFile;
16610
16672
  expandedFileInfos.push({
16611
16673
  name: FileInfo.name,
16612
16674
  data: new TextEncoder().encode(JSON.stringify(CTRfile))
@@ -16645,11 +16707,10 @@ var Chargy = class {
16645
16707
  } while (archiveFound);
16646
16708
  return expandedFileInfos;
16647
16709
  }
16648
- //#endregion
16649
16710
  async extractArchive(fileName, data, mimeType) {
16650
16711
  const archiveData = this.toUint8Array(data);
16651
16712
  if (mimeType === "application/zip")
16652
- return await this.extractZipArchive(archiveData);
16713
+ return this.extractZipArchive(archiveData);
16653
16714
  if (mimeType === "application/x-tar")
16654
16715
  return this.extractTarArchive(archiveData);
16655
16716
  if (mimeType === "application/gzip") {
@@ -16688,7 +16749,7 @@ var Chargy = class {
16688
16749
  break;
16689
16750
  const prefix = this.readTarString(header, 345, 155);
16690
16751
  const path = prefix.length > 0 ? prefix + "/" + name : name;
16691
- const typeFlag = String.fromCharCode(header[156] ?? 0);
16752
+ const typeFlag = String.fromCharCode(getArrayElement(header, 156, "Missing tar header type flag"));
16692
16753
  const dataStart = offset + 512;
16693
16754
  const dataEnd = dataStart + size;
16694
16755
  if (dataEnd > data.byteLength)
@@ -16784,6 +16845,7 @@ var Chargy = class {
16784
16845
  const value = this.readTarString(data, offset, length).replace(/\0/g, "").trim();
16785
16846
  return value.length > 0 ? parseInt(value, 8) : 0;
16786
16847
  }
16848
+ //#endregion
16787
16849
  //#region DetectAndConvertContentFormat(FileInfos)
16788
16850
  async DetectAndConvertContentFormat(FileInfos) {
16789
16851
  if (FileInfos.length == 0) return {
@@ -16797,45 +16859,48 @@ var Chargy = class {
16797
16859
  for (const fileInfo of FileInfos) {
16798
16860
  if (fileInfo.type === "application/pdf" || fileInfo.name.endsWith(".pdf")) {
16799
16861
  const pdfjsLib = await importPdfJs();
16800
- const pdfDocument = fileInfo.data ? await pdfjsLib.getDocument({ data: fileInfo.data }).promise : fileInfo.path ? await pdfjsLib.getDocument({ url: fileInfo.path }).promise : null;
16801
- if (pdfDocument) {
16862
+ const pdfDocument = fileInfo.data ? await pdfjsLib.getDocument({ data: fileInfo.data }).promise : fileInfo.path != null && fileInfo.path.length > 0 ? await pdfjsLib.getDocument({ url: fileInfo.path }).promise : null;
16863
+ if (pdfDocument !== null) {
16802
16864
  try {
16803
- const attachments = await pdfDocument.getAttachments();
16804
- Object.keys(attachments).forEach((fileName) => {
16805
- const attachment = attachments[fileName];
16806
- if (attachment.filename.endsWith(".chargy"))
16807
- expandedFiles.push({
16808
- name: attachment.filename,
16809
- path: FileInfos[0]?.path,
16810
- type: "application/chargy",
16811
- data: attachment.content,
16812
- info: "A CHARGY file extracted from a PDF/A-3 or newer attachment"
16813
- });
16814
- else if (attachment.filename.endsWith(".xml"))
16815
- expandedFiles.push({
16816
- name: attachment.filename,
16817
- path: FileInfos[0]?.path,
16818
- type: "application/xml",
16819
- data: attachment.content,
16820
- info: "A XML file extracted from a PDF/A-3 or newer attachment"
16821
- });
16822
- else if (attachment.filename.endsWith(".json"))
16823
- expandedFiles.push({
16824
- name: attachment.filename,
16825
- path: FileInfos[0]?.path,
16826
- type: "application/json",
16827
- data: attachment.content,
16828
- info: "A JSON file extracted from a PDF/A-3 or newer attachment"
16829
- });
16830
- else if (attachment.filename.endsWith(".csv"))
16831
- expandedFiles.push({
16832
- name: attachment.filename,
16833
- path: FileInfos[0]?.path,
16834
- type: "text/csv",
16835
- data: attachment.content,
16836
- info: "A CSV file extracted from a PDF/A-3 or newer attachment"
16837
- });
16838
- });
16865
+ const attachmentsUnknown = await pdfDocument.getAttachments();
16866
+ if (isMandatoryJSONObject(attachmentsUnknown))
16867
+ Object.values(attachmentsUnknown).forEach((attachmentUnknown) => {
16868
+ if (!isPdfAttachment(attachmentUnknown))
16869
+ return;
16870
+ const attachment = attachmentUnknown;
16871
+ if (attachment.filename.endsWith(".chargy"))
16872
+ expandedFiles.push({
16873
+ name: attachment.filename,
16874
+ path: FileInfos[0]?.path,
16875
+ type: "application/chargy",
16876
+ data: attachment.content,
16877
+ info: "A CHARGY file extracted from a PDF/A-3 or newer attachment"
16878
+ });
16879
+ else if (attachment.filename.endsWith(".xml"))
16880
+ expandedFiles.push({
16881
+ name: attachment.filename,
16882
+ path: FileInfos[0]?.path,
16883
+ type: "application/xml",
16884
+ data: attachment.content,
16885
+ info: "A XML file extracted from a PDF/A-3 or newer attachment"
16886
+ });
16887
+ else if (attachment.filename.endsWith(".json"))
16888
+ expandedFiles.push({
16889
+ name: attachment.filename,
16890
+ path: FileInfos[0]?.path,
16891
+ type: "application/json",
16892
+ data: attachment.content,
16893
+ info: "A JSON file extracted from a PDF/A-3 or newer attachment"
16894
+ });
16895
+ else if (attachment.filename.endsWith(".csv"))
16896
+ expandedFiles.push({
16897
+ name: attachment.filename,
16898
+ path: FileInfos[0]?.path,
16899
+ type: "text/csv",
16900
+ data: attachment.content,
16901
+ info: "A CSV file extracted from a PDF/A-3 or newer attachment"
16902
+ });
16903
+ });
16839
16904
  } catch (error) {
16840
16905
  console.error(`Error extracting PDF/A-3 attachments: ${String(error)}`);
16841
16906
  }
@@ -16881,7 +16946,7 @@ var Chargy = class {
16881
16946
  break;
16882
16947
  }
16883
16948
  processedFile.result = await new SAFEXML(this).tryToParseSAFEXML(XMLDocument);
16884
- if (processedFile.result.status && processedFile.result.status !== "Unvalidated" /* Unvalidated */ && getElementsByLocalName(XMLDocument, "chargingStation").length === 0) {
16949
+ if (processedFile.result.status != null && processedFile.result.status !== "Unvalidated" /* Unvalidated */ && getElementsByLocalName(XMLDocument, "chargingStation").length === 0) {
16885
16950
  processedFile.result = new XMLContainer(this).tryToParseXMLContainer(XMLDocument);
16886
16951
  }
16887
16952
  break;
@@ -16965,8 +17030,7 @@ var Chargy = class {
16965
17030
  if (isMandatoryJSONObject(JSONContent)) {
16966
17031
  const JSONContext = JSONContent["@context"];
16967
17032
  if (IsAChargeTransparencyLiveLink(JSONContent)) {
16968
- if (JSONContent.timestamp == null)
16969
- JSONContent.timestamp = (/* @__PURE__ */ new Date()).toISOString();
17033
+ JSONContent.timestamp ??= (/* @__PURE__ */ new Date()).toISOString();
16970
17034
  processedFile.result = JSONContent;
16971
17035
  } else if (isMandatoryString(JSONContext)) {
16972
17036
  if (JSONContext.startsWith("https://open.charging.cloud/contexts/CTR+json"))
@@ -17010,25 +17074,18 @@ var Chargy = class {
17010
17074
  processedFiles.push(processedFile);
17011
17075
  }
17012
17076
  if (processedFiles.length == 1) {
17013
- const processedFile = processedFiles[0];
17014
- if (processedFile) {
17015
- if (IsAChargeTransparencyRecord(processedFile.result))
17016
- return this.processChargeTransparencyRecord(processedFile.result);
17017
- if (IsAChargeTransparencyLiveLink(processedFile.result))
17018
- return processedFile.result;
17019
- if (IsAPublicKeyLookup(processedFile.result))
17020
- return {
17021
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
17022
- message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
17023
- certainty: 0
17024
- };
17077
+ const processedFile = getFirstArrayElement(processedFiles, "Missing processed file");
17078
+ if (IsAChargeTransparencyRecord(processedFile.result))
17079
+ return this.processChargeTransparencyRecord(processedFile.result);
17080
+ if (IsAChargeTransparencyLiveLink(processedFile.result))
17025
17081
  return processedFile.result;
17026
- }
17027
- return {
17028
- status: "InvalidSessionFormat" /* InvalidSessionFormat */,
17029
- message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
17030
- certainty: 0
17031
- };
17082
+ if (IsAPublicKeyLookup(processedFile.result))
17083
+ return {
17084
+ status: "InvalidSessionFormat" /* InvalidSessionFormat */,
17085
+ message: this.GetMultilanguageText("UnknownOrInvalidChargeTransparencyRecord"),
17086
+ certainty: 0
17087
+ };
17088
+ return processedFile.result;
17032
17089
  } else if (processedFiles.length > 1) {
17033
17090
  const mergedCTR = {
17034
17091
  "@id": "",
@@ -17042,14 +17099,12 @@ var Chargy = class {
17042
17099
  mergedCTR["@id"] = processedFileResult["@id"];
17043
17100
  if (mergedCTR["@context"] === "")
17044
17101
  mergedCTR["@context"] = processedFileResult["@context"];
17045
- if (!mergedCTR.begin || mergedCTR.begin && processedFileResult.begin && mergedCTR.begin > processedFileResult.begin)
17102
+ if (processedFileResult.begin != null && processedFileResult.begin.length > 0 && (mergedCTR.begin == null || mergedCTR.begin.length === 0 || mergedCTR.begin > processedFileResult.begin))
17046
17103
  mergedCTR.begin = processedFileResult.begin;
17047
- if (!mergedCTR.end || mergedCTR.end && processedFileResult.end && mergedCTR.end < processedFileResult.end)
17104
+ if (processedFileResult.end != null && processedFileResult.end.length > 0 && (mergedCTR.end == null || mergedCTR.end.length === 0 || mergedCTR.end < processedFileResult.end))
17048
17105
  mergedCTR.end = processedFileResult.end;
17049
- if (!mergedCTR.description)
17050
- mergedCTR.description = processedFileResult.description;
17051
- if (!mergedCTR.contract)
17052
- mergedCTR.contract = processedFileResult.contract;
17106
+ mergedCTR.description ??= processedFileResult.description;
17107
+ mergedCTR.contract ??= processedFileResult.contract;
17053
17108
  if (!mergedCTR.chargingStationOperators)
17054
17109
  mergedCTR.chargingStationOperators = processedFileResult.chargingStationOperators;
17055
17110
  else if (processedFileResult.chargingStationOperators)
@@ -17081,17 +17136,14 @@ var Chargy = class {
17081
17136
  for (const mediationService of processedFileResult.mediationServices)
17082
17137
  mergedCTR.mediationServices.push(mediationService);
17083
17138
  } else if (IsAPublicKeyInfo(processedFileResult)) {
17084
- if (!mergedCTR.publicKeys)
17085
- mergedCTR.publicKeys = new Array();
17139
+ mergedCTR.publicKeys ??= new Array();
17086
17140
  mergedCTR.publicKeys.push(processedFileResult);
17087
17141
  } else if (IsAPublicKeyLookup(processedFileResult)) {
17088
- if (!mergedCTR.publicKeys)
17089
- mergedCTR.publicKeys = new Array();
17142
+ mergedCTR.publicKeys ??= new Array();
17090
17143
  for (const publicKey of processedFileResult.publicKeys)
17091
17144
  mergedCTR.publicKeys.push(publicKey);
17092
17145
  } else {
17093
- if (mergedCTR.invalidDataSets === void 0)
17094
- mergedCTR.invalidDataSets = new Array();
17146
+ mergedCTR.invalidDataSets ??= new Array();
17095
17147
  mergedCTR.invalidDataSets.push(processedFile);
17096
17148
  }
17097
17149
  }
@@ -17119,8 +17171,6 @@ var Chargy = class {
17119
17171
  this.EVSEs = [];
17120
17172
  this.meters = [];
17121
17173
  this.chargingSessions = [];
17122
- this.eMobilityProviders = [];
17123
- this.mediationServices = [];
17124
17174
  try {
17125
17175
  this.internalCTR = CloneCTR(CTR);
17126
17176
  this.currentCTR = CTR;
@@ -17247,9 +17297,9 @@ var Chargy = class {
17247
17297
  if (measurement.name !== "ENERGY_TOTAL" || measurement.values.length < 2) {
17248
17298
  continue;
17249
17299
  }
17250
- const firstValue2 = measurement.values[0];
17251
- const lastValue = measurement.values[measurement.values.length - 1];
17252
- if (firstValue2 == null || lastValue == null) {
17300
+ const firstValue2 = measurement.values.at(0);
17301
+ const lastValue = measurement.values.at(-1);
17302
+ if (firstValue2 === void 0 || lastValue === void 0) {
17253
17303
  continue;
17254
17304
  }
17255
17305
  const firstValueKWh = this.measurementValueInKWh(measurement, firstValue2);
@@ -17398,14 +17448,12 @@ var Chargy = class {
17398
17448
  mergedCTR["@id"] = ctr["@id"];
17399
17449
  if (mergedCTR["@context"] === "")
17400
17450
  mergedCTR["@context"] = ctr["@context"];
17401
- if (!mergedCTR.begin || mergedCTR.begin && ctr.begin && mergedCTR.begin > ctr.begin)
17451
+ if (ctr.begin != null && ctr.begin.length > 0 && (mergedCTR.begin == null || mergedCTR.begin.length === 0 || mergedCTR.begin > ctr.begin))
17402
17452
  mergedCTR.begin = ctr.begin;
17403
- if (!mergedCTR.end || mergedCTR.end && ctr.end && mergedCTR.end < ctr.end)
17453
+ if (ctr.end != null && ctr.end.length > 0 && (mergedCTR.end == null || mergedCTR.end.length === 0 || mergedCTR.end < ctr.end))
17404
17454
  mergedCTR.end = ctr.end;
17405
- if (!mergedCTR.description)
17406
- mergedCTR.description = ctr.description;
17407
- if (!mergedCTR.contract)
17408
- mergedCTR.contract = ctr.contract;
17455
+ mergedCTR.description ??= ctr.description;
17456
+ mergedCTR.contract ??= ctr.contract;
17409
17457
  if (!mergedCTR.chargingStationOperators)
17410
17458
  mergedCTR.chargingStationOperators = ctr.chargingStationOperators;
17411
17459
  else if (ctr.chargingStationOperators)
@@ -17453,6 +17501,6 @@ function toSessionVerificationResults(CTR, noRecordsMessage = { "en": "No charge
17453
17501
  };
17454
17502
  }
17455
17503
 
17456
- export { ACrypt, Alfen, AlfenCrypt01, BSMCrypt01, CanonicalJSONError, ChargeIT, ChargePoint, ChargePointCrypt01, IChargeTransparencyLiveLink_exports as ChargeTransparencyLiveLink, ChargeTransparencyLiveLinkContext, IChargeTransparencyRecord_exports as ChargeTransparencyRecord, Chargy, chargyInterfaces_exports as ChargyInterfaces, Clone, CloneCTR, ConcatenateBuffers, CreateDiv, CreateDiv2, CreateError, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKeyInfo, IsAPublicKeyLookup, IsASessionCryptoResult, IsNullOrEmpty, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFTransactionTypes, OCMFv1_x, OCPI, PCDF, PCDFCrypt01, PCDFParseError, PCDFValidationError, PCDF_FIELD_ORDER, PCDF_PREFIX, ParseJSON_LD, PublicKeyFormats, IPublicKeyInfo_exports as PublicKeyInfo, SAFEXML, SessionVerificationResult, SetHex, SetInt8, SetText, SetText_withLength, SetTimestamp, SetTimestamp32, SetUInt32, SetUInt32_withCode, SetUInt64, SetUInt64D, SignMessage, SignatureFormats, TimeStatusTypes, UTC2human, VerificationResult, VerifyJSONMessageSignatures, WarningLevel, WhenNullOrEmpty, XMLContainer, asJSONArray, asJSONObject, asNumber, asString, buf2hex, buildMennekesSignatureData, bytesToHex2 as bytesToHex, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, extractMennekesChargingProcesses, firstKey, firstValue, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isGeoLocation, isICryptoResult, isIFileInfo, isIPublicKeyXY, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isMultilanguageText, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalURL, isPCDFText, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, secp224k1, setUILocale, sha256, sha384, sha512, signJSONMessage, signMessage, stripPCDFControlCharacters, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, unquotePCDFText, validatePCDFFields, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
17504
+ export { ACrypt, Alfen, AlfenCrypt01, BSMCrypt01, CanonicalJSONError, ChargeIT, ChargePoint, ChargePointCrypt01, IChargeTransparencyLiveLink_exports as ChargeTransparencyLiveLink, ChargeTransparencyLiveLinkContext, IChargeTransparencyRecord_exports as ChargeTransparencyRecord, Chargy, chargyInterfaces_exports as ChargyInterfaces, Clone, CloneCTR, ConcatenateBuffers, CreateDiv, CreateDiv2, CreateError, CryptoAlgorithms, CryptoHashAlgorithms, DayOfWeek, DisplayPrefixes, EMHCrypt01, ErrorLevel, GDFCrypt01, IECCurves, IEncoding, InformationRelevance, InformationRelevanceToString, IsAChargeTransparencyLiveLink, IsAChargeTransparencyRecord, IsAPublicKeyInfo, IsAPublicKeyLookup, IsASessionCryptoResult, IsNullOrEmpty, JSONSignatureVerificationStatus, MENNEKES_EDL40_OBIS, MENNEKES_EDL40_XMLNS, Mennekes, MennekesCrypt01, OBIS2Hex, OBIS2MeasurementName, OBIS_RegExpr, OCMF, OCMFTransactionTypes, OCMFv1_x, OCPI, PCDF, PCDFCrypt01, PCDFParseError, PCDFValidationError, PCDF_FIELD_ORDER, PCDF_PREFIX, ParseJSON_LD, PublicKeyFormats, IPublicKeyInfo_exports as PublicKeyInfo, SAFEXML, SessionVerificationResult, SetHex, SetInt8, SetText, SetText_withLength, SetTimestamp, SetTimestamp32, SetUInt32, SetUInt32_withCode, SetUInt64, SetUInt64D, SignMessage, SignatureFormats, TimeStatusTypes, UTC2human, VerificationResult, VerifyJSONMessageSignatures, WarningLevel, WhenNullOrEmpty, XMLContainer, asJSONArray, asJSONObject, asNumber, asString, buf2hex, buildMennekesSignatureData, bytesToHex2 as bytesToHex, canonicalJSONBytes, canonicalJSONStringify, cleanHex, closeFullscreen, createHexString, dateToMennekesLocalEpochSeconds, extractMennekesChargingProcesses, firstKey, firstValue, getArrayElement, getArrayLikeElement, getDirectChildByLocalName, getDirectChildrenByLocalName, getElementsByLocalName, getFirstArrayElement, getInt16Bytes, getInt32Bytes, getInt64Bytes, getInt8Bytes, getLastArrayElement, getTrimmedTextContent, hashFile, hex2bin, hex32, hexToArrayBuffer, hexToBytes, intFromBytes, isGeoLocation, isICryptoResult, isIFileInfo, isIPublicKeyXY, isISessionCryptoResult1, isISessionCryptoResult2, isJSONLDObject, isMandatoryArrayOfStrings, isMandatoryBoolean, isMandatoryDecimal, isMandatoryJSONArray, isMandatoryJSONObject, isMandatoryNumber, isMandatoryString, isMandatoryURL, isMultilanguageText, isOIDInfo, isObject, isOptionalArrayOfStrings, isOptionalDecimal, isOptionalJSONArray, isOptionalJSONArrayError, isOptionalJSONArrayOk, isOptionalJSONObject, isOptionalNumber, isOptionalString, isOptionalURL, isPCDFText, isString, isStringArray, isStringOrOIDInfo, isStringOrStringArray, jsonPrettyPrinter, measurementName2human, normalizePCDFPublicKeyHex, normalizeXMLText, openFullscreen, pad, parseAndVerifyJSONSignatures, parseDescription, parseHexString, parseMennekesXMLDocument, parseNumber, parseOBIS, parsePCDFDocument, parsePCDFPublicKey, parsePCDFSignature, parseUTC, readQRCodeTextFromImage, readQRCodeTextFromImageData, secp224k1, setUILocale, sha256, sha384, sha512, signJSONMessage, signMessage, stripPCDFControlCharacters, time2human, toArrayBuffer, toSessionVerificationResults, toUint8Array, unquotePCDFText, validatePCDFFields, verifyJSONMessageSignatureResults, verifyJSONMessageSignatures, verifyJSONSignature, verifyJSONSignatureResult, verifyPCDFDocument };
17457
17505
  //# sourceMappingURL=index.js.map
17458
17506
  //# sourceMappingURL=index.js.map