@open-charging-cloud/wwcp-poi 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1155 -836
- package/README.md +88 -32
- package/dist/common.d.ts +11 -0
- package/dist/common.d.ts.map +1 -1
- package/dist/evTaler/contractTerms.d.ts +19 -0
- package/dist/evTaler/contractTerms.d.ts.map +1 -1
- package/dist/history/apply.d.ts.map +1 -1
- package/dist/history/changeSet.d.ts +12 -2
- package/dist/history/changeSet.d.ts.map +1 -1
- package/dist/history/commit.d.ts +8 -2
- package/dist/history/commit.d.ts.map +1 -1
- package/dist/history/preconditions.d.ts +3 -2
- package/dist/history/preconditions.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +835 -324
- package/dist/index.js.map +1 -1
- package/dist/network/evTaler.d.ts +6 -0
- package/dist/network/evTaler.d.ts.map +1 -1
- package/dist/network/poiJSON.d.ts +4 -1
- package/dist/network/poiJSON.d.ts.map +1 -1
- package/dist/network/poiValues.d.ts +9 -2
- package/dist/network/poiValues.d.ts.map +1 -1
- package/dist/network/reading.d.ts +13 -1
- package/dist/network/reading.d.ts.map +1 -1
- package/dist/network/references.d.ts +10 -3
- package/dist/network/references.d.ts.map +1 -1
- package/dist/network/roamingNetwork.d.ts +7 -1
- package/dist/network/roamingNetwork.d.ts.map +1 -1
- package/dist/network/writtenForm.d.ts +27 -1
- package/dist/network/writtenForm.d.ts.map +1 -1
- package/dist/proofs/keyStatement.d.ts.map +1 -1
- package/dist/verifier/grossRates.d.ts +11 -0
- package/dist/verifier/grossRates.d.ts.map +1 -0
- package/dist/verifier/sessionPrices.d.ts +3 -0
- package/dist/verifier/sessionPrices.d.ts.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -270,7 +270,7 @@ var Parser = class {
|
|
|
270
270
|
}
|
|
271
271
|
parseObject(depth) {
|
|
272
272
|
const object2 = {};
|
|
273
|
-
const
|
|
273
|
+
const names2 = /* @__PURE__ */ new Set();
|
|
274
274
|
this.position++;
|
|
275
275
|
this.skipWhitespace();
|
|
276
276
|
if (this.text[this.position] === "}") {
|
|
@@ -282,9 +282,9 @@ var Parser = class {
|
|
|
282
282
|
if (this.text[this.position] !== '"')
|
|
283
283
|
this.fail("expected a property name");
|
|
284
284
|
const name = this.parseString();
|
|
285
|
-
if (
|
|
285
|
+
if (names2.has(name))
|
|
286
286
|
this.fail(`the property '${name}' is named twice`);
|
|
287
|
-
|
|
287
|
+
names2.add(name);
|
|
288
288
|
this.skipWhitespace();
|
|
289
289
|
if (this.text[this.position] !== ":")
|
|
290
290
|
this.fail(`expected ':'`);
|
|
@@ -784,6 +784,11 @@ function firstText(i18n3) {
|
|
|
784
784
|
const first2 = Object.values(i18n3)[0];
|
|
785
785
|
return typeof first2 === "string" ? first2 : void 0;
|
|
786
786
|
}
|
|
787
|
+
var withArticle = (nounPhrase, capitalized2 = true) => (/^[aeio]/iu.test(nounPhrase) ? capitalized2 ? "An " : "an " : capitalized2 ? "A " : "a ") + nounPhrase;
|
|
788
|
+
function numberText(value) {
|
|
789
|
+
const text2 = value.toString();
|
|
790
|
+
return text2.includes(".") ? text2.replace(/\.?0+$/u, "") : text2;
|
|
791
|
+
}
|
|
787
792
|
var DIGEST_LENGTH = {
|
|
788
793
|
sha256: 32,
|
|
789
794
|
sha384: 48,
|
|
@@ -1348,6 +1353,7 @@ var CHARGING_STATION_RULES = {
|
|
|
1348
1353
|
"address",
|
|
1349
1354
|
"geoLocation",
|
|
1350
1355
|
"hotline",
|
|
1356
|
+
"webPaymentURL",
|
|
1351
1357
|
"manufacturerId",
|
|
1352
1358
|
"modelId",
|
|
1353
1359
|
"modelURL",
|
|
@@ -1378,6 +1384,7 @@ var CHARGING_POOL_RULES = {
|
|
|
1378
1384
|
"parkingType",
|
|
1379
1385
|
"accessibility",
|
|
1380
1386
|
"hotline",
|
|
1387
|
+
"webPaymentURL",
|
|
1381
1388
|
"gridConnectionPointId",
|
|
1382
1389
|
"openingTimes",
|
|
1383
1390
|
"energyMix",
|
|
@@ -1746,11 +1753,11 @@ function optionalIds(json, property, description, parser) {
|
|
|
1746
1753
|
return parsed;
|
|
1747
1754
|
});
|
|
1748
1755
|
}
|
|
1749
|
-
function optionalEnum(json, property, description,
|
|
1756
|
+
function optionalEnum(json, property, description, names2) {
|
|
1750
1757
|
const value = get(json, property);
|
|
1751
1758
|
if (value === void 0)
|
|
1752
1759
|
return void 0;
|
|
1753
|
-
if (typeof value !== "string" || !
|
|
1760
|
+
if (typeof value !== "string" || !names2.includes(value))
|
|
1754
1761
|
throw new POIError(`Invalid ${description} '${tokenText(value)}'!`);
|
|
1755
1762
|
return value;
|
|
1756
1763
|
}
|
|
@@ -1883,7 +1890,7 @@ var sameId = (left, right) => left !== void 0 && right !== void 0 && ignoringCas
|
|
|
1883
1890
|
var sameText = (left, right) => left === void 0 ? right === void 0 : sameId(left, right);
|
|
1884
1891
|
function distinct(values, key2, description) {
|
|
1885
1892
|
if (new Set(values.map(key2)).size !== values.length)
|
|
1886
|
-
throw new POIError(
|
|
1893
|
+
throw new POIError(`${withArticle(description)} must not be given twice!`);
|
|
1887
1894
|
return [...values];
|
|
1888
1895
|
}
|
|
1889
1896
|
var isBlank = (text2) => trimmed(text2).length === 0;
|
|
@@ -1923,7 +1930,7 @@ function checkPartyKeys(keys, name) {
|
|
|
1923
1930
|
for (const [list, description] of [[keys.signingKeys, "signing key"], [keys.identityKeys, "identity key"]]) {
|
|
1924
1931
|
const ids2 = list.map((key2) => key2.id);
|
|
1925
1932
|
if (new Set(ids2).size !== ids2.length)
|
|
1926
|
-
return
|
|
1933
|
+
return `${withArticle(`${description} of ${name}`)} must not be given twice!`;
|
|
1927
1934
|
}
|
|
1928
1935
|
const signingIds = keys.signingKeys.map((key2) => key2.id).sort(ordinal);
|
|
1929
1936
|
const identities = [...keys.identityKeys].sort((a, b) => ordinal(a.id, b.id));
|
|
@@ -2200,8 +2207,8 @@ ZW|ZWE|716|263|Zimbabwe
|
|
|
2200
2207
|
YY|YYY|999|999|Testland
|
|
2201
2208
|
`;
|
|
2202
2209
|
var ALL = TABLE.trim().split("\n").map((line) => {
|
|
2203
|
-
const [alpha2 = "", alpha3 = "", numeric = "", calling = "", ...
|
|
2204
|
-
return { alpha2, alpha3, numeric: Number(numeric), calling: Number(calling), names };
|
|
2210
|
+
const [alpha2 = "", alpha3 = "", numeric = "", calling = "", ...names2] = line.split("|");
|
|
2211
|
+
return { alpha2, alpha3, numeric: Number(numeric), calling: Number(calling), names: names2 };
|
|
2205
2212
|
});
|
|
2206
2213
|
var by = (keys) => {
|
|
2207
2214
|
const countries = /* @__PURE__ */ new Map();
|
|
@@ -2230,7 +2237,7 @@ var EV_TALER_EXCHANGE_CONTEXT = CONTEXT_PREFIX + "roamingNetwork/evTalerExchange
|
|
|
2230
2237
|
var EV_TALER_PAYMENT_OPTION = "EVTaler";
|
|
2231
2238
|
var EV_TALER_PAYMENT_MEANS = "EV_TALER";
|
|
2232
2239
|
var CROCKFORD_BASE32 = "0123456789ABCDEFGHJKMNPQRSTVWXYZ";
|
|
2233
|
-
var MERCHANT_PROPERTIES = ["@context", "merchantBaseURL", "merchantPublicKey", "exchanges"];
|
|
2240
|
+
var MERCHANT_PROPERTIES = ["@context", "merchantBaseURL", "merchantPublicKey", "exchanges", "offersURL"];
|
|
2234
2241
|
var EXCHANGE_PROPERTIES = ["@context", "masterPublicKey", "baseURL", "currency", "name"];
|
|
2235
2242
|
var CURRENCIES = new Set(`EUR CHF USD CZK GBP HRK PLN RON RSD RUB SEK AED AFN ALL AMD AOA ARS AUD AWG AZN BAM BBD BDT BGN BHD BIF
|
|
2236
2243
|
BMD BND BOB BRL BSD BTN BWP BYN BZD CAD CDF CLP CNY COP CRC CUP CVE DJF DKK DOP DZD EGP ERN ETB FJD FKP
|
|
@@ -2333,6 +2340,8 @@ function notWrittenAsRead(json, read) {
|
|
|
2333
2340
|
return `The EV Taler merchant must not name the property '${property2}'!`;
|
|
2334
2341
|
if (get(json, "merchantBaseURL") !== read.merchantBaseURL)
|
|
2335
2342
|
return `The merchant base URL '${tokenText(get(json, "merchantBaseURL") ?? "")}' is written as '${read.merchantBaseURL}'!`;
|
|
2343
|
+
if (read.offersURL !== void 0 && get(json, "offersURL") !== read.offersURL)
|
|
2344
|
+
return `The offers URL '${tokenText(get(json, "offersURL") ?? "")}' is written as '${read.offersURL}'!`;
|
|
2336
2345
|
return void 0;
|
|
2337
2346
|
}
|
|
2338
2347
|
const exchange = (error) => `Invalid exchange of an EV Taler merchant: ${error}`;
|
|
@@ -2400,9 +2409,15 @@ function evTalerMerchantOf(value) {
|
|
|
2400
2409
|
exchanges.push(exchange);
|
|
2401
2410
|
read.push([exchangeJSON, exchange]);
|
|
2402
2411
|
}
|
|
2412
|
+
const offersURL = urlOf(value, "offersURL", "offers URL of an EV Taler merchant");
|
|
2413
|
+
if (typeof offersURL === "string")
|
|
2414
|
+
return invalid(offersURL);
|
|
2403
2415
|
const urlError = invalidBaseURL(merchantBaseURL, "merchant base URL");
|
|
2404
2416
|
if (urlError !== void 0)
|
|
2405
2417
|
return invalid(`${urlError} (Parameter 'MerchantBaseURL')`);
|
|
2418
|
+
const offersURLError = offersURL === void 0 ? void 0 : invalidBaseURL(offersURL, "offers URL");
|
|
2419
|
+
if (offersURLError !== void 0)
|
|
2420
|
+
return invalid(`${offersURLError} (Parameter 'OffersURL')`);
|
|
2406
2421
|
if (exchanges.length === 0)
|
|
2407
2422
|
return invalid("A merchant accepts at least one exchange! (Parameter 'Exchanges')");
|
|
2408
2423
|
if (new Set(exchanges.map((exchange) => exchange.masterPublicKey)).size !== exchanges.length)
|
|
@@ -2410,7 +2425,8 @@ function evTalerMerchantOf(value) {
|
|
|
2410
2425
|
const merchant = {
|
|
2411
2426
|
merchantBaseURL: merchantBaseURL.text,
|
|
2412
2427
|
merchantPublicKey,
|
|
2413
|
-
exchanges: exchanges.sort((left, right) => ordinal(left.masterPublicKey, right.masterPublicKey))
|
|
2428
|
+
exchanges: exchanges.sort((left, right) => ordinal(left.masterPublicKey, right.masterPublicKey)),
|
|
2429
|
+
...offersURL === void 0 ? {} : { offersURL: offersURL.text }
|
|
2414
2430
|
};
|
|
2415
2431
|
const notWritten2 = notWrittenAsRead(value, merchant) ?? read.map(([json, exchange]) => notWrittenAsRead(json, exchange)).find((error) => error !== void 0);
|
|
2416
2432
|
return notWritten2 === void 0 ? merchant : invalid(notWritten2);
|
|
@@ -2599,18 +2615,18 @@ function ids(json, property, description, parser) {
|
|
|
2599
2615
|
}
|
|
2600
2616
|
return parsed;
|
|
2601
2617
|
}
|
|
2602
|
-
function flags(json, property, description,
|
|
2618
|
+
function flags(json, property, description, names2) {
|
|
2603
2619
|
const value = get(json, property);
|
|
2604
2620
|
if (value === void 0)
|
|
2605
2621
|
return void 0;
|
|
2606
2622
|
if (!isArray(value))
|
|
2607
2623
|
return `The ${description} must be a JSON array!`;
|
|
2608
|
-
const invalid = value.find((item) => typeof item !== "string" || !
|
|
2624
|
+
const invalid = value.find((item) => typeof item !== "string" || !names2.includes(item));
|
|
2609
2625
|
return invalid === void 0 ? void 0 : `Invalid ${description} '${interpolated(invalid)}'!`;
|
|
2610
2626
|
}
|
|
2611
|
-
function enumeration(json, property, description,
|
|
2627
|
+
function enumeration(json, property, description, names2) {
|
|
2612
2628
|
const value = get(json, property);
|
|
2613
|
-
return value === void 0 || typeof value === "string" &&
|
|
2629
|
+
return value === void 0 || typeof value === "string" && names2.includes(value) ? void 0 : `Invalid ${description} '${interpolated(value)}'!`;
|
|
2614
2630
|
}
|
|
2615
2631
|
function texts(json, property, description) {
|
|
2616
2632
|
const value = get(json, property);
|
|
@@ -2867,7 +2883,7 @@ function twice2(items) {
|
|
|
2867
2883
|
}
|
|
2868
2884
|
return void 0;
|
|
2869
2885
|
}
|
|
2870
|
-
var givenTwice2 = (items, description) => twice2(items) === void 0 ? void 0 : new Thrown(`${description} must not be given twice!`);
|
|
2886
|
+
var givenTwice2 = (items, description) => twice2(items) === void 0 ? void 0 : new Thrown(`${withArticle(description)} must not be given twice!`);
|
|
2871
2887
|
function raise(error) {
|
|
2872
2888
|
if (error !== void 0)
|
|
2873
2889
|
throw error;
|
|
@@ -4800,9 +4816,9 @@ function dataLicenses(json) {
|
|
|
4800
4816
|
const id = dataLicense(license);
|
|
4801
4817
|
if (id instanceof Refused)
|
|
4802
4818
|
return `Invalid data license: ${id.error}`;
|
|
4803
|
-
if (given2.has(id))
|
|
4819
|
+
if (given2.has(ignoringCase(id)))
|
|
4804
4820
|
return `The data license '${id}' must not be given twice!`;
|
|
4805
|
-
given2.add(id);
|
|
4821
|
+
given2.add(ignoringCase(id));
|
|
4806
4822
|
}
|
|
4807
4823
|
}
|
|
4808
4824
|
if (licenseIds !== void 0) {
|
|
@@ -4814,9 +4830,9 @@ function dataLicenses(json) {
|
|
|
4814
4830
|
return `Invalid data license identification '${interpolated(item)}'!`;
|
|
4815
4831
|
if (!KNOWN_DATA_LICENSES.includes(id.toUpperCase()))
|
|
4816
4832
|
return `The data license '${id}' is not well-known, so it must be given completely!`;
|
|
4817
|
-
if (given2.has(id))
|
|
4833
|
+
if (given2.has(ignoringCase(id)))
|
|
4818
4834
|
return `The data license '${id}' must not be given twice!`;
|
|
4819
|
-
given2.add(id);
|
|
4835
|
+
given2.add(ignoringCase(id));
|
|
4820
4836
|
}
|
|
4821
4837
|
}
|
|
4822
4838
|
return void 0;
|
|
@@ -4885,7 +4901,7 @@ function openingTimes(json) {
|
|
|
4885
4901
|
if (begin === void 0 || end === void 0)
|
|
4886
4902
|
return `Invalid regular hours '${interpolated(period)}' on ${day}!`;
|
|
4887
4903
|
if (end[0] < begin[0] && end[0] !== 0 || end[0] === begin[0] && end[1] < begin[1] && end[1] !== 0)
|
|
4888
|
-
return `
|
|
4904
|
+
return `The end period '${hhmm(end)}h' must be after the start period '${hhmm(begin)}h'! (Parameter 'PeriodEnd')`;
|
|
4889
4905
|
}
|
|
4890
4906
|
}
|
|
4891
4907
|
}
|
|
@@ -5035,10 +5051,12 @@ function keyError(id, key2, chain) {
|
|
|
5035
5051
|
return computed === id ? void 0 : `The identification '${id}' of a measurement public key is not the SHA-256 '${computed}' of its key!`;
|
|
5036
5052
|
}
|
|
5037
5053
|
var transparencySoftwareAssignment = (json) => context(json, contextOf2("transparencySoftwareAssignment"), `The JSON-LD context of the transparency software status must be '${contextOf2("transparencySoftwareAssignment")}'!`) ?? (get(json, "certificateId") !== void 0 ? "A transparency software status names no certificateId: the certificates of the energy meter and of its charging station prove it!" : void 0) ?? textError(json, "transparencySoftwareId", "transparency software identification", nonEmpty) ?? textError(json, "legalStatus", "legal status", nonEmpty) ?? (get(json, "transparencySoftwareId") === void 0 || get(json, "legalStatus") === void 0 ? "A transparency software status needs its transparencySoftwareId and its legalStatus!" : void 0);
|
|
5054
|
+
var SECURE_DYNAMIC_QR_CODE_CHANNELS = ["BLE", "Display", "NFC"];
|
|
5055
|
+
var SECURE_DYNAMIC_QR_CODE = "SecureDynamicQRCode";
|
|
5038
5056
|
function authenticationMode(json) {
|
|
5039
5057
|
try {
|
|
5040
5058
|
const type = get(json, "type");
|
|
5041
|
-
const error = context(json, contextOf2("authenticationMode"), `The JSON-LD context of the authentication mode must be '${contextOf2("authenticationMode")}'!`) ?? text(json, "type", "authentication mode type") ?? errorOf(idsByName(json, "cardTypes", "RFID card type", ["MifareClassic", "MifareDESFire", "Calypso"])) ?? brands(json) ?? text(json, "number", "number") ?? text(json, "stationCode", "station code") ?? (type === void 0 ? "An authentication mode needs its type!" : void 0);
|
|
5059
|
+
const error = context(json, contextOf2("authenticationMode"), `The JSON-LD context of the authentication mode must be '${contextOf2("authenticationMode")}'!`) ?? text(json, "type", "authentication mode type") ?? errorOf(idsByName(json, "cardTypes", "RFID card type", ["MifareClassic", "MifareDESFire", "Calypso"])) ?? brands(json) ?? text(json, "number", "number") ?? text(json, "stationCode", "station code") ?? errorOf(idsByName(json, "channels", "channel of the secure dynamic QR code", SECURE_DYNAMIC_QR_CODE_CHANNELS)) ?? (type === void 0 ? "An authentication mode needs its type!" : void 0);
|
|
5042
5060
|
if (error !== void 0 || typeof type !== "string")
|
|
5043
5061
|
return error;
|
|
5044
5062
|
if (trimmed(type) === "" || trimmed(type) !== type)
|
|
@@ -5046,6 +5064,9 @@ function authenticationMode(json) {
|
|
|
5046
5064
|
const cardTypes = idsByName(json, "cardTypes", "RFID card type", []);
|
|
5047
5065
|
if (new Set(cardTypes).size !== cardTypes.length)
|
|
5048
5066
|
throw new Thrown("An RFID card type must not be given twice! (Parameter 'CardTypes')");
|
|
5067
|
+
const channels = idsByName(json, "channels", "channel of the secure dynamic QR code", []);
|
|
5068
|
+
if (new Set(channels).size !== channels.length)
|
|
5069
|
+
throw new Thrown("A channel of the secure dynamic QR code must not be given twice! (Parameter 'Channels')");
|
|
5049
5070
|
const brandIds = (isArray(get(json, "brands")) ? get(json, "brands") : []).flatMap((item) => {
|
|
5050
5071
|
const id = isObject(item) && typeof item["@id"] === "string" ? freeId(item["@id"]) : void 0;
|
|
5051
5072
|
return id === void 0 ? [] : [id];
|
|
@@ -5066,6 +5087,11 @@ function authenticationMode(json) {
|
|
|
5066
5087
|
throw new Thrown(`Only SMS and PhoneCall name a number, not '${type}'! (Parameter 'Number')`);
|
|
5067
5088
|
if (get(json, "stationCode") !== void 0 && type !== "SMS")
|
|
5068
5089
|
throw new Thrown(`Only SMS names a station code, not '${type}'! (Parameter 'StationCode')`);
|
|
5090
|
+
if (type === SECURE_DYNAMIC_QR_CODE) {
|
|
5091
|
+
if (channels.length === 0)
|
|
5092
|
+
throw new Thrown(`The authentication mode '${type}' needs the channels its URL is given over: ${SECURE_DYNAMIC_QR_CODE_CHANNELS.join(", ")}! (Parameter 'Channels')`);
|
|
5093
|
+
} else if (channels.length > 0)
|
|
5094
|
+
throw new Thrown(`Only ${SECURE_DYNAMIC_QR_CODE} names channels, not '${type}'! (Parameter 'Channels')`);
|
|
5069
5095
|
return void 0;
|
|
5070
5096
|
} catch (e) {
|
|
5071
5097
|
if (e instanceof Thrown)
|
|
@@ -5073,13 +5099,13 @@ function authenticationMode(json) {
|
|
|
5073
5099
|
throw e;
|
|
5074
5100
|
}
|
|
5075
5101
|
}
|
|
5076
|
-
var idsByName = (json, property, description,
|
|
5102
|
+
var idsByName = (json, property, description, names2) => {
|
|
5077
5103
|
const value = get(json, property);
|
|
5078
5104
|
if (value === void 0)
|
|
5079
5105
|
return [];
|
|
5080
5106
|
if (!isArray(value))
|
|
5081
5107
|
return new Refused(`The ${description} must be a JSON array!`);
|
|
5082
|
-
const invalid =
|
|
5108
|
+
const invalid = names2.length === 0 ? void 0 : value.find((item) => typeof item !== "string" || !names2.includes(item));
|
|
5083
5109
|
return invalid === void 0 ? value.filter((item) => typeof item === "string") : new Refused(`Invalid ${description} '${interpolated(invalid)}'!`);
|
|
5084
5110
|
};
|
|
5085
5111
|
var relatedLocation = (json) => context(json, contextOf2("additionalGeoLocation"), `The JSON-LD context of the related location must be '${contextOf2("additionalGeoLocation")}'!`) ?? geoLocationError(json, "geoLocation", "geo location") ?? i18n(json, "name") ?? (get(json, "geoLocation") === void 0 ? "A related location needs its geo location!" : void 0);
|
|
@@ -5637,6 +5663,7 @@ var STATION_SINGLES = [
|
|
|
5637
5663
|
"address",
|
|
5638
5664
|
"geoLocation",
|
|
5639
5665
|
"hotline",
|
|
5666
|
+
"webPaymentURL",
|
|
5640
5667
|
"manufacturerId",
|
|
5641
5668
|
"modelId",
|
|
5642
5669
|
"modelURL",
|
|
@@ -5795,8 +5822,7 @@ function powerSum(station, evses, id) {
|
|
|
5795
5822
|
const scale = Math.max(left.scale, right.scale);
|
|
5796
5823
|
return new Decimal(left.mantissa * 10n ** BigInt(scale - left.scale) + right.mantissa * 10n ** BigInt(scale - right.scale), scale);
|
|
5797
5824
|
}, new Decimal(0n, 0));
|
|
5798
|
-
|
|
5799
|
-
return maxPower.compareTo(sum2) > 0 ? `The maximum power of the charging station '${id}', ${watt(maxPower)} W, must not exceed the ${watt(sum2)} W of all its EVSEs together! (Parameter 'MaxPower')` : void 0;
|
|
5825
|
+
return maxPower.compareTo(sum2) > 0 ? `The maximum power of the charging station '${id}', ${numberText(maxPower)} W, must not exceed the ${numberText(sum2)} W of all its EVSEs together! (Parameter 'MaxPower')` : void 0;
|
|
5800
5826
|
}
|
|
5801
5827
|
var invalidGroupOrOffer = (operator) => whileChecking(() => groupOrOfferError(operator));
|
|
5802
5828
|
function groupOrOfferError(operator) {
|
|
@@ -5999,9 +6025,16 @@ function newProviderOfferOverlap(network, before) {
|
|
|
5999
6025
|
return void 0;
|
|
6000
6026
|
}
|
|
6001
6027
|
var invalidPaymentOption = (operator) => whileChecking(() => paymentOptionError(operator));
|
|
6028
|
+
var namesSecureDynamicQRCode = (authenticationModes) => isArray(authenticationModes) && authenticationModes.some((mode) => isObject(mode) && mode["type"] === SECURE_DYNAMIC_QR_CODE);
|
|
6002
6029
|
function paymentOptionError(operator) {
|
|
6003
|
-
if (get(operator, "evTaler") !== void 0)
|
|
6030
|
+
if (get(operator, "evTaler") !== void 0) {
|
|
6031
|
+
for (const pool of poolsOf(operator)) {
|
|
6032
|
+
const effective = [pool, ...templatesOf2(pool, operator, "chargingPoolTemplates", poolTemplateId)];
|
|
6033
|
+
if (effective.some((entity) => namesEVTaler(get(entity, "paymentOptions"))) && !effective.some((entity) => namesSecureDynamicQRCode(get(entity, "authenticationModes"))))
|
|
6034
|
+
return `The charging pool '${textOf2(pool, poolId)}' names the payment option '${EV_TALER_PAYMENT_OPTION}' without the authentication mode '${SECURE_DYNAMIC_QR_CODE}': an EV Taler session names the one-time password its EVSE gives right then!`;
|
|
6035
|
+
}
|
|
6004
6036
|
return void 0;
|
|
6037
|
+
}
|
|
6005
6038
|
const id = textOf2(operator, operatorId);
|
|
6006
6039
|
for (const [property, parser, what] of [["chargingPools", poolId, "charging pool"], ["chargingPoolTemplates", poolTemplateId, "charging pool template"]])
|
|
6007
6040
|
for (const entity of sortedAt(operator, property, parser))
|
|
@@ -6023,13 +6056,23 @@ function construct(operator, id, of) {
|
|
|
6023
6056
|
if (later !== void 0)
|
|
6024
6057
|
fail(`The ${description} '${later}' of the operator '${id}' must not be given twice!`, "Children");
|
|
6025
6058
|
};
|
|
6026
|
-
const
|
|
6059
|
+
const operatorOf2 = (entity, parser) => textOf2(entity, parser).slice(0, 6);
|
|
6027
6060
|
for (const pool of objectsAt(operator, "chargingPools"))
|
|
6028
|
-
if (
|
|
6061
|
+
if (operatorOf2(pool, poolId) !== id)
|
|
6029
6062
|
fail(`The charging pool '${textOf2(pool, poolId)}' does not belong to the operator '${id}'!`, "ChargingPools");
|
|
6030
6063
|
ofOperator(objectsAt(operator, "chargingPools"), poolId, "charging pool");
|
|
6064
|
+
const stations = poolsOf(operator).flatMap(stationsOf);
|
|
6065
|
+
for (const [entities, parser, description] of [
|
|
6066
|
+
[stations, stationId, "charging station"],
|
|
6067
|
+
[stations.flatMap(evsesOf), evseId, "EVSE"],
|
|
6068
|
+
[metersOfOperator(operator), freeId, "energy meter"]
|
|
6069
|
+
]) {
|
|
6070
|
+
const later = laterTwice(entities, parser);
|
|
6071
|
+
if (later !== void 0)
|
|
6072
|
+
fail(`The ${description} '${later}' of the operator '${id}' must not be given twice!`, "ChargingPools");
|
|
6073
|
+
}
|
|
6031
6074
|
for (const tariff2 of objectsAt(operator, "chargingTariffs"))
|
|
6032
|
-
if (
|
|
6075
|
+
if (operatorOf2(tariff2, tariffId) !== id)
|
|
6033
6076
|
fail(`The charging tariff '${textOf2(tariff2, tariffId)}' does not belong to the operator '${id}'!`, "ChargingTariffs");
|
|
6034
6077
|
ofOperator(objectsAt(operator, "chargingTariffs"), tariffId, "charging tariff");
|
|
6035
6078
|
const tariffs = keysAt(operator, "chargingTariffs", tariffId);
|
|
@@ -6052,7 +6095,7 @@ function construct(operator, id, of) {
|
|
|
6052
6095
|
]) {
|
|
6053
6096
|
ofOperator(objectsAt(operator, property), parser, description);
|
|
6054
6097
|
for (const group2 of sortedAt(operator, property, parser))
|
|
6055
|
-
if (
|
|
6098
|
+
if (operatorOf2(group2, parser) !== id)
|
|
6056
6099
|
fail(`The group '${textOf2(group2, parser)}' does not belong to the operator '${id}'!`, parameter);
|
|
6057
6100
|
}
|
|
6058
6101
|
ofOperator(objectsAt(operator, "energyMeterGroups"), freeId, "energy meter group");
|
|
@@ -6072,7 +6115,7 @@ function construct(operator, id, of) {
|
|
|
6072
6115
|
ofOperator(objectsAt(operator, "energyMeterTemplates"), freeId, "energy meter template");
|
|
6073
6116
|
for (const [property, parser, , parameter] of templateKinds)
|
|
6074
6117
|
for (const template of sortedAt(operator, property, parser)) {
|
|
6075
|
-
if (
|
|
6118
|
+
if (operatorOf2(template, parser) !== id)
|
|
6076
6119
|
fail(`The template '${textOf2(template, parser)}' does not belong to the operator '${id}'!`, parameter);
|
|
6077
6120
|
const tariff2 = property === "chargingTariffTemplates" ? void 0 : idOf3(template, tariffId, "chargingTariffId");
|
|
6078
6121
|
if (tariff2 !== void 0 && !tariffs.has(tariff2.key))
|
|
@@ -6632,11 +6675,11 @@ var energyMeter = (json) => caught("an energy meter", () => {
|
|
|
6632
6675
|
if (error !== void 0)
|
|
6633
6676
|
return error;
|
|
6634
6677
|
const of = `the energy meter '${id.text}'`;
|
|
6635
|
-
raise(givenTwice2(idsAt(json, "templateIds", freeId), `
|
|
6636
|
-
raise(givenTwice2(releasesAt(json), `
|
|
6637
|
-
raise(givenTwice2(namesAt(json, "signatureMethods"), `
|
|
6638
|
-
raise(givenTwice2(publicKeysAt(json), `
|
|
6639
|
-
raise(givenTwice2(idsAt(json, "certificateIds", freeId), `
|
|
6678
|
+
raise(givenTwice2(idsAt(json, "templateIds", freeId), `template of ${of}`));
|
|
6679
|
+
raise(givenTwice2(releasesAt(json), `transparency software release of ${of}`));
|
|
6680
|
+
raise(givenTwice2(namesAt(json, "signatureMethods"), `signature method of ${of}`));
|
|
6681
|
+
raise(givenTwice2(publicKeysAt(json), `public key of ${of}`));
|
|
6682
|
+
raise(givenTwice2(idsAt(json, "certificateIds", freeId), `certificate of ${of}`));
|
|
6640
6683
|
return void 0;
|
|
6641
6684
|
});
|
|
6642
6685
|
function embeddedEnergyMeter(json) {
|
|
@@ -6654,9 +6697,9 @@ var energyMeterTemplate = (json) => caught("an energy meter template", () => {
|
|
|
6654
6697
|
if (error !== void 0)
|
|
6655
6698
|
return error;
|
|
6656
6699
|
const of = `the energy meter template '${id.text}'`;
|
|
6657
|
-
raise(givenTwice2(releasesAt(json), `
|
|
6658
|
-
raise(givenTwice2(namesAt(json, "signatureMethods"), `
|
|
6659
|
-
raise(givenTwice2(idsAt(json, "certificateIds", freeId), `
|
|
6700
|
+
raise(givenTwice2(releasesAt(json), `transparency software release of ${of}`));
|
|
6701
|
+
raise(givenTwice2(namesAt(json, "signatureMethods"), `signature method of ${of}`));
|
|
6702
|
+
raise(givenTwice2(idsAt(json, "certificateIds", freeId), `certificate of ${of}`));
|
|
6660
6703
|
return void 0;
|
|
6661
6704
|
});
|
|
6662
6705
|
var EVSE_GROUP = { what: "EVSE group", article: "an", kind: "evseGroup", id: evseGroupId, members: "EVSEIds", member: evseId };
|
|
@@ -6671,7 +6714,7 @@ var group = (kind) => (json) => caught(`${kind.article} ${kind.what}`, () => {
|
|
|
6671
6714
|
const error = i18n(json, "name") ?? i18n(json, "description") ?? text(json, "dataSource", "data source") ?? errorOf(ids(json, kind.members, "member identification", kind.member)) ?? metadata(json);
|
|
6672
6715
|
if (error !== void 0)
|
|
6673
6716
|
return error;
|
|
6674
|
-
raise(givenTwice2(idsAt(json, kind.members, kind.member), `
|
|
6717
|
+
raise(givenTwice2(idsAt(json, kind.members, kind.member), `member of the ${kind.what} '${id.text}'`));
|
|
6675
6718
|
return void 0;
|
|
6676
6719
|
});
|
|
6677
6720
|
var memberGroups = (json) => children(json, "EVSEGroups", "EVSEGroupIds", "EVSEGroups", group(EVSE_GROUP)) ?? children(json, "chargingStationGroups", "chargingStationGroupIds", "ChargingStationGroups", group(CHARGING_STATION_GROUP)) ?? children(json, "chargingPoolGroups", "chargingPoolGroupIds", "ChargingPoolGroups", group(CHARGING_POOL_GROUP));
|
|
@@ -6688,9 +6731,9 @@ var chargingConnector = (json) => caught("a charging connector", () => {
|
|
|
6688
6731
|
if (error !== void 0)
|
|
6689
6732
|
return error;
|
|
6690
6733
|
const of = `the charging connector '${id.text}'`;
|
|
6691
|
-
raise(givenTwice2(namesAt(json, "standards"), `
|
|
6692
|
-
raise(givenTwice2(imagesAt(json), `
|
|
6693
|
-
raise(givenTwice2(idsAt(json, "chargingTariffIds", tariffId), `
|
|
6734
|
+
raise(givenTwice2(namesAt(json, "standards"), `standard of ${of}`));
|
|
6735
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
6736
|
+
raise(givenTwice2(idsAt(json, "chargingTariffIds", tariffId), `charging tariff of ${of}`));
|
|
6694
6737
|
if (cableLength instanceof Decimal && signOf(cableLength) <= 0)
|
|
6695
6738
|
return `The cable length of ${of} must be positive!`;
|
|
6696
6739
|
if (cableWeight instanceof Decimal && signOf(cableWeight) <= 0)
|
|
@@ -6719,13 +6762,13 @@ var evse = (json) => caught("an EVSE", () => {
|
|
|
6719
6762
|
if (error !== void 0)
|
|
6720
6763
|
return error;
|
|
6721
6764
|
const of = `the EVSE '${id.text}'`;
|
|
6722
|
-
raise(givenTwice2(idsAt(json, "templateIds", evseTemplateId), `
|
|
6765
|
+
raise(givenTwice2(idsAt(json, "templateIds", evseTemplateId), `template of ${of}`));
|
|
6723
6766
|
evseConstruction(json, of);
|
|
6724
|
-
raise(givenTwice2(idsAt(json, "chargingTariffIds", tariffId), `
|
|
6767
|
+
raise(givenTwice2(idsAt(json, "chargingTariffIds", tariffId), `charging tariff of ${of}`));
|
|
6725
6768
|
collection(objectsOf3(get(json, "brands")), freeId, "brand", of);
|
|
6726
|
-
raise(givenTwice2(imagesAt(json), `
|
|
6727
|
-
raise(givenTwice2(namesAt(json, "standards"), `
|
|
6728
|
-
raise(givenTwice2(idsAt(json, "acceptedEMobilityProviderIds", providerId), `
|
|
6769
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
6770
|
+
raise(givenTwice2(namesAt(json, "standards"), `standard of ${of}`));
|
|
6771
|
+
raise(givenTwice2(idsAt(json, "acceptedEMobilityProviderIds", providerId), `accepted e-mobility provider of ${of}`));
|
|
6729
6772
|
return void 0;
|
|
6730
6773
|
});
|
|
6731
6774
|
var evseTemplate = (json) => caught("an EVSE template", () => {
|
|
@@ -6738,21 +6781,21 @@ var evseTemplate = (json) => caught("an EVSE template", () => {
|
|
|
6738
6781
|
const of = `the EVSE template '${id.text}'`;
|
|
6739
6782
|
evseConstruction(json, of);
|
|
6740
6783
|
collection(objectsOf3(get(json, "brands")), freeId, "brand", of);
|
|
6741
|
-
raise(givenTwice2(imagesAt(json), `
|
|
6742
|
-
raise(givenTwice2(namesAt(json, "standards"), `
|
|
6743
|
-
raise(givenTwice2(idsAt(json, "acceptedEMobilityProviderIds", providerId), `
|
|
6784
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
6785
|
+
raise(givenTwice2(namesAt(json, "standards"), `standard of ${of}`));
|
|
6786
|
+
raise(givenTwice2(idsAt(json, "acceptedEMobilityProviderIds", providerId), `accepted e-mobility provider of ${of}`));
|
|
6744
6787
|
return void 0;
|
|
6745
6788
|
});
|
|
6746
|
-
var stationModel = (json, serialNumber) => textError(json, "hotline", "hotline phone number", phoneNumber) ?? textError(json, "manufacturerId", "manufacturer identification", nonEmpty) ?? textError(json, "modelId", "model identification", nonEmpty) ?? textError(json, "modelURL", "model URL", url) ?? (serialNumber ? textError(json, "serialNumber", "serial number", exactText) : void 0) ?? textError(json, "hardwareRevision", "hardware revision", exactText) ?? textError(json, "firmwareVersion", "firmware version", exactText) ?? objects2(json, "transparencySoftwareStatus", "transparency software status", transparencySoftwareAssignment) ?? errorOf(ids(json, "signatureMethods", "signature method", nonEmpty));
|
|
6789
|
+
var stationModel = (json, serialNumber) => textError(json, "hotline", "hotline phone number", phoneNumber) ?? textError(json, "webPaymentURL", "web payment URL", url) ?? textError(json, "manufacturerId", "manufacturer identification", nonEmpty) ?? textError(json, "modelId", "model identification", nonEmpty) ?? textError(json, "modelURL", "model URL", url) ?? (serialNumber ? textError(json, "serialNumber", "serial number", exactText) : void 0) ?? textError(json, "hardwareRevision", "hardware revision", exactText) ?? textError(json, "firmwareVersion", "firmware version", exactText) ?? objects2(json, "transparencySoftwareStatus", "transparency software status", transparencySoftwareAssignment) ?? errorOf(ids(json, "signatureMethods", "signature method", nonEmpty));
|
|
6747
6790
|
var stationLists = (json) => errorOf(ids(json, "vehicleTypes", "vehicle type", nonEmpty)) ?? errorOf(ids(json, "euVehicleCategories", "EU vehicle category", nonEmpty)) ?? textError(json, "accessibility", "accessibility", nonEmpty) ?? errorOf(ids(json, "features", "charging station feature", nonEmpty)) ?? textError(json, "calibrationInfo", "calibration information", url) ?? textError(json, "certificationInfo", "certification information", url) ?? errorOf(ids(json, "parkingSpaceIds", "parking space identification", freeId)) ?? errorOf(ids(json, "certificateIds", "certificate identification", freeId)) ?? errorOf(optionalDecimal2(json, "maxPower", "maximum power"));
|
|
6748
6791
|
function stationListsConstruction(json, of) {
|
|
6749
6792
|
collection(objectsOf3(get(json, "brands")), freeId, "brand", of);
|
|
6750
|
-
raise(givenTwice2(imagesAt(json), `
|
|
6751
|
-
raise(givenTwice2(namesAt(json, "vehicleTypes"), `
|
|
6752
|
-
raise(givenTwice2(namesAt(json, "euVehicleCategories"), `
|
|
6753
|
-
raise(givenTwice2(namesAt(json, "features"), `
|
|
6754
|
-
raise(givenTwice2(idsAt(json, "parkingSpaceIds", freeId), `
|
|
6755
|
-
raise(givenTwice2(idsAt(json, "certificateIds", freeId), `
|
|
6793
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
6794
|
+
raise(givenTwice2(namesAt(json, "vehicleTypes"), `vehicle type of ${of}`));
|
|
6795
|
+
raise(givenTwice2(namesAt(json, "euVehicleCategories"), `EU vehicle category of ${of}`));
|
|
6796
|
+
raise(givenTwice2(namesAt(json, "features"), `feature of ${of}`));
|
|
6797
|
+
raise(givenTwice2(idsAt(json, "parkingSpaceIds", freeId), `parking space of ${of}`));
|
|
6798
|
+
raise(givenTwice2(idsAt(json, "certificateIds", freeId), `certificate of ${of}`));
|
|
6756
6799
|
}
|
|
6757
6800
|
function powerSumError(station, evses, id) {
|
|
6758
6801
|
const maxPower = optionalDecimal2(station, "maxPower", "");
|
|
@@ -6763,8 +6806,7 @@ function powerSumError(station, evses, id) {
|
|
|
6763
6806
|
const scale = Math.max(left.scale, right.scale);
|
|
6764
6807
|
return new Decimal(left.mantissa * 10n ** BigInt(scale - left.scale) + right.mantissa * 10n ** BigInt(scale - right.scale), scale);
|
|
6765
6808
|
}, new Decimal(0n, 0));
|
|
6766
|
-
|
|
6767
|
-
return maxPower.compareTo(sum2) > 0 ? thrown(`The maximum power of the charging station '${id}', ${watt(maxPower)} W, must not exceed the ${watt(sum2)} W of all its EVSEs together!`, "MaxPower") : void 0;
|
|
6809
|
+
return maxPower.compareTo(sum2) > 0 ? thrown(`The maximum power of the charging station '${id}', ${numberText(maxPower)} W, must not exceed the ${numberText(sum2)} W of all its EVSEs together!`, "MaxPower") : void 0;
|
|
6768
6810
|
}
|
|
6769
6811
|
var chargingStation = (json) => caught("a charging station", () => {
|
|
6770
6812
|
const id = header(json, "charging station identification", stationId, "chargingStation", "charging station");
|
|
@@ -6776,7 +6818,7 @@ var chargingStation = (json) => caught("a charging station", () => {
|
|
|
6776
6818
|
const of = `the charging station '${id.text}'`;
|
|
6777
6819
|
const evses = objectsOf3(get(json, "EVSEs"));
|
|
6778
6820
|
const operator = id.text.slice(0, 6);
|
|
6779
|
-
raise(givenTwice2(idsAt(json, "templateIds", stationTemplateId), `
|
|
6821
|
+
raise(givenTwice2(idsAt(json, "templateIds", stationTemplateId), `template of ${of}`));
|
|
6780
6822
|
if (isNegative2(optionalDecimal2(json, "maxPower", "")))
|
|
6781
6823
|
throw thrown(`The maximum power of ${of} must not be negative!`, "MaxPower");
|
|
6782
6824
|
for (const item of evses) {
|
|
@@ -6785,9 +6827,9 @@ var chargingStation = (json) => caught("a charging station", () => {
|
|
|
6785
6827
|
throw thrown(`The EVSE '${evseOf.text}' does not belong to the operator '${operator}' of ${of}!`, "EVSEs");
|
|
6786
6828
|
}
|
|
6787
6829
|
raise(powerSumError(json, evses, id.text));
|
|
6788
|
-
raise(givenTwice2(releasesAt(json), `
|
|
6789
|
-
raise(givenTwice2(namesAt(json, "signatureMethods"), `
|
|
6790
|
-
raise(givenTwice2(publicKeysAt(json), `
|
|
6830
|
+
raise(givenTwice2(releasesAt(json), `transparency software release of ${of}`));
|
|
6831
|
+
raise(givenTwice2(namesAt(json, "signatureMethods"), `signature method of ${of}`));
|
|
6832
|
+
raise(givenTwice2(publicKeysAt(json), `public key of ${of}`));
|
|
6791
6833
|
collection(evses, evseId, "EVSE", of);
|
|
6792
6834
|
if (twice2(objectsOf3(get(json, "energyMeters")).flatMap((meter) => idOf3(meter, freeId) ?? [])) !== void 0)
|
|
6793
6835
|
throw thrown(`An energy meter of ${of} must not be given twice!`, "EnergyMeters");
|
|
@@ -6804,8 +6846,8 @@ var chargingStationTemplate = (json) => caught("a charging station template", ()
|
|
|
6804
6846
|
const of = `the charging station template '${id.text}'`;
|
|
6805
6847
|
if (isNegative2(optionalDecimal2(json, "maxPower", "")))
|
|
6806
6848
|
throw thrown(`The maximum power of ${of} must not be negative!`, "MaxPower");
|
|
6807
|
-
raise(givenTwice2(releasesAt(json), `
|
|
6808
|
-
raise(givenTwice2(namesAt(json, "signatureMethods"), `
|
|
6849
|
+
raise(givenTwice2(releasesAt(json), `transparency software release of ${of}`));
|
|
6850
|
+
raise(givenTwice2(namesAt(json, "signatureMethods"), `signature method of ${of}`));
|
|
6809
6851
|
stationListsConstruction(json, of);
|
|
6810
6852
|
return void 0;
|
|
6811
6853
|
});
|
|
@@ -6814,19 +6856,19 @@ var nutsCode = (given2) => /^[A-Z]{2}[A-Z0-9]{0,3}$/u.test(trimmed(given2).toUpp
|
|
|
6814
6856
|
function poolListsConstruction(json, of) {
|
|
6815
6857
|
const authenticationModes = objectsOf3(get(json, "authenticationModes")).map((mode) => ({ text: asText(mode["type"]), key: asText(mode["type"]) }));
|
|
6816
6858
|
const relatedLocations = objectsOf3(get(json, "relatedLocations")).map((location) => ({ text: "", key: canonicalJSON([location["geoLocation"] ?? null, location["name"] ?? null]) }));
|
|
6817
|
-
raise(givenTwice2(imagesAt(json), `
|
|
6859
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
6818
6860
|
raise(timeZoneError(json, of));
|
|
6819
|
-
raise(givenTwice2(namesAt(json, "facilities"), `
|
|
6820
|
-
raise(givenTwice2(namesAt(json, "paymentOptions"), `
|
|
6821
|
-
raise(givenTwice2(authenticationModes, `
|
|
6822
|
-
raise(givenTwice2(namesAt(json, "uiFeatures"), `
|
|
6823
|
-
raise(givenTwice2(namesAt(json, "features"), `
|
|
6824
|
-
raise(givenTwice2(keyed(idsByNameAt(json, "locationLanguages"), (name) => name), `
|
|
6825
|
-
raise(givenTwice2(namesAt(json, "parkingRestrictions"), `
|
|
6826
|
-
raise(givenTwice2(relatedLocations, `
|
|
6827
|
-
raise(givenTwice2(namesAt(json, "services"), `
|
|
6828
|
-
raise(givenTwice2(namesAt(json, "standards"), `
|
|
6829
|
-
raise(givenTwice2(keyed(idsAt(json, "nutsCodes", freeId).map((code) => code.text.toUpperCase()), (name) => name), `
|
|
6861
|
+
raise(givenTwice2(namesAt(json, "facilities"), `facility of ${of}`));
|
|
6862
|
+
raise(givenTwice2(namesAt(json, "paymentOptions"), `payment option of ${of}`));
|
|
6863
|
+
raise(givenTwice2(authenticationModes, `authentication mode of ${of}`));
|
|
6864
|
+
raise(givenTwice2(namesAt(json, "uiFeatures"), `user interface feature of ${of}`));
|
|
6865
|
+
raise(givenTwice2(namesAt(json, "features"), `feature of ${of}`));
|
|
6866
|
+
raise(givenTwice2(keyed(idsByNameAt(json, "locationLanguages"), (name) => name), `language of ${of}`));
|
|
6867
|
+
raise(givenTwice2(namesAt(json, "parkingRestrictions"), `parking restriction of ${of}`));
|
|
6868
|
+
raise(givenTwice2(relatedLocations, `related location of ${of}`));
|
|
6869
|
+
raise(givenTwice2(namesAt(json, "services"), `service of ${of}`));
|
|
6870
|
+
raise(givenTwice2(namesAt(json, "standards"), `standard of ${of}`));
|
|
6871
|
+
raise(givenTwice2(keyed(idsAt(json, "nutsCodes", freeId).map((code) => code.text.toUpperCase()), (name) => name), `NUTS code of ${of}`));
|
|
6830
6872
|
}
|
|
6831
6873
|
function timeZoneError(json, of) {
|
|
6832
6874
|
const timeZone2 = get(json, "timeZone");
|
|
@@ -6841,13 +6883,13 @@ var chargingPool = (json) => caught("a charging pool", () => {
|
|
|
6841
6883
|
const id = header(json, "charging pool identification", poolId, "chargingPool", "charging pool");
|
|
6842
6884
|
if (id instanceof Refused)
|
|
6843
6885
|
return id.error;
|
|
6844
|
-
const error = i18n(json, "name") ?? i18n(json, "description") ?? text(json, "dataSource", "data source") ?? addressError(json, "address", "address") ?? geoLocationError(json, "geoLocation", "geo location") ?? textError(json, "parkingType", "parking type", nonEmpty) ?? textError(json, "accessibility", "accessibility", nonEmpty) ?? textError(json, "hotline", "hotline phone number", phoneNumber) ?? dataLicenses(json) ?? children(json, "chargingStations", "chargingStationIds", "charging stations", chargingStation) ?? (get(json, "gridConnectionPoint") !== void 0 ? `The grid connection point of the charging pool '${id.text}' is embedded in its grid operator: name it by 'gridConnectionPointId'!` : void 0) ?? textError(json, "gridConnectionPointId", "grid connection point identification", nonEmpty) ?? energyMeters(json) ?? brands(json) ?? object(json, "openingTimes", "opening times", openingTimes) ?? object(json, "energyMix", "energy mix", energyMix) ?? objects2(json, "images", "images", image) ?? poolLists(json) ?? optionalBoolean(json, "chargingWhenClosed", "charging when closed") ?? errorOf(ids(json, "templateIds", "template identification", poolTemplateId)) ?? metadata(json);
|
|
6886
|
+
const error = i18n(json, "name") ?? i18n(json, "description") ?? text(json, "dataSource", "data source") ?? addressError(json, "address", "address") ?? geoLocationError(json, "geoLocation", "geo location") ?? textError(json, "parkingType", "parking type", nonEmpty) ?? textError(json, "accessibility", "accessibility", nonEmpty) ?? textError(json, "hotline", "hotline phone number", phoneNumber) ?? textError(json, "webPaymentURL", "web payment URL", url) ?? dataLicenses(json) ?? children(json, "chargingStations", "chargingStationIds", "charging stations", chargingStation) ?? (get(json, "gridConnectionPoint") !== void 0 ? `The grid connection point of the charging pool '${id.text}' is embedded in its grid operator: name it by 'gridConnectionPointId'!` : void 0) ?? textError(json, "gridConnectionPointId", "grid connection point identification", nonEmpty) ?? energyMeters(json) ?? brands(json) ?? object(json, "openingTimes", "opening times", openingTimes) ?? object(json, "energyMix", "energy mix", energyMix) ?? objects2(json, "images", "images", image) ?? poolLists(json) ?? optionalBoolean(json, "chargingWhenClosed", "charging when closed") ?? errorOf(ids(json, "templateIds", "template identification", poolTemplateId)) ?? metadata(json);
|
|
6845
6887
|
if (error !== void 0)
|
|
6846
6888
|
return error;
|
|
6847
6889
|
const of = `the charging pool '${id.text}'`;
|
|
6848
6890
|
const stations = objectsOf3(get(json, "chargingStations"));
|
|
6849
6891
|
const operator = id.text.slice(0, 6);
|
|
6850
|
-
raise(givenTwice2(idsAt(json, "templateIds", poolTemplateId), `
|
|
6892
|
+
raise(givenTwice2(idsAt(json, "templateIds", poolTemplateId), `template of ${of}`));
|
|
6851
6893
|
for (const station of stations) {
|
|
6852
6894
|
const stationOf = idOf3(station, stationId);
|
|
6853
6895
|
if (stationOf !== void 0 && stationOf.text.slice(0, 6) !== operator)
|
|
@@ -6864,7 +6906,7 @@ var chargingPoolTemplate = (json) => caught("a charging pool template", () => {
|
|
|
6864
6906
|
const id = header(json, "charging pool template identification", poolTemplateId, "chargingPoolTemplate", "charging pool template");
|
|
6865
6907
|
if (id instanceof Refused)
|
|
6866
6908
|
return id.error;
|
|
6867
|
-
const error = i18n(json, "name") ?? i18n(json, "description") ?? text(json, "dataSource", "data source") ?? textError(json, "chargingTariffId", "charging tariff identification", tariffId) ?? addressError(json, "address", "address") ?? geoLocationError(json, "geoLocation", "geo location") ?? textError(json, "parkingType", "parking type", nonEmpty) ?? textError(json, "accessibility", "accessibility", nonEmpty) ?? textError(json, "hotline", "hotline phone number", phoneNumber) ?? dataLicenses(json) ?? textError(json, "gridConnectionPointId", "grid connection point identification", nonEmpty) ?? brands(json) ?? object(json, "openingTimes", "opening times", openingTimes) ?? object(json, "energyMix", "energy mix", energyMix) ?? objects2(json, "images", "images", image) ?? poolLists(json) ?? optionalBoolean(json, "chargingWhenClosed", "charging when closed") ?? metadata(json);
|
|
6909
|
+
const error = i18n(json, "name") ?? i18n(json, "description") ?? text(json, "dataSource", "data source") ?? textError(json, "chargingTariffId", "charging tariff identification", tariffId) ?? addressError(json, "address", "address") ?? geoLocationError(json, "geoLocation", "geo location") ?? textError(json, "parkingType", "parking type", nonEmpty) ?? textError(json, "accessibility", "accessibility", nonEmpty) ?? textError(json, "hotline", "hotline phone number", phoneNumber) ?? textError(json, "webPaymentURL", "web payment URL", url) ?? dataLicenses(json) ?? textError(json, "gridConnectionPointId", "grid connection point identification", nonEmpty) ?? brands(json) ?? object(json, "openingTimes", "opening times", openingTimes) ?? object(json, "energyMix", "energy mix", energyMix) ?? objects2(json, "images", "images", image) ?? poolLists(json) ?? optionalBoolean(json, "chargingWhenClosed", "charging when closed") ?? metadata(json);
|
|
6868
6910
|
if (error !== void 0)
|
|
6869
6911
|
return error;
|
|
6870
6912
|
const of = `the charging pool template '${id.text}'`;
|
|
@@ -6914,12 +6956,12 @@ function priceComponent(json) {
|
|
|
6914
6956
|
if (stepSize instanceof Refused)
|
|
6915
6957
|
return stepSize.error;
|
|
6916
6958
|
if (price !== void 0 && price.mantissa < 0n)
|
|
6917
|
-
return `The price of
|
|
6959
|
+
return `The price of ${withArticle(`${asText(type)} price component`, false)} must not be negative!`;
|
|
6918
6960
|
if (vat !== void 0 && (vat.mantissa < 0n || vat.compareTo(new Decimal(100n, 0)) > 0))
|
|
6919
|
-
return `The VAT of
|
|
6961
|
+
return `The VAT of ${withArticle(`${asText(type)} price component`, false)} must be between 0 and 100 percent!`;
|
|
6920
6962
|
if (type === "FLAT")
|
|
6921
6963
|
return isGiven3(get(json, "stepSize")) ? "A FLAT price component has no step size!" : void 0;
|
|
6922
|
-
return stepSize === void 0 || signOf(stepSize) <= 0 ?
|
|
6964
|
+
return stepSize === void 0 || signOf(stepSize) <= 0 ? `${withArticle(`${asText(type)} price component`)} needs a positive step size!` : void 0;
|
|
6923
6965
|
}
|
|
6924
6966
|
function exactTime(given2, format) {
|
|
6925
6967
|
if (format === "HH:mm") {
|
|
@@ -7066,9 +7108,9 @@ var tariff = (template) => (json) => caught(template ? "a charging tariff templa
|
|
|
7066
7108
|
if (error !== void 0)
|
|
7067
7109
|
return error;
|
|
7068
7110
|
if (!template)
|
|
7069
|
-
raise(givenTwice2(idsAt(json, "templateIds", tariffTemplateId), `
|
|
7070
|
-
raise(givenTwice2(namesAt(json, "paymentMeans"), `
|
|
7071
|
-
raise(givenTwice2(namesAt(json, "paymentBrands"), `
|
|
7111
|
+
raise(givenTwice2(idsAt(json, "templateIds", tariffTemplateId), `template of the ${of}`));
|
|
7112
|
+
raise(givenTwice2(namesAt(json, "paymentMeans"), `payment means of the ${of}`));
|
|
7113
|
+
raise(givenTwice2(namesAt(json, "paymentBrands"), `payment brand of the ${of}`));
|
|
7072
7114
|
return void 0;
|
|
7073
7115
|
});
|
|
7074
7116
|
var chargingTariff = tariff(false);
|
|
@@ -7095,7 +7137,7 @@ function discount(json) {
|
|
|
7095
7137
|
return error;
|
|
7096
7138
|
const value = percent instanceof Decimal ? percent : new Decimal(BigInt(percent), 0);
|
|
7097
7139
|
if (value.mantissa <= 0n || value.compareTo(new Decimal(100n, 0)) > 0)
|
|
7098
|
-
return `The percentage of a discount must be above 0 and at most 100, not ${value
|
|
7140
|
+
return `The percentage of a discount must be above 0 and at most 100, not ${numberText(value)}! (Parameter 'Percent')`;
|
|
7099
7141
|
const dimensions = idsByName(json, "dimensions", "", []);
|
|
7100
7142
|
return new Set(dimensions).size !== dimensions.length ? "A dimension of a discount must not be given twice! (Parameter 'Dimensions')" : void 0;
|
|
7101
7143
|
}
|
|
@@ -7114,11 +7156,11 @@ var chargingTariffOffer = (json) => caught("a charging tariff offer", () => {
|
|
|
7114
7156
|
return error;
|
|
7115
7157
|
if (price === void 0 === (reduction === void 0))
|
|
7116
7158
|
throw thrown(`The charging tariff offer '${id.text}' must have exactly one of a price of its own and a discount!`, "ChargingTariff");
|
|
7117
|
-
raise(givenTwice2(idsAt(json, "EVSEGroupIds", evseGroupId), `
|
|
7118
|
-
raise(givenTwice2(idsAt(json, "chargingStationGroupIds", stationGroupId), `
|
|
7119
|
-
raise(givenTwice2(idsAt(json, "chargingPoolGroupIds", poolGroupId), `
|
|
7120
|
-
raise(givenTwice2(idsAt(json, "chargingStationOperatorIds", operatorId), `
|
|
7121
|
-
raise(givenTwice2(idsAt(json, "eMobilityProviderIds", providerId), `
|
|
7159
|
+
raise(givenTwice2(idsAt(json, "EVSEGroupIds", evseGroupId), `EVSE group of ${owner}`));
|
|
7160
|
+
raise(givenTwice2(idsAt(json, "chargingStationGroupIds", stationGroupId), `charging station group of ${owner}`));
|
|
7161
|
+
raise(givenTwice2(idsAt(json, "chargingPoolGroupIds", poolGroupId), `charging pool group of ${owner}`));
|
|
7162
|
+
raise(givenTwice2(idsAt(json, "chargingStationOperatorIds", operatorId), `charging station operator of ${owner}`));
|
|
7163
|
+
raise(givenTwice2(idsAt(json, "eMobilityProviderIds", providerId), `e-mobility provider of ${owner}`));
|
|
7122
7164
|
if (["EVSEGroupIds", "chargingStationGroupIds", "chargingPoolGroupIds", "chargingStationOperatorIds"].every((property) => idsAt(json, property, freeId).length === 0))
|
|
7123
7165
|
throw thrown(`The charging tariff offer '${id.text}' must name at least one EVSE group, charging station group, charging pool group or charging station operator!`, "EVSEGroupIds");
|
|
7124
7166
|
if (typeof notBefore === "number" && typeof notAfter === "number" && notAfter < notBefore)
|
|
@@ -7134,20 +7176,20 @@ var parkingSpace = (json) => caught("a parking space", () => {
|
|
|
7134
7176
|
if (error !== void 0)
|
|
7135
7177
|
return error;
|
|
7136
7178
|
const of = `the parking space '${id.text}'`;
|
|
7137
|
-
raise(givenTwice2(idsAt(json, "templateIds", freeId), `
|
|
7138
|
-
raise(givenTwice2(idsAt(json, "parkingSensorIds", freeId), `
|
|
7139
|
-
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `
|
|
7140
|
-
raise(givenTwice2(idsAt(json, "parkingProductIds", caseId), `
|
|
7141
|
-
raise(givenTwice2(namesAt(json, "parkingRestrictions"), `
|
|
7142
|
-
raise(givenTwice2(namesAt(json, "euVehicleCategories"), `
|
|
7179
|
+
raise(givenTwice2(idsAt(json, "templateIds", freeId), `template of ${of}`));
|
|
7180
|
+
raise(givenTwice2(idsAt(json, "parkingSensorIds", freeId), `parking sensor of ${of}`));
|
|
7181
|
+
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `charging station of ${of}`));
|
|
7182
|
+
raise(givenTwice2(idsAt(json, "parkingProductIds", caseId), `parking product of ${of}`));
|
|
7183
|
+
raise(givenTwice2(namesAt(json, "parkingRestrictions"), `parking restriction of ${of}`));
|
|
7184
|
+
raise(givenTwice2(namesAt(json, "euVehicleCategories"), `EU vehicle category of ${of}`));
|
|
7143
7185
|
if (notPositive(json, "maxVehicleWeight"))
|
|
7144
7186
|
throw thrown(`The maximum vehicle weight of ${of} must be positive!`, "MaxVehicleWeight");
|
|
7145
7187
|
for (const property of dimensions)
|
|
7146
7188
|
if (notPositive(json, property))
|
|
7147
7189
|
throw thrown(`The ${property} of ${of} must be positive!`, property.charAt(0).toUpperCase() + property.slice(1));
|
|
7148
|
-
raise(givenTwice2(namesAt(json, "vehicleTypes"), `
|
|
7149
|
-
raise(givenTwice2(namesAt(json, "standards"), `
|
|
7150
|
-
raise(givenTwice2(imagesAt(json), `
|
|
7190
|
+
raise(givenTwice2(namesAt(json, "vehicleTypes"), `vehicle type of ${of}`));
|
|
7191
|
+
raise(givenTwice2(namesAt(json, "standards"), `standard of ${of}`));
|
|
7192
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
7151
7193
|
return void 0;
|
|
7152
7194
|
});
|
|
7153
7195
|
var notPositive = (json, property) => {
|
|
@@ -7167,14 +7209,14 @@ var parkingSpaceTemplate = (json) => caught("a parking space template", () => {
|
|
|
7167
7209
|
const of = `the parking space template '${id.text}'`;
|
|
7168
7210
|
if (["maxVehicleWeight", ...dimensions].some((property) => notPositive(json, property)))
|
|
7169
7211
|
throw thrown(`The vehicle limits and dimensions of ${of} must be positive!`);
|
|
7170
|
-
raise(givenTwice2(idsAt(json, "parkingProductIds", caseId), `
|
|
7171
|
-
raise(givenTwice2(idsAt(json, "parkingSensorIds", freeId), `
|
|
7172
|
-
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `
|
|
7173
|
-
raise(givenTwice2(namesAt(json, "parkingRestrictions"), `
|
|
7174
|
-
raise(givenTwice2(namesAt(json, "euVehicleCategories"), `
|
|
7175
|
-
raise(givenTwice2(namesAt(json, "vehicleTypes"), `
|
|
7176
|
-
raise(givenTwice2(namesAt(json, "standards"), `
|
|
7177
|
-
raise(givenTwice2(imagesAt(json), `
|
|
7212
|
+
raise(givenTwice2(idsAt(json, "parkingProductIds", caseId), `parking product of ${of}`));
|
|
7213
|
+
raise(givenTwice2(idsAt(json, "parkingSensorIds", freeId), `parking sensor of ${of}`));
|
|
7214
|
+
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `charging station of ${of}`));
|
|
7215
|
+
raise(givenTwice2(namesAt(json, "parkingRestrictions"), `parking restriction of ${of}`));
|
|
7216
|
+
raise(givenTwice2(namesAt(json, "euVehicleCategories"), `EU vehicle category of ${of}`));
|
|
7217
|
+
raise(givenTwice2(namesAt(json, "vehicleTypes"), `vehicle type of ${of}`));
|
|
7218
|
+
raise(givenTwice2(namesAt(json, "standards"), `standard of ${of}`));
|
|
7219
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
7178
7220
|
return void 0;
|
|
7179
7221
|
});
|
|
7180
7222
|
var parkingGarage = (json) => caught("a parking garage", () => {
|
|
@@ -7185,9 +7227,9 @@ var parkingGarage = (json) => caught("a parking garage", () => {
|
|
|
7185
7227
|
if (error !== void 0)
|
|
7186
7228
|
return error;
|
|
7187
7229
|
const of = `the parking garage '${id.text}'`;
|
|
7188
|
-
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `
|
|
7189
|
-
raise(givenTwice2(imagesAt(json), `
|
|
7190
|
-
raise(givenTwice2(idsAt(json, "parkingProductIds", caseId), `
|
|
7230
|
+
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `charging station of ${of}`));
|
|
7231
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
7232
|
+
raise(givenTwice2(idsAt(json, "parkingProductIds", caseId), `parking product of ${of}`));
|
|
7191
7233
|
return void 0;
|
|
7192
7234
|
});
|
|
7193
7235
|
var parkingSensor = (json) => caught("a parking sensor", () => {
|
|
@@ -7197,7 +7239,7 @@ var parkingSensor = (json) => caught("a parking sensor", () => {
|
|
|
7197
7239
|
const error = i18n(json, "name") ?? i18n(json, "description") ?? text(json, "dataSource", "data source") ?? geoLocationError(json, "geoLocation", "geo location") ?? errorOf(ids(json, "chargingStationIds", "charging station identification", stationId)) ?? metadata(json);
|
|
7198
7240
|
if (error !== void 0)
|
|
7199
7241
|
return error;
|
|
7200
|
-
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `
|
|
7242
|
+
raise(givenTwice2(idsAt(json, "chargingStationIds", stationId), `charging station of the parking sensor '${id.text}'`));
|
|
7201
7243
|
return void 0;
|
|
7202
7244
|
});
|
|
7203
7245
|
var parkingSpaceGroup = (json) => caught("a parking space group", () => {
|
|
@@ -7207,7 +7249,7 @@ var parkingSpaceGroup = (json) => caught("a parking space group", () => {
|
|
|
7207
7249
|
const error = i18n(json, "name") ?? i18n(json, "description") ?? text(json, "dataSource", "data source") ?? errorOf(ids(json, "parkingSpaceIds", "member identification", freeId)) ?? metadata(json);
|
|
7208
7250
|
if (error !== void 0)
|
|
7209
7251
|
return error;
|
|
7210
|
-
raise(givenTwice2(idsAt(json, "parkingSpaceIds", freeId), `
|
|
7252
|
+
raise(givenTwice2(idsAt(json, "parkingSpaceIds", freeId), `member of the parking space group '${id.text}'`));
|
|
7211
7253
|
return void 0;
|
|
7212
7254
|
});
|
|
7213
7255
|
var parkingProduct = (json) => caught("a parking product", () => {
|
|
@@ -7272,8 +7314,8 @@ var model = (meter) => (json) => caught(meter ? "an energy meter model" : "a cha
|
|
|
7272
7314
|
const versions = versionTwice(json, of);
|
|
7273
7315
|
if (versions !== void 0)
|
|
7274
7316
|
throw new Thrown(versions);
|
|
7275
|
-
raise(givenTwice2(imagesAt(json), `
|
|
7276
|
-
raise(givenTwice2(namesAt(json, meter ? "signatureMethods" : "connectorTypes"),
|
|
7317
|
+
raise(givenTwice2(imagesAt(json), `image of ${of}`));
|
|
7318
|
+
raise(givenTwice2(namesAt(json, meter ? "signatureMethods" : "connectorTypes"), `${meter ? "signature method" : "connector type"} of ${of}`));
|
|
7277
7319
|
return void 0;
|
|
7278
7320
|
});
|
|
7279
7321
|
var manufacturer = (meter) => (json) => caught(meter ? "an energy meter manufacturer" : "a charging station manufacturer", () => {
|
|
@@ -7465,7 +7507,7 @@ var gridConnectionPoint = (json) => caught("a grid connection point", () => {
|
|
|
7465
7507
|
return error;
|
|
7466
7508
|
const of = `the grid connection point '${id.text}'`;
|
|
7467
7509
|
if (isObject(by2) && by2["entityType"] !== "ChargingStationOperator" && by2["entityType"] !== "ParkingOperator")
|
|
7468
|
-
throw thrown(`
|
|
7510
|
+
throw thrown(`Besides its grid operator, the grid connection point '${id.text}' can only be maintained by a charging station operator or a parking operator, not by ${partyText(by2)}!`);
|
|
7469
7511
|
if (["nominalVoltage", "nominalFrequency"].some((property) => notPositive(json, property)))
|
|
7470
7512
|
throw thrown(`The nominal voltage and frequency of ${of} must be positive!`);
|
|
7471
7513
|
const contracted = powers.map(([property]) => optionalDecimal2(json, property, property));
|
|
@@ -7579,7 +7621,7 @@ var chargingStationOperator = (of) => (json) => caught("a charging station opera
|
|
|
7579
7621
|
if (id instanceof Refused)
|
|
7580
7622
|
return id.error;
|
|
7581
7623
|
const merchant = get(json, "evTaler");
|
|
7582
|
-
const error = i18n(json, "name") ?? i18n(json, "description") ?? styxText(json, "dataSource", "data source") ?? dataLicenses(json) ?? addressError(json, "address", "address") ?? geoLocationError(json, "geoLocation", "geo location") ?? operatorLogos(json) ?? textError(json, "telephone", "telephone number", phoneNumber) ?? eMailAddressError(json, "eMailAddress", "e-mail address") ?? textError(json, "homepage", "homepage", url) ?? textError(json, "hotline", "hotline phone number", phoneNumber) ?? textError(json, "termsAndConditions", "terms and conditions URL", url) ?? (merchant === void 0 ? void 0 : (() => {
|
|
7624
|
+
const error = i18n(json, "name") ?? i18n(json, "description") ?? styxText(json, "dataSource", "data source") ?? dataLicenses(json) ?? addressError(json, "address", "address") ?? geoLocationError(json, "geoLocation", "geo location") ?? operatorLogos(json) ?? textError(json, "telephone", "telephone number", phoneNumber) ?? eMailAddressError(json, "eMailAddress", "e-mail address") ?? textError(json, "homepage", "homepage", url) ?? textError(json, "hotline", "hotline phone number", phoneNumber) ?? textError(json, "termsAndConditions", "terms and conditions URL", url) ?? textError(json, "webPaymentURL", "web payment URL", url) ?? (merchant === void 0 ? void 0 : (() => {
|
|
7583
7625
|
const read = evTalerMerchantOf(merchant);
|
|
7584
7626
|
return typeof read === "string" ? read : void 0;
|
|
7585
7627
|
})()) ?? children(json, "chargingPools", "chargingPoolIds", "charging pools", chargingPool) ?? children(json, "EVSEGroups", "EVSEGroupIds", "EVSEGroups", group(EVSE_GROUP)) ?? children(json, "chargingStationGroups", "chargingStationGroupIds", "ChargingStationGroups", group(CHARGING_STATION_GROUP)) ?? children(json, "chargingPoolGroups", "chargingPoolGroupIds", "ChargingPoolGroups", group(CHARGING_POOL_GROUP)) ?? children(json, "chargingTariffGroups", "chargingTariffGroupIds", "ChargingTariffGroups", group(CHARGING_TARIFF_GROUP)) ?? energyMeterGroups(json) ?? children(json, "EVSETemplates", "EVSETemplateIds", "EVSE templates", evseTemplate) ?? children(json, "chargingStationTemplates", "chargingStationTemplateIds", "charging station templates", chargingStationTemplate) ?? children(json, "chargingPoolTemplates", "chargingPoolTemplateIds", "charging pool templates", chargingPoolTemplate) ?? children(json, "chargingTariffTemplates", "chargingTariffTemplateIds", "charging tariff templates", chargingTariffTemplate) ?? energyMeterTemplates(json) ?? children(json, "parkingSpaces", "parkingSpaceIds", "parking spaces", parkingSpace) ?? children(json, "chargingTariffOffers", "chargingTariffOfferIds", "charging tariff offers", chargingTariffOffer) ?? children(json, "brands", "brandIds", "brands", brand) ?? children(json, "chargingTariffs", "chargingTariffIds", "charging tariffs", chargingTariff) ?? keysError(json) ?? metadata(json);
|
|
@@ -7628,6 +7670,37 @@ function invalidReading(content, of = "version") {
|
|
|
7628
7670
|
throw e;
|
|
7629
7671
|
}
|
|
7630
7672
|
}
|
|
7673
|
+
var PARTY_READERS = {
|
|
7674
|
+
ChargingStationManufacturer: manufacturer(false),
|
|
7675
|
+
EMobilityProvider: eMobilityProvider,
|
|
7676
|
+
GridOperator: gridOperator,
|
|
7677
|
+
ParkingOperator: parkingOperator,
|
|
7678
|
+
TransparencySoftwareManufacturer: softwareManufacturer,
|
|
7679
|
+
ConformityAssessmentBody: conformityAssessmentBody,
|
|
7680
|
+
EnergyMeterManufacturer: manufacturer(true),
|
|
7681
|
+
ChargingStationOperator: chargingStationOperator("change set")
|
|
7682
|
+
};
|
|
7683
|
+
function invalidParty(type, json) {
|
|
7684
|
+
try {
|
|
7685
|
+
return PARTY_READERS[type]?.(json);
|
|
7686
|
+
} catch (e) {
|
|
7687
|
+
if (e instanceof Thrown)
|
|
7688
|
+
return `The given JSON representation of a roaming network is invalid: ${e.message}`;
|
|
7689
|
+
throw e;
|
|
7690
|
+
}
|
|
7691
|
+
}
|
|
7692
|
+
function invalidTreeHashAlgorithms(value) {
|
|
7693
|
+
if (!isArray(value))
|
|
7694
|
+
return "The 'treeHashAlgorithms' must be a JSON array of hash algorithms!";
|
|
7695
|
+
const unknown = value.find((algorithm) => !isHashAlgorithm(algorithm));
|
|
7696
|
+
if (unknown !== void 0)
|
|
7697
|
+
return `Unknown tree hash algorithm '${asText(unknown)}': sha256, sha384 or sha512!`;
|
|
7698
|
+
if (value.length === 0)
|
|
7699
|
+
return "The 'treeHashAlgorithms' must name at least one hash algorithm!";
|
|
7700
|
+
if (new Set(value).size !== value.length)
|
|
7701
|
+
return "The 'treeHashAlgorithms' must not name a hash algorithm twice!";
|
|
7702
|
+
return void 0;
|
|
7703
|
+
}
|
|
7631
7704
|
|
|
7632
7705
|
// src/network/writtenForm.ts
|
|
7633
7706
|
var idOf4 = (value) => isObject(value) && typeof value["@id"] === "string" ? value["@id"] : "";
|
|
@@ -7666,6 +7739,7 @@ var ORDERED_TEXTS = /* @__PURE__ */ new Set([
|
|
|
7666
7739
|
"verifiedTransparencySoftwareIds",
|
|
7667
7740
|
"compatibleTransparencySoftwareIds",
|
|
7668
7741
|
"cardTypes",
|
|
7742
|
+
"channels",
|
|
7669
7743
|
"dimensions",
|
|
7670
7744
|
"usages"
|
|
7671
7745
|
]);
|
|
@@ -7676,6 +7750,7 @@ var LEFT_OUT_WHEN_EMPTY = /* @__PURE__ */ new Set([
|
|
|
7676
7750
|
"cardTypes",
|
|
7677
7751
|
"certificateIds",
|
|
7678
7752
|
"certificates",
|
|
7753
|
+
"channels",
|
|
7679
7754
|
"chargingConnectors",
|
|
7680
7755
|
"chargingPoolGroupIds",
|
|
7681
7756
|
"chargingPoolGroups",
|
|
@@ -7757,8 +7832,13 @@ var LEFT_OUT_WHEN_EMPTY = /* @__PURE__ */ new Set([
|
|
|
7757
7832
|
"vehicleTypes",
|
|
7758
7833
|
"regularOpenings",
|
|
7759
7834
|
"exceptionalOpenings",
|
|
7760
|
-
"exceptionalClosings"
|
|
7835
|
+
"exceptionalClosings",
|
|
7836
|
+
"dataLicenses"
|
|
7761
7837
|
]);
|
|
7838
|
+
var FLAGS = {
|
|
7839
|
+
currentTypes: ["AC_OnePhase", "AC_ThreePhases", "DC"],
|
|
7840
|
+
chargingModes: ["Mode_1", "Mode_2", "Mode_3", "Mode_4", "CHAdeMO"]
|
|
7841
|
+
};
|
|
7762
7842
|
var LEFT_OUT_WHEN_EMPTY_TEXT = {
|
|
7763
7843
|
"": ["dataSource"],
|
|
7764
7844
|
chargingStationOperators: ["dataSource"],
|
|
@@ -7886,7 +7966,8 @@ var ENTITY_PROPERTIES = {
|
|
|
7886
7966
|
"stackTrace",
|
|
7887
7967
|
"telephone",
|
|
7888
7968
|
"termsAndConditions",
|
|
7889
|
-
"uri"
|
|
7969
|
+
"uri",
|
|
7970
|
+
"webPaymentURL"
|
|
7890
7971
|
],
|
|
7891
7972
|
"eMobilityProviders": [
|
|
7892
7973
|
"@context",
|
|
@@ -8191,7 +8272,8 @@ var ENTITY_PROPERTIES = {
|
|
|
8191
8272
|
"standards",
|
|
8192
8273
|
"templateIds",
|
|
8193
8274
|
"timeZone",
|
|
8194
|
-
"uiFeatures"
|
|
8275
|
+
"uiFeatures",
|
|
8276
|
+
"webPaymentURL"
|
|
8195
8277
|
],
|
|
8196
8278
|
"chargingPoolTemplates": [
|
|
8197
8279
|
"@context",
|
|
@@ -8234,7 +8316,8 @@ var ENTITY_PROPERTIES = {
|
|
|
8234
8316
|
"services",
|
|
8235
8317
|
"standards",
|
|
8236
8318
|
"timeZone",
|
|
8237
|
-
"uiFeatures"
|
|
8319
|
+
"uiFeatures",
|
|
8320
|
+
"webPaymentURL"
|
|
8238
8321
|
],
|
|
8239
8322
|
"chargingPoolGroups": [
|
|
8240
8323
|
"@context",
|
|
@@ -8286,7 +8369,8 @@ var ENTITY_PROPERTIES = {
|
|
|
8286
8369
|
"signatureMethods",
|
|
8287
8370
|
"templateIds",
|
|
8288
8371
|
"transparencySoftwareStatus",
|
|
8289
|
-
"vehicleTypes"
|
|
8372
|
+
"vehicleTypes",
|
|
8373
|
+
"webPaymentURL"
|
|
8290
8374
|
],
|
|
8291
8375
|
"chargingStationTemplates": [
|
|
8292
8376
|
"@context",
|
|
@@ -8321,7 +8405,8 @@ var ENTITY_PROPERTIES = {
|
|
|
8321
8405
|
"physicalReference",
|
|
8322
8406
|
"signatureMethods",
|
|
8323
8407
|
"transparencySoftwareStatus",
|
|
8324
|
-
"vehicleTypes"
|
|
8408
|
+
"vehicleTypes",
|
|
8409
|
+
"webPaymentURL"
|
|
8325
8410
|
],
|
|
8326
8411
|
"chargingStationGroups": [
|
|
8327
8412
|
"@context",
|
|
@@ -8656,7 +8741,7 @@ var PROPERTIES_OF = {
|
|
|
8656
8741
|
keyStatement: ["@context", "roamingNetworkId", "roamingNetworkOperatorId", "identityKeys", "minConsensus", "signedAt", "validUntil", "signatures"],
|
|
8657
8742
|
signatures: ["algorithm", "keyId", "value"],
|
|
8658
8743
|
signingKeyCertificates: ["@context", "roamingNetworkOperatorId", "signingKey", "signedAt", "algorithm", "keyId", "value"],
|
|
8659
|
-
evTaler: ["@context", "merchantBaseURL", "merchantPublicKey", "exchanges"],
|
|
8744
|
+
evTaler: ["@context", "merchantBaseURL", "merchantPublicKey", "exchanges", "offersURL"],
|
|
8660
8745
|
exchanges: ["@context", "masterPublicKey", "baseURL", "currency", "name"]
|
|
8661
8746
|
};
|
|
8662
8747
|
var PROPERTY_SETS = new Map(Object.entries(PROPERTIES_OF).map(([kind, properties]) => [kind, new Set(properties)]));
|
|
@@ -8669,6 +8754,7 @@ var TRIMMED = /* @__PURE__ */ new Set([
|
|
|
8669
8754
|
"transparencySoftwareId",
|
|
8670
8755
|
"version",
|
|
8671
8756
|
"vulnerabilityContact",
|
|
8757
|
+
"hotline",
|
|
8672
8758
|
"energyMeterManufacturerId",
|
|
8673
8759
|
"energyMeterModel",
|
|
8674
8760
|
"roamingNetworkId",
|
|
@@ -8757,8 +8843,8 @@ function writtenText(property, text2) {
|
|
|
8757
8843
|
return LANGUAGES.has(text2.toLowerCase()) ? text2.toLowerCase() : text2;
|
|
8758
8844
|
if (property === "exceptionalOpenings" || property === "exceptionalClosings")
|
|
8759
8845
|
return periodOf(text2) ?? text2;
|
|
8760
|
-
const
|
|
8761
|
-
return
|
|
8846
|
+
const names2 = NAMED_VALUES[property];
|
|
8847
|
+
return names2?.find((name) => name.toLowerCase() === trimmed(text2).toLowerCase()) ?? trimmed(text2);
|
|
8762
8848
|
}
|
|
8763
8849
|
function writtenTexts(items, property) {
|
|
8764
8850
|
const texts3 = items.map((item) => typeof item === "string" ? writtenText(property, item) : void 0);
|
|
@@ -8767,7 +8853,16 @@ function writtenTexts(items, property) {
|
|
|
8767
8853
|
const written2 = texts3;
|
|
8768
8854
|
return ORDERED_TEXTS.has(property) ? [...written2].sort(ordinal) : written2;
|
|
8769
8855
|
}
|
|
8770
|
-
var URLS = /* @__PURE__ */ new Set([
|
|
8856
|
+
var URLS = /* @__PURE__ */ new Set([
|
|
8857
|
+
"homepage",
|
|
8858
|
+
"datasheetURL",
|
|
8859
|
+
"vulnerabilityReporting",
|
|
8860
|
+
"vulnerabilityDisclosurePolicy",
|
|
8861
|
+
"securityAdvisories",
|
|
8862
|
+
"merchantBaseURL",
|
|
8863
|
+
"baseURL",
|
|
8864
|
+
"offersURL"
|
|
8865
|
+
]);
|
|
8771
8866
|
var NAMED_VALUES = {
|
|
8772
8867
|
role: ["battery", "evse", "grid", "gridConnectionPoint", "pool", "pv", "station", "wind"],
|
|
8773
8868
|
legalStatus: ["forInformationOnly", "germanCalibrationLaw", "verified"],
|
|
@@ -8787,13 +8882,26 @@ function orderKeys(items, property) {
|
|
|
8787
8882
|
return items.map((item) => isObject(item) ? asText(item["masterPublicKey"]) : "");
|
|
8788
8883
|
if (property === "daysOfWeek")
|
|
8789
8884
|
return items.map((item) => String(DAYS_OF_WEEK2.indexOf(typeof item === "string" ? item : "")).padStart(2, "0"));
|
|
8885
|
+
const flags2 = property === void 0 ? void 0 : FLAGS[property];
|
|
8886
|
+
if (flags2 !== void 0)
|
|
8887
|
+
return items.map((item) => String(flags2.indexOf(typeof item === "string" ? item : "")).padStart(2, "0"));
|
|
8790
8888
|
if (items.length > 0 && items.every((item) => isObject(item) && typeof item["@id"] === "string"))
|
|
8791
8889
|
return items.map(idOf4);
|
|
8792
8890
|
if (property !== void 0 && ORDERED_TEXTS.has(property) && items.every((item) => typeof item === "string"))
|
|
8793
8891
|
return items.map((item) => typeof item === "string" ? item : "");
|
|
8794
8892
|
return void 0;
|
|
8795
8893
|
}
|
|
8796
|
-
var
|
|
8894
|
+
var LANGUAGE_NAMES = [...LANGUAGES];
|
|
8895
|
+
function languageOf(language) {
|
|
8896
|
+
if (LANGUAGES.has(language.toLowerCase()))
|
|
8897
|
+
return language.toLowerCase();
|
|
8898
|
+
if (!/^[+-]?\d+$/u.test(language))
|
|
8899
|
+
return void 0;
|
|
8900
|
+
const number = Number(language);
|
|
8901
|
+
return number >= 0 && number < LANGUAGE_NAMES.length ? LANGUAGE_NAMES[number] : String(number);
|
|
8902
|
+
}
|
|
8903
|
+
var textsOf2 = (text2) => Object.fromEntries(Object.entries(text2).filter(([, value]) => typeof value === "string").map(([language, value]) => [languageOf(language), value]).filter((entry) => entry[0] !== void 0));
|
|
8904
|
+
var languagesOf2 = (text2) => Object.keys(textsOf2(text2));
|
|
8797
8905
|
function writtenValueOf(property, value, holder) {
|
|
8798
8906
|
if ((property === "@id" || property === "type" && holder === "chargingConnectors") && (typeof value === "number" || typeof value === "boolean"))
|
|
8799
8907
|
return String(value);
|
|
@@ -8806,9 +8914,9 @@ function writtenValueOf(property, value, holder) {
|
|
|
8806
8914
|
return trimmed(value);
|
|
8807
8915
|
if (URLS.has(property))
|
|
8808
8916
|
return hermodURL(value)?.text;
|
|
8809
|
-
const
|
|
8810
|
-
if (
|
|
8811
|
-
return
|
|
8917
|
+
const names2 = NAMED_VALUES[property];
|
|
8918
|
+
if (names2 !== void 0)
|
|
8919
|
+
return names2.find((name) => name.toLowerCase() === trimmed(value).toLowerCase()) ?? trimmed(value);
|
|
8812
8920
|
}
|
|
8813
8921
|
if (holder === "geoLocation" && (property === "lat" || property === "lng" || property === "alt")) {
|
|
8814
8922
|
const number = isNumber(value) ? Number(canonicalJSON(value)) : typeof value === "string" || typeof value === "boolean" ? doubleOf(value) : void 0;
|
|
@@ -8838,7 +8946,7 @@ function writtenValueOf(property, value, holder) {
|
|
|
8838
8946
|
return valueText(value) ?? void 0;
|
|
8839
8947
|
return void 0;
|
|
8840
8948
|
}
|
|
8841
|
-
var contentText = (value) => typeof value === "number" && !Number.isSafeInteger(value) ? String(value) : canonicalJSON(value);
|
|
8949
|
+
var contentText = (value) => value === void 0 ? "absent" : typeof value === "number" && !Number.isSafeInteger(value) ? String(value) : canonicalJSON(value);
|
|
8842
8950
|
function asRead(value, kind) {
|
|
8843
8951
|
if (isArray(value))
|
|
8844
8952
|
return value.map((element) => asRead(element, kind));
|
|
@@ -8847,10 +8955,23 @@ function asRead(value, kind) {
|
|
|
8847
8955
|
const known = PROPERTIES_OF[kind];
|
|
8848
8956
|
return Object.fromEntries(Object.entries(value).filter(([key2]) => known === void 0 || known.includes(key2)).map(([key2, element]) => [key2, PROPERTIES_OF[key2] === void 0 ? element : asRead(element, key2)]));
|
|
8849
8957
|
}
|
|
8958
|
+
function heldNumber(value) {
|
|
8959
|
+
if (typeof value !== "number" || Number.isSafeInteger(value))
|
|
8960
|
+
return value;
|
|
8961
|
+
try {
|
|
8962
|
+
return Decimal.parse(String(value));
|
|
8963
|
+
} catch {
|
|
8964
|
+
return void 0;
|
|
8965
|
+
}
|
|
8966
|
+
}
|
|
8850
8967
|
function notWritten(value, property, path, of) {
|
|
8851
8968
|
const eachOnce = of === "new value";
|
|
8852
8969
|
const join2 = (at, key2) => at === "" ? key2 : `${at}.${key2}`;
|
|
8853
|
-
const
|
|
8970
|
+
const heldAt = (place, held) => ({ at: place, value: held });
|
|
8971
|
+
const holdsAs = (at, place, written2) => {
|
|
8972
|
+
const held = heldNumber(written2);
|
|
8973
|
+
return { path: at, reason: `the content holds it as '${contentText(written2)}'`, ...held === void 0 ? {} : { held: heldAt(place, held) } };
|
|
8974
|
+
};
|
|
8854
8975
|
const leftOut = (key2, element, kind, keepsEmptyName) => {
|
|
8855
8976
|
if (element === null)
|
|
8856
8977
|
return "a property without a value is left out";
|
|
@@ -8869,22 +8990,53 @@ function notWritten(value, property, path, of) {
|
|
|
8869
8990
|
return "the content leaves it out";
|
|
8870
8991
|
return void 0;
|
|
8871
8992
|
};
|
|
8872
|
-
const
|
|
8993
|
+
const writtenOtherwise = (key2, element, kind, at, place) => {
|
|
8994
|
+
if (typeof element === "string" && TIMESTAMP_PROPERTIES.has(key2) && !TIMESTAMP4.test(element)) {
|
|
8995
|
+
const time = timestampOf(element);
|
|
8996
|
+
return {
|
|
8997
|
+
path: at,
|
|
8998
|
+
reason: "a timestamp is UTC to the millisecond, yyyy-MM-ddTHH:mm:ss.fffZ",
|
|
8999
|
+
...time === void 0 ? {} : { held: heldAt(place, toTimestamp(time)) }
|
|
9000
|
+
};
|
|
9001
|
+
}
|
|
9002
|
+
const written2 = key2 === "customData" ? void 0 : writtenValueOf(key2, element, kind);
|
|
9003
|
+
if (written2 !== void 0 && (typeof written2 === "string" && typeof element === "string" ? written2 !== element : contentText(written2) !== contentText(element)))
|
|
9004
|
+
return holdsAs(at, place, written2);
|
|
9005
|
+
return void 0;
|
|
9006
|
+
};
|
|
9007
|
+
const check2 = (item, name, holder, at, place, root = false) => {
|
|
8873
9008
|
if (name === "customData")
|
|
8874
9009
|
return void 0;
|
|
8875
9010
|
if (isArray(item)) {
|
|
8876
9011
|
const written2 = name === void 0 ? void 0 : writtenTexts(item, name);
|
|
8877
9012
|
const differs = written2?.findIndex((text2, index) => text2 !== item[index]) ?? -1;
|
|
8878
9013
|
if (written2 !== void 0 && differs >= 0)
|
|
8879
|
-
return holdsAs(`${at}[${String(differs)}]`, written2[differs] ?? "");
|
|
9014
|
+
return { ...holdsAs(`${at}[${String(differs)}]`, place, written2[differs] ?? ""), held: heldAt(place, written2) };
|
|
8880
9015
|
if (name !== void 0 && ORDERED_TEXTS.has(name) && item.some((element) => typeof element === "string" && trimmed(element) !== element))
|
|
8881
|
-
return {
|
|
9016
|
+
return {
|
|
9017
|
+
path: at,
|
|
9018
|
+
reason: "the texts of its elements are trimmed",
|
|
9019
|
+
held: heldAt(place, item.map((element) => typeof element === "string" ? trimmed(element) : element))
|
|
9020
|
+
};
|
|
8882
9021
|
const keys = orderKeys(item, name);
|
|
8883
|
-
if (keys?.some((key2, index) => index > 0 && ordinal(keys[index - 1] ?? "", key2) >= (eachOnce ? 0 : 1)) === true)
|
|
8884
|
-
|
|
9022
|
+
if (keys?.some((key2, index) => index > 0 && ordinal(keys[index - 1] ?? "", key2) >= (eachOnce ? 0 : 1)) === true) {
|
|
9023
|
+
const seen = /* @__PURE__ */ new Set();
|
|
9024
|
+
const firsts = ({ key: key2 }) => {
|
|
9025
|
+
if (seen.has(key2))
|
|
9026
|
+
return false;
|
|
9027
|
+
seen.add(key2);
|
|
9028
|
+
return true;
|
|
9029
|
+
};
|
|
9030
|
+
const ordered2 = keys.map((key2, index) => ({ key: key2, index })).sort((left, right) => ordinal(left.key, right.key) || left.index - right.index).filter((entry) => !eachOnce || firsts(entry)).map(({ index }) => item[index] ?? null);
|
|
9031
|
+
return {
|
|
9032
|
+
path: at,
|
|
9033
|
+
reason: eachOnce ? "its elements are in the order the content holds them in, each once" : "its elements are in the order the content holds them in",
|
|
9034
|
+
held: heldAt(place, ordered2)
|
|
9035
|
+
};
|
|
9036
|
+
}
|
|
8885
9037
|
for (const [index, element] of item.entries()) {
|
|
8886
9038
|
const elementAt = `${at}[${String(index)}]`;
|
|
8887
|
-
const found = check2(element, void 0, name, elementAt);
|
|
9039
|
+
const found = check2(element, void 0, name, elementAt, [...place, index]);
|
|
8888
9040
|
if (found !== void 0)
|
|
8889
9041
|
return found;
|
|
8890
9042
|
}
|
|
@@ -8895,44 +9047,75 @@ function notWritten(value, property, path, of) {
|
|
|
8895
9047
|
const party = name === void 0 && holder !== void 0 ? PARTY_NAMES[holder] : void 0;
|
|
8896
9048
|
const keepsEmptyName = name === void 0 && holder === "chargingStationOperators";
|
|
8897
9049
|
if (name !== void 0 && TEXTS_IN_LANGUAGES.has(name) && [...Object.keys(item)].sort(ordinal).join("\0") !== languagesOf2(item).sort(ordinal).join("\0"))
|
|
8898
|
-
return {
|
|
9050
|
+
return {
|
|
9051
|
+
path: at,
|
|
9052
|
+
reason: "a text in languages names each language as Styx writes it, in lower case, with a text",
|
|
9053
|
+
held: heldAt(place, textsOf2(item))
|
|
9054
|
+
};
|
|
8899
9055
|
for (const [key2, element] of Object.entries(item)) {
|
|
8900
9056
|
if (key2 === "@context") {
|
|
8901
9057
|
if (root)
|
|
8902
9058
|
continue;
|
|
8903
|
-
return { path: at, reason: "embedded, an object names no JSON-LD context" };
|
|
9059
|
+
return { path: at, reason: "embedded, an object names no JSON-LD context", held: heldAt([...place, key2], void 0) };
|
|
8904
9060
|
}
|
|
8905
9061
|
const elementAt = join2(at, key2);
|
|
9062
|
+
const elementPlace = [...place, key2];
|
|
8906
9063
|
const omitted2 = leftOut(key2, element, kind, keepsEmptyName);
|
|
8907
9064
|
if (omitted2 !== void 0)
|
|
8908
|
-
return { path: elementAt, reason: omitted2 };
|
|
8909
|
-
|
|
8910
|
-
return { path: elementAt, reason: "a timestamp is UTC to the millisecond, yyyy-MM-ddTHH:mm:ss.fffZ" };
|
|
8911
|
-
const written2 = key2 === "customData" ? void 0 : writtenValueOf(key2, element, kind);
|
|
8912
|
-
if (written2 !== void 0 && (typeof written2 === "string" && typeof element === "string" ? written2 !== element : contentText(written2) !== contentText(element)))
|
|
8913
|
-
return holdsAs(elementAt, written2);
|
|
8914
|
-
const found = check2(element, key2, kind, elementAt);
|
|
9065
|
+
return { path: elementAt, reason: omitted2, held: heldAt(elementPlace, void 0) };
|
|
9066
|
+
const found = writtenOtherwise(key2, element, kind, elementAt, elementPlace) ?? check2(element, key2, kind, elementAt, elementPlace);
|
|
8915
9067
|
if (found !== void 0)
|
|
8916
9068
|
return found;
|
|
8917
9069
|
}
|
|
8918
9070
|
if (party !== void 0 && !("name" in item))
|
|
8919
|
-
return holdsAs(join2(at, "name"), { en: `${party} '${asText(writtenValueOf("@id", item["@id"] ?? "", holder) ?? item["@id"])}'` });
|
|
9071
|
+
return holdsAs(join2(at, "name"), [...place, "name"], { en: `${party} '${asText(writtenValueOf("@id", item["@id"] ?? "", holder) ?? item["@id"])}'` });
|
|
8920
9072
|
for (const list of name === void 0 && holder !== void 0 ? WRITTEN_ALSO_EMPTY[holder] ?? [] : [])
|
|
8921
9073
|
if (!(list in item))
|
|
8922
|
-
return holdsAs(join2(at, list), []);
|
|
9074
|
+
return holdsAs(join2(at, list), [...place, list], []);
|
|
8923
9075
|
if (!eachOnce && typeof item["created"] === "string" && !("lastChange" in item))
|
|
8924
|
-
return holdsAs(join2(at, "lastChange"), item["created"]);
|
|
9076
|
+
return holdsAs(join2(at, "lastChange"), [...place, "lastChange"], item["created"]);
|
|
8925
9077
|
if (kind === "openingTimes" && !("24/7" in item)) {
|
|
8926
9078
|
const regular = item["regularOpenings"];
|
|
8927
|
-
return holdsAs(join2(at, "24/7"), !(isArray(regular) && regular.length > 0));
|
|
9079
|
+
return holdsAs(join2(at, "24/7"), [...place, "24/7"], !(isArray(regular) && regular.length > 0));
|
|
8928
9080
|
}
|
|
8929
9081
|
}
|
|
8930
9082
|
return void 0;
|
|
8931
9083
|
};
|
|
8932
9084
|
const omitted = property === void 0 ? void 0 : leftOut(property, value, void 0, false);
|
|
8933
9085
|
if (omitted !== void 0)
|
|
8934
|
-
return { path, reason: omitted };
|
|
8935
|
-
return check2(value, property, void 0, path, of === "version" && property === void 0);
|
|
9086
|
+
return { path, reason: omitted, held: heldAt([], void 0) };
|
|
9087
|
+
return (property === void 0 ? void 0 : writtenOtherwise(property, value, void 0, path, [])) ?? check2(value, property, void 0, path, [], of === "version" && property === void 0);
|
|
9088
|
+
}
|
|
9089
|
+
function heldAs(value, property) {
|
|
9090
|
+
let held = clone(value);
|
|
9091
|
+
for (let round = 0; round < 1e3; round++) {
|
|
9092
|
+
const found = notWritten(held, property, property ?? "", "new value");
|
|
9093
|
+
if (found === void 0)
|
|
9094
|
+
return { value: held };
|
|
9095
|
+
if (found.held === void 0)
|
|
9096
|
+
return void 0;
|
|
9097
|
+
const next = placed(held, found.held.at, found.held.value);
|
|
9098
|
+
if (next === void 0)
|
|
9099
|
+
return { value: void 0 };
|
|
9100
|
+
held = next;
|
|
9101
|
+
}
|
|
9102
|
+
return void 0;
|
|
9103
|
+
}
|
|
9104
|
+
function placed(value, at, held) {
|
|
9105
|
+
const [first2, ...rest] = at;
|
|
9106
|
+
if (first2 === void 0)
|
|
9107
|
+
return held;
|
|
9108
|
+
if (isArray(value) && typeof first2 === "number") {
|
|
9109
|
+
const element = value[first2];
|
|
9110
|
+
const inner = element === void 0 ? held : placed(element, rest, held);
|
|
9111
|
+
return inner === void 0 ? value.filter((_, index) => index !== first2) : value.map((item, index) => index === first2 ? inner : item);
|
|
9112
|
+
}
|
|
9113
|
+
if (isObject(value) && typeof first2 === "string") {
|
|
9114
|
+
const element = value[first2];
|
|
9115
|
+
const inner = element === void 0 || rest.length === 0 ? held : placed(element, rest, held);
|
|
9116
|
+
return inner === void 0 ? without(value, first2) : { ...value, [first2]: inner };
|
|
9117
|
+
}
|
|
9118
|
+
return value;
|
|
8936
9119
|
}
|
|
8937
9120
|
function notWrittenAsHeld(content) {
|
|
8938
9121
|
const found = notWritten(content, void 0, "", "version");
|
|
@@ -9173,13 +9356,17 @@ var KeyStatement = class _KeyStatement {
|
|
|
9173
9356
|
return { algorithm, keyId, value: value2 };
|
|
9174
9357
|
});
|
|
9175
9358
|
onlyProperties(json, ["@context", "roamingNetworkId", "roamingNetworkOperatorId", "identityKeys", "minConsensus", "signedAt", "validUntil", "signatures"], "A key statement");
|
|
9359
|
+
if (new Set(identityKeys.map((key2) => key2.id)).size !== identityKeys.length)
|
|
9360
|
+
throw new POIError("Invalid key statement: An identity key of a key statement must not be given twice!");
|
|
9176
9361
|
if (identityKeys.some((key2, index) => {
|
|
9177
9362
|
const before = identityKeys[index - 1];
|
|
9178
9363
|
return before !== void 0 && before.id >= key2.id;
|
|
9179
9364
|
}))
|
|
9180
9365
|
throw new POIError("The identity keys of a key statement are written in the order of their @ids!");
|
|
9181
9366
|
if (validUntil < signedAt)
|
|
9182
|
-
throw new POIError("A key statement is not valid until before it was signed
|
|
9367
|
+
throw new POIError("Invalid key statement: A key statement is not valid until before it was signed. (Parameter 'ValidUntil')");
|
|
9368
|
+
if (new Set(signatures.map((signature) => signature.keyId)).size !== signatures.length)
|
|
9369
|
+
throw new POIError("Invalid key statement: An identity key signs a key statement once. (Parameter 'Signatures')");
|
|
9183
9370
|
return new _KeyStatement(roamingNetworkId, roamingNetworkOperatorId, identityKeys, minConsensus, signedAt, validUntil, signatures, json);
|
|
9184
9371
|
}
|
|
9185
9372
|
/** The statement as it is signed: without `signatures`, with its `@context`, keys embedded without theirs. */
|
|
@@ -9428,12 +9615,12 @@ var RoamingNetworkOperator = class _RoamingNetworkOperator {
|
|
|
9428
9615
|
const invalid = (error) => new POIError(`The given JSON representation of a roaming network operator is invalid: ${error}`);
|
|
9429
9616
|
const certifications = certificates.map((certificate) => `${certificate.signingKey.id}/${certificate.keyId}`);
|
|
9430
9617
|
if (new Set(certifications).size !== certifications.length)
|
|
9431
|
-
throw invalid(`
|
|
9618
|
+
throw invalid(`A certificate of a signing key of the roaming network operator '${id}' must not be given twice!`);
|
|
9432
9619
|
const certified = /* @__PURE__ */ new Map();
|
|
9433
9620
|
for (const certificate of certificates) {
|
|
9434
9621
|
const before = certified.get(certificate.signingKey.id);
|
|
9435
9622
|
if (before !== void 0 && !sameValue(without(before.json, "@context"), without(asRead(certificate.signingKey.json, "signingKey"), "@context")))
|
|
9436
|
-
throw invalid(`
|
|
9623
|
+
throw invalid(`A signing key of the roaming network operator '${id}' must not be given twice!`);
|
|
9437
9624
|
certified.set(certificate.signingKey.id, certificate.signingKey);
|
|
9438
9625
|
}
|
|
9439
9626
|
const signingKeys = [...certified.values()];
|
|
@@ -9483,6 +9670,18 @@ var RoamingNetworkOperator = class _RoamingNetworkOperator {
|
|
|
9483
9670
|
return new _RoamingNetworkOperator(id, identityKeys, minConsensus, keyStatement, certificates, json);
|
|
9484
9671
|
}
|
|
9485
9672
|
};
|
|
9673
|
+
function invalidRoamingNetworkOperator(json, roamingNetworkId) {
|
|
9674
|
+
try {
|
|
9675
|
+
RoamingNetworkOperator.parse(json, roamingNetworkId);
|
|
9676
|
+
return void 0;
|
|
9677
|
+
} catch (e) {
|
|
9678
|
+
if (e instanceof KeyStatementError)
|
|
9679
|
+
return void 0;
|
|
9680
|
+
if (e instanceof POIError)
|
|
9681
|
+
return e.message;
|
|
9682
|
+
throw e;
|
|
9683
|
+
}
|
|
9684
|
+
}
|
|
9486
9685
|
var RoamingNetwork = class _RoamingNetwork {
|
|
9487
9686
|
constructor(id, content, operator, treeHashAlgorithms) {
|
|
9488
9687
|
this.id = id;
|
|
@@ -9530,15 +9729,9 @@ var RoamingNetwork = class _RoamingNetwork {
|
|
|
9530
9729
|
let treeHashAlgorithms = ["sha256"];
|
|
9531
9730
|
const treeHashAlgorithmsJSON = get(json, "treeHashAlgorithms");
|
|
9532
9731
|
if (treeHashAlgorithmsJSON !== void 0) {
|
|
9533
|
-
|
|
9534
|
-
|
|
9535
|
-
|
|
9536
|
-
if (unknown !== void 0)
|
|
9537
|
-
throw new POIError(`Unknown tree hash algorithm '${asText(unknown)}': sha256, sha384 or sha512!`);
|
|
9538
|
-
if (treeHashAlgorithmsJSON.length === 0)
|
|
9539
|
-
throw new POIError("The 'treeHashAlgorithms' must name at least one hash algorithm!");
|
|
9540
|
-
if (new Set(treeHashAlgorithmsJSON).size !== treeHashAlgorithmsJSON.length)
|
|
9541
|
-
throw new POIError("The 'treeHashAlgorithms' must not name a hash algorithm twice!");
|
|
9732
|
+
const invalid = invalidTreeHashAlgorithms(treeHashAlgorithmsJSON);
|
|
9733
|
+
if (invalid !== void 0)
|
|
9734
|
+
throw new POIError(invalid);
|
|
9542
9735
|
treeHashAlgorithms = treeHashAlgorithmsJSON;
|
|
9543
9736
|
}
|
|
9544
9737
|
if (get(json, "signingKeys") !== void 0 || get(json, "identityKeys") !== void 0)
|
|
@@ -10693,10 +10886,10 @@ function parsePreconditions(value) {
|
|
|
10693
10886
|
const context2 = get(item, "@context");
|
|
10694
10887
|
const entityType = get(item, "entityType");
|
|
10695
10888
|
const entityId2 = get(item, "entityId");
|
|
10696
|
-
if (context2 !== void 0 && context2 !== PRECONDITION_CONTEXT || typeof entityType !== "string" ||
|
|
10889
|
+
if (context2 !== void 0 && context2 !== PRECONDITION_CONTEXT || typeof entityType !== "string" || typeof entityId2 !== "string")
|
|
10697
10890
|
throw invalid;
|
|
10698
10891
|
try {
|
|
10699
|
-
return { entityType, entityId: entityId2, eTag: parseETag(get(item, "eTag"), true) };
|
|
10892
|
+
return { entityType: trimmed(entityType), entityId: trimmed(entityId2), eTag: parseETag(get(item, "eTag"), true) };
|
|
10700
10893
|
} catch {
|
|
10701
10894
|
throw invalid;
|
|
10702
10895
|
}
|
|
@@ -10832,12 +11025,119 @@ function brokenPrecondition(content, preconditions) {
|
|
|
10832
11025
|
|
|
10833
11026
|
// src/history/changeSet.ts
|
|
10834
11027
|
var CHANGE_SET_CONTEXT = CONTEXT_PREFIX + "roamingNetwork/changeSet/v3";
|
|
11028
|
+
var CHANGE_CONTEXT = CONTEXT_PREFIX + "roamingNetwork/change/v1";
|
|
10835
11029
|
var MERGE_CHANGE_SET_ID_PREFIX = "merge-";
|
|
10836
11030
|
function changeSetIdentification(json) {
|
|
10837
|
-
const content = without(json, "@id", "signatures");
|
|
11031
|
+
const content = without(asRead2(json), "@id", "signatures");
|
|
10838
11032
|
set(content, "@context", CHANGE_SET_CONTEXT);
|
|
10839
11033
|
return toHex(hash("sha256", canonicalJSONBytes(content)));
|
|
10840
11034
|
}
|
|
11035
|
+
var readTrimmed = (text2) => trimmed(text2) === "" ? text2 : trimmed(text2);
|
|
11036
|
+
function asRead2(json) {
|
|
11037
|
+
const copy = { ...json };
|
|
11038
|
+
let changed = false;
|
|
11039
|
+
const networkId = get(json, "roamingNetworkId");
|
|
11040
|
+
if (typeof networkId === "string" && readTrimmed(networkId) !== networkId) {
|
|
11041
|
+
copy["roamingNetworkId"] = readTrimmed(networkId);
|
|
11042
|
+
changed = true;
|
|
11043
|
+
}
|
|
11044
|
+
const description = get(json, "description");
|
|
11045
|
+
if (description === null || isObject(description) && Object.keys(textsOf2(description)).length === 0) {
|
|
11046
|
+
delete copy["description"];
|
|
11047
|
+
changed = true;
|
|
11048
|
+
} else if (isObject(description) && canonicalJSON(textsOf2(description)) !== canonicalJSON(description)) {
|
|
11049
|
+
copy["description"] = textsOf2(description);
|
|
11050
|
+
changed = true;
|
|
11051
|
+
}
|
|
11052
|
+
const metadata2 = get(json, "metadata");
|
|
11053
|
+
if (isObject(metadata2) && Object.keys(metadata2).length === 0) {
|
|
11054
|
+
delete copy["metadata"];
|
|
11055
|
+
changed = true;
|
|
11056
|
+
}
|
|
11057
|
+
const preconditions = get(json, "preconditions");
|
|
11058
|
+
if (isArray(preconditions) && preconditions.length === 0) {
|
|
11059
|
+
delete copy["preconditions"];
|
|
11060
|
+
changed = true;
|
|
11061
|
+
} else if (isArray(preconditions)) {
|
|
11062
|
+
const read = preconditions.map(preconditionAsRead);
|
|
11063
|
+
if (read.some((precondition, index) => precondition !== preconditions[index])) {
|
|
11064
|
+
copy["preconditions"] = read;
|
|
11065
|
+
changed = true;
|
|
11066
|
+
}
|
|
11067
|
+
}
|
|
11068
|
+
const changes = changesAsRead(get(json, "changes"));
|
|
11069
|
+
if (changes !== get(json, "changes")) {
|
|
11070
|
+
copy["changes"] = changes ?? null;
|
|
11071
|
+
changed = true;
|
|
11072
|
+
}
|
|
11073
|
+
return changed ? copy : json;
|
|
11074
|
+
}
|
|
11075
|
+
var changeSetAsWritten = (json) => asRead2(json);
|
|
11076
|
+
function roamingNetworkIdOf(json, id) {
|
|
11077
|
+
const value = get(json, "roamingNetworkId");
|
|
11078
|
+
if (value === void 0)
|
|
11079
|
+
throw new POIError("Missing JSON property 'roamingNetworkId'!");
|
|
11080
|
+
if (value === null || typeof value === "string" && trimmed(value) === "")
|
|
11081
|
+
throw new POIError("Invalid 'roaming network identification'!");
|
|
11082
|
+
return trimmed(requireString(json, "roamingNetworkId", `The roaming network of the change set '${id}'`));
|
|
11083
|
+
}
|
|
11084
|
+
function preconditionAsRead(precondition) {
|
|
11085
|
+
if (!isObject(precondition))
|
|
11086
|
+
return precondition;
|
|
11087
|
+
const context2 = precondition["@context"];
|
|
11088
|
+
const entityType = precondition["entityType"];
|
|
11089
|
+
const entityId2 = precondition["entityId"];
|
|
11090
|
+
const eTag = precondition["eTag"];
|
|
11091
|
+
if (context2 !== void 0 && context2 !== PRECONDITION_CONTEXT || typeof entityType !== "string" || typeof entityId2 !== "string" || eTag === void 0)
|
|
11092
|
+
return precondition;
|
|
11093
|
+
try {
|
|
11094
|
+
parseETag(eTag, true);
|
|
11095
|
+
} catch {
|
|
11096
|
+
return precondition;
|
|
11097
|
+
}
|
|
11098
|
+
const read = { entityType: trimmed(entityType), entityId: trimmed(entityId2), eTag };
|
|
11099
|
+
return Object.keys(precondition).length === 3 && read["entityType"] === entityType && read["entityId"] === entityId2 ? precondition : read;
|
|
11100
|
+
}
|
|
11101
|
+
function changesAsRead(changes) {
|
|
11102
|
+
if (!isArray(changes))
|
|
11103
|
+
return changes;
|
|
11104
|
+
const read = changes.map((change) => {
|
|
11105
|
+
if (!isObject(change))
|
|
11106
|
+
return change;
|
|
11107
|
+
const copy = { ...change };
|
|
11108
|
+
let changed = false;
|
|
11109
|
+
for (const property of ["kind", "entityType", "entityId"]) {
|
|
11110
|
+
const value = change[property];
|
|
11111
|
+
if (typeof value === "string" && readTrimmed(value) !== value) {
|
|
11112
|
+
copy[property] = readTrimmed(value);
|
|
11113
|
+
changed = true;
|
|
11114
|
+
}
|
|
11115
|
+
}
|
|
11116
|
+
if (change["@context"] === CHANGE_CONTEXT) {
|
|
11117
|
+
delete copy["@context"];
|
|
11118
|
+
changed = true;
|
|
11119
|
+
}
|
|
11120
|
+
const path = change["elementPath"];
|
|
11121
|
+
if (isArray(path) && path.length === 0) {
|
|
11122
|
+
delete copy["elementPath"];
|
|
11123
|
+
changed = true;
|
|
11124
|
+
} else if (isArray(path) && path.some((segment) => isObject(segment) && (segment["@context"] === ELEMENT_PATH_SEGMENT_CONTEXT || typeof segment["propertyName"] === "string" && readTrimmed(segment["propertyName"]) !== segment["propertyName"]))) {
|
|
11125
|
+
copy["elementPath"] = path.map((segment) => {
|
|
11126
|
+
if (!isObject(segment))
|
|
11127
|
+
return segment;
|
|
11128
|
+
const segmentCopy = { ...segment };
|
|
11129
|
+
if (segment["@context"] === ELEMENT_PATH_SEGMENT_CONTEXT)
|
|
11130
|
+
delete segmentCopy["@context"];
|
|
11131
|
+
if (typeof segment["propertyName"] === "string")
|
|
11132
|
+
segmentCopy["propertyName"] = readTrimmed(segment["propertyName"]);
|
|
11133
|
+
return segmentCopy;
|
|
11134
|
+
});
|
|
11135
|
+
changed = true;
|
|
11136
|
+
}
|
|
11137
|
+
return changed ? copy : change;
|
|
11138
|
+
});
|
|
11139
|
+
return read.some((change, index) => change !== changes[index]) ? read : changes;
|
|
11140
|
+
}
|
|
10841
11141
|
function checkRebasedFrom(json, id) {
|
|
10842
11142
|
const metadata2 = get(json, "metadata");
|
|
10843
11143
|
const rebasedFrom = isObject(metadata2) ? get(metadata2, "rebasedFrom") : void 0;
|
|
@@ -10874,7 +11174,7 @@ function checkRebasedFrom(json, id) {
|
|
|
10874
11174
|
});
|
|
10875
11175
|
const changes = get(json, "changes");
|
|
10876
11176
|
(isArray(changes) ? changes : []).forEach((change, index) => {
|
|
10877
|
-
if (isObject(change) && get(change, "oldValue") === void 0 &&
|
|
11177
|
+
if (isObject(change) && get(change, "oldValue") === void 0 && !["Add", "AddElement"].includes(readTrimmed(asText(change["kind"]))))
|
|
10878
11178
|
throw new POIError(`Change ${index} of the change set '${id}', which was rebased, has no old value: the rebase may have overwritten a concurrent change!`);
|
|
10879
11179
|
});
|
|
10880
11180
|
}
|
|
@@ -10907,7 +11207,7 @@ function elementPathSegment(value, index) {
|
|
|
10907
11207
|
throw new POIError(`Change ${index}: invalid element path segment: a schema property name is required!`);
|
|
10908
11208
|
if (elementId !== void 0 && (typeof elementId !== "string" || blank(elementId)))
|
|
10909
11209
|
throw new POIError(`Change ${index}: invalid element path segment: an element identifier must not be empty!`);
|
|
10910
|
-
return { propertyName, elementId };
|
|
11210
|
+
return { propertyName: trimmed(propertyName), elementId };
|
|
10911
11211
|
}
|
|
10912
11212
|
function checkChange(change, index) {
|
|
10913
11213
|
const refused = (reason) => {
|
|
@@ -10917,6 +11217,8 @@ function checkChange(change, index) {
|
|
|
10917
11217
|
refused("its entity type and identification must not be empty!");
|
|
10918
11218
|
if (change.parentEntityType === void 0 !== (change.parentEntityId === void 0))
|
|
10919
11219
|
refused("parent type and parent identifier must be supplied together!");
|
|
11220
|
+
if (change.parentEntityType !== void 0 && (blank(change.parentEntityType) || blank(change.parentEntityId ?? "")))
|
|
11221
|
+
refused("its parent entity type and identification must not be empty!");
|
|
10920
11222
|
if (change.newValue === null)
|
|
10921
11223
|
refused("a new JSON value must not be null; a property is cleared by RemoveProperty!");
|
|
10922
11224
|
const elementKind = ELEMENT_KINDS.includes(change.kind);
|
|
@@ -11002,37 +11304,57 @@ var ChangeSet = class _ChangeSet {
|
|
|
11002
11304
|
"signatures"
|
|
11003
11305
|
], "A change set");
|
|
11004
11306
|
const id = requireString(json, "@id", "The identification of a change set");
|
|
11005
|
-
|
|
11006
|
-
|
|
11007
|
-
if (id !== contentId)
|
|
11008
|
-
throw new POIError(`The change set '${id}' is not identified by its content, '${contentId}'!`);
|
|
11009
|
-
checkRebasedFrom(json, id);
|
|
11010
|
-
}
|
|
11307
|
+
const roamingNetworkId = roamingNetworkIdOf(json, id);
|
|
11308
|
+
const createdAt = requireTimestamp(json, "createdAt", `The createdAt of the change set '${id}'`);
|
|
11011
11309
|
const changes = requireArray(get(json, "changes"), `The changes of the change set '${id}'`).map((item, index) => {
|
|
11012
11310
|
const change = requireObject(item, `Change ${index}`);
|
|
11013
11311
|
onlyProperties(change, ["@context", "kind", "entityType", "entityId", "propertyName", "oldValue", "newValue", "parentEntityType", "parentEntityId", "elementPath"], `Change ${index}`);
|
|
11014
|
-
const
|
|
11312
|
+
const refused = (reason) => {
|
|
11313
|
+
throw new POIError(`Change ${index}: ${reason}`);
|
|
11314
|
+
};
|
|
11315
|
+
const context2 = get(change, "@context");
|
|
11316
|
+
if (context2 !== void 0 && context2 !== CHANGE_CONTEXT)
|
|
11317
|
+
refused(`the JSON-LD context of the roaming network change must be '${CHANGE_CONTEXT}'!`);
|
|
11318
|
+
const text2 = (property, description2) => {
|
|
11319
|
+
const value2 = get(change, property);
|
|
11320
|
+
return value2 === void 0 || typeof value2 === "string" ? value2 : refused(`the ${description2} must be a text!`);
|
|
11321
|
+
};
|
|
11322
|
+
const mandatory = (property, description2) => readTrimmed(text2(property, description2) ?? refused(`the ${description2} must be a text!`));
|
|
11323
|
+
const kind = mandatory("kind", "kind");
|
|
11015
11324
|
if (!KINDS.includes(kind))
|
|
11016
|
-
|
|
11325
|
+
refused(`unknown kind '${trimmed(kind)}'!`);
|
|
11326
|
+
const entityType = mandatory("entityType", "entity type");
|
|
11327
|
+
const entityId2 = mandatory("entityId", "entity identification");
|
|
11328
|
+
const propertyName = text2("propertyName", "property name");
|
|
11329
|
+
const parentEntityType = text2("parentEntityType", "parent entity type");
|
|
11330
|
+
const parentEntityId = text2("parentEntityId", "parent entity identification");
|
|
11017
11331
|
const pathJSON = get(change, "elementPath");
|
|
11018
11332
|
if (pathJSON !== void 0 && !isArray(pathJSON))
|
|
11019
|
-
|
|
11020
|
-
const elementPath = pathJSON
|
|
11333
|
+
refused("the element path must be a JSON array!");
|
|
11334
|
+
const elementPath = !isArray(pathJSON) || pathJSON.length === 0 ? void 0 : pathJSON.map((segment) => elementPathSegment(segment, index));
|
|
11021
11335
|
const parsed = {
|
|
11022
11336
|
kind,
|
|
11023
|
-
entityType
|
|
11024
|
-
entityId:
|
|
11025
|
-
propertyName
|
|
11337
|
+
entityType,
|
|
11338
|
+
entityId: entityId2,
|
|
11339
|
+
propertyName,
|
|
11026
11340
|
oldValue: get(change, "oldValue"),
|
|
11027
11341
|
newValue: get(change, "newValue"),
|
|
11028
|
-
parentEntityType
|
|
11029
|
-
parentEntityId
|
|
11342
|
+
parentEntityType,
|
|
11343
|
+
parentEntityId,
|
|
11030
11344
|
elementPath,
|
|
11031
11345
|
json: change
|
|
11032
11346
|
};
|
|
11033
11347
|
checkChange(parsed, index);
|
|
11034
11348
|
return parsed;
|
|
11035
11349
|
});
|
|
11350
|
+
const beforeETags = parseETags(get(json, "beforeETags"), true, `The beforeETags of the change set '${id}'`);
|
|
11351
|
+
const afterETags = parseETags(get(json, "afterETags"), true, `The afterETags of the change set '${id}'`);
|
|
11352
|
+
const description = get(json, "description");
|
|
11353
|
+
if (description !== void 0 && description !== null && !isObject(description))
|
|
11354
|
+
throw new POIError("JSON property 'description' is not an object!");
|
|
11355
|
+
const metadata2 = get(json, "metadata");
|
|
11356
|
+
if (metadata2 !== void 0 && !isObject(metadata2))
|
|
11357
|
+
throw new POIError("The metadata must be a JSON object!");
|
|
11036
11358
|
const preconditions = parsePreconditions(get(json, "preconditions"));
|
|
11037
11359
|
const signatures = get(json, "signatures") === void 0 ? [] : requireArray(get(json, "signatures"), `The signatures of the change set '${id}'`).map((item) => {
|
|
11038
11360
|
const signature = requireObject(item, "A signature of a change set");
|
|
@@ -11047,30 +11369,29 @@ var ChangeSet = class _ChangeSet {
|
|
|
11047
11369
|
throw new POIError(`The ${property} of a signature of the change set '${id}' must not be empty!`);
|
|
11048
11370
|
return read;
|
|
11049
11371
|
});
|
|
11050
|
-
|
|
11051
|
-
|
|
11052
|
-
|
|
11053
|
-
|
|
11054
|
-
|
|
11055
|
-
|
|
11056
|
-
|
|
11057
|
-
parseETags(get(json, "afterETags"), true, `The afterETags of the change set '${id}'`),
|
|
11058
|
-
signatures,
|
|
11059
|
-
json
|
|
11060
|
-
);
|
|
11372
|
+
if (!id.startsWith(MERGE_CHANGE_SET_ID_PREFIX)) {
|
|
11373
|
+
const contentId = changeSetIdentification(json);
|
|
11374
|
+
if (id !== contentId)
|
|
11375
|
+
throw new POIError(`The change set '${id}' is not identified by its content, '${contentId}'!`);
|
|
11376
|
+
checkRebasedFrom(json, id);
|
|
11377
|
+
}
|
|
11378
|
+
return new _ChangeSet(id, roamingNetworkId, createdAt, changes, preconditions, beforeETags, afterETags, signatures, json);
|
|
11061
11379
|
}
|
|
11062
11380
|
/** The description in its first language. */
|
|
11063
11381
|
get description() {
|
|
11064
11382
|
const description = get(this.json, "description");
|
|
11065
11383
|
return isObject(description) && typeof Object.values(description)[0] === "string" ? Object.values(description)[0] : void 0;
|
|
11066
11384
|
}
|
|
11067
|
-
/**
|
|
11385
|
+
/**
|
|
11386
|
+
* The signature input of one of its signatures (4): the context, its algorithm and key, and the change set without
|
|
11387
|
+
* signatures, as WWCP_POI3 writes it again (`ToJSON(Embedded: true, IncludeSignatures: false)`), as it is identified.
|
|
11388
|
+
*/
|
|
11068
11389
|
signingBytes(signature) {
|
|
11069
11390
|
return canonicalJSONBytes({
|
|
11070
11391
|
"@context": CHANGE_SET_CONTEXT,
|
|
11071
11392
|
algorithm: signature.algorithm,
|
|
11072
11393
|
keyId: signature.keyId,
|
|
11073
|
-
changeSet: without(this.json, "signatures", "@context")
|
|
11394
|
+
changeSet: without(asRead2(this.json), "signatures", "@context")
|
|
11074
11395
|
});
|
|
11075
11396
|
}
|
|
11076
11397
|
/** Verifies one signature with the given key. */
|
|
@@ -11224,20 +11545,26 @@ var Commit = class _Commit {
|
|
|
11224
11545
|
throw new POIError(`The commit '${id}' of revision 0 has parents!`);
|
|
11225
11546
|
return commit;
|
|
11226
11547
|
}
|
|
11227
|
-
/**
|
|
11548
|
+
/**
|
|
11549
|
+
* What the identification is the digest of: the commit without `@id`, its signatures and those of its change set; its
|
|
11550
|
+
* change set as WWCP_POI3 writes it again, as it identifies a commit over it (RoamingNetworkCommit.TryParse).
|
|
11551
|
+
*/
|
|
11228
11552
|
identificationContent() {
|
|
11229
11553
|
const content = without(this.json, "@id", "signatures", "changeSet");
|
|
11230
11554
|
content["@context"] = COMMIT_CONTEXT2;
|
|
11231
11555
|
if (this.changeSet !== void 0)
|
|
11232
|
-
content["changeSet"] = without(this.changeSet, "signatures", "@context");
|
|
11556
|
+
content["changeSet"] = without(changeSetAsWritten(this.changeSet), "signatures", "@context");
|
|
11233
11557
|
return content;
|
|
11234
11558
|
}
|
|
11235
|
-
/**
|
|
11559
|
+
/**
|
|
11560
|
+
* The commit as a signature of it signs it: with its `@context`, its `@id` and the signatures of its change set (5.4);
|
|
11561
|
+
* its change set as WWCP_POI3 writes it again.
|
|
11562
|
+
*/
|
|
11236
11563
|
signedContent() {
|
|
11237
11564
|
const content = without(this.json, "signatures", "changeSet");
|
|
11238
11565
|
content["@context"] = COMMIT_CONTEXT2;
|
|
11239
11566
|
if (this.changeSet !== void 0)
|
|
11240
|
-
content["changeSet"] = without(this.changeSet, "@context");
|
|
11567
|
+
content["changeSet"] = without(changeSetAsWritten(this.changeSet), "@context");
|
|
11241
11568
|
return content;
|
|
11242
11569
|
}
|
|
11243
11570
|
/** The signature input of one of its signatures (5.4). */
|
|
@@ -11469,7 +11796,7 @@ var MANUFACTURER_PROPERTIES = [...PARTY_PROPERTIES, ...CONTACT_PROPERTIES];
|
|
|
11469
11796
|
var RNO_PROPERTIES = [...REGISTRY_PROPERTIES, "identityKeys", "eMailAddress", "hotlineEMailAddress", "minConsensus", "keyStatement", "signingKeyCertificates"];
|
|
11470
11797
|
var PARTY_REGISTRIES = {
|
|
11471
11798
|
RoamingNetworkOperator: { what: "roaming network operator", article: "a", changeable: RNO_PROPERTIES },
|
|
11472
|
-
ChargingStationOperator: { what: "charging station operator", article: "a", changeable: [...MANUFACTURER_PROPERTIES, "evTaler", "brands"] },
|
|
11799
|
+
ChargingStationOperator: { what: "charging station operator", article: "a", changeable: [...MANUFACTURER_PROPERTIES, "webPaymentURL", "evTaler", "brands"] },
|
|
11473
11800
|
EMobilityProvider: { what: "e-mobility provider", article: "an", changeable: MANUFACTURER_PROPERTIES },
|
|
11474
11801
|
GridOperator: { what: "grid operator", article: "a", changeable: PARTY_PROPERTIES },
|
|
11475
11802
|
ParkingOperator: { what: "parking operator", article: "a", changeable: PARTY_PROPERTIES },
|
|
@@ -11798,6 +12125,24 @@ var OPERATOR_CHILD_ARRAYS = {
|
|
|
11798
12125
|
};
|
|
11799
12126
|
var TARIFF_TYPES = /* @__PURE__ */ new Set(["ChargingTariff", "ChargingTariffTemplate", "ChargingTariffGroup", "ChargingTariffOffer"]);
|
|
11800
12127
|
var INFRASTRUCTURE_TYPES = /* @__PURE__ */ new Set([...Object.keys(OPERATOR_CHILD_ARRAYS), "ChargingPool", "ChargingStation", "EVSE"]);
|
|
12128
|
+
var INFRASTRUCTURE_IDS = {
|
|
12129
|
+
ChargingPool: poolId,
|
|
12130
|
+
ChargingStation: stationId,
|
|
12131
|
+
EVSE: evseId,
|
|
12132
|
+
ChargingTariff: tariffId,
|
|
12133
|
+
EVSEGroup: evseGroupId,
|
|
12134
|
+
ChargingStationGroup: stationGroupId,
|
|
12135
|
+
ChargingPoolGroup: poolGroupId,
|
|
12136
|
+
ChargingTariffGroup: tariffGroupId,
|
|
12137
|
+
EVSETemplate: evseTemplateId,
|
|
12138
|
+
ChargingStationTemplate: stationTemplateId,
|
|
12139
|
+
ChargingPoolTemplate: poolTemplateId,
|
|
12140
|
+
ChargingTariffTemplate: tariffTemplateId
|
|
12141
|
+
};
|
|
12142
|
+
function operatorIdOf(entityType, entityId2) {
|
|
12143
|
+
const id = INFRASTRUCTURE_IDS[entityType]?.(entityId2);
|
|
12144
|
+
return id === void 0 ? void 0 : operatorOf(id);
|
|
12145
|
+
}
|
|
11801
12146
|
var POOL_TEMPLATE_PROPERTIES = [
|
|
11802
12147
|
"dataLicenses",
|
|
11803
12148
|
"address",
|
|
@@ -11805,6 +12150,7 @@ var POOL_TEMPLATE_PROPERTIES = [
|
|
|
11805
12150
|
"parkingType",
|
|
11806
12151
|
"accessibility",
|
|
11807
12152
|
"hotline",
|
|
12153
|
+
"webPaymentURL",
|
|
11808
12154
|
"gridConnectionPointId",
|
|
11809
12155
|
"brands",
|
|
11810
12156
|
"openingTimes",
|
|
@@ -11835,6 +12181,7 @@ var STATION_TEMPLATE_PROPERTIES = [
|
|
|
11835
12181
|
"address",
|
|
11836
12182
|
"geoLocation",
|
|
11837
12183
|
"hotline",
|
|
12184
|
+
"webPaymentURL",
|
|
11838
12185
|
"manufacturerId",
|
|
11839
12186
|
"modelId",
|
|
11840
12187
|
"modelURL",
|
|
@@ -11917,58 +12264,102 @@ var INFRASTRUCTURE = {
|
|
|
11917
12264
|
ChargingPoolTemplate: { what: "charging pool template", changeable: [...BASE_PROPERTIES, "chargingTariffId", "customData", ...POOL_TEMPLATE_PROPERTIES] },
|
|
11918
12265
|
ChargingTariffTemplate: { what: "charging tariff template", changeable: [...BASE_PROPERTIES, "customData", ...TARIFF_TEMPLATE_PROPERTIES] }
|
|
11919
12266
|
};
|
|
11920
|
-
|
|
11921
|
-
|
|
11922
|
-
|
|
11923
|
-
|
|
12267
|
+
var heldChecks;
|
|
12268
|
+
function asGiven(value, property, change, index, what, heldId) {
|
|
12269
|
+
const check2 = () => {
|
|
12270
|
+
const refused = notHeldAsGiven(value, property, change, index, what, heldId);
|
|
12271
|
+
if (refused !== void 0)
|
|
12272
|
+
throw new POIError(refused);
|
|
12273
|
+
};
|
|
12274
|
+
if (heldChecks === void 0)
|
|
12275
|
+
check2();
|
|
12276
|
+
else
|
|
12277
|
+
heldChecks.push(check2);
|
|
11924
12278
|
return clone(value);
|
|
11925
12279
|
}
|
|
12280
|
+
function notHeldAsGiven(given2, property, change, index, what, heldId) {
|
|
12281
|
+
const element = change.elementChange;
|
|
12282
|
+
if (element !== void 0 && (element.kind === "RemoveElement" || element.kind === "RemoveElementProperty"))
|
|
12283
|
+
return void 0;
|
|
12284
|
+
const found = notWritten(given2, property, property ?? "", "new value");
|
|
12285
|
+
if (found === void 0 && (heldId === void 0 || !isObject(given2) || given2["@id"] === heldId))
|
|
12286
|
+
return void 0;
|
|
12287
|
+
const held = heldAs(given2, property);
|
|
12288
|
+
if (held === void 0)
|
|
12289
|
+
return found === void 0 ? void 0 : `Change ${index}, the ${what}${change.kind === "Add" ? " to add" : ""}: ${found.path === "" ? "it" : `'${found.path}'`} is not given as the content holds it: ${found.reason}!`;
|
|
12290
|
+
let heldValue = heldId !== void 0 && isObject(held.value) ? { ...held.value, "@id": heldId } : held.value;
|
|
12291
|
+
let givenValue = given2;
|
|
12292
|
+
let named2;
|
|
12293
|
+
if (element !== void 0) {
|
|
12294
|
+
const elementProperty = element.kind === "UpdateElementProperty";
|
|
12295
|
+
const removal = applyElement({ ...element, kind: elementProperty ? "RemoveElementProperty" : "RemoveElement", newValue: void 0 }, heldValue);
|
|
12296
|
+
named2 = `'${pathText(element.elementPath ?? [], elementProperty ? element.propertyName : void 0)}' of the ${what}`;
|
|
12297
|
+
givenValue = element.newValue ?? null;
|
|
12298
|
+
heldValue = removal.error === void 0 ? removal.current : void 0;
|
|
12299
|
+
} else
|
|
12300
|
+
named2 = change.kind === "Add" ? `the ${what} to add` : `the property '${property ?? ""}' of the ${what}`;
|
|
12301
|
+
if (heldValue === void 0)
|
|
12302
|
+
return `Change ${index}: ${named2} is given as '${contentText(givenValue)}', which the content does not hold at all!`;
|
|
12303
|
+
return sameValue(givenValue, heldValue) ? void 0 : `Change ${index}: ${named2} is not given as the content holds it, '${contentText(heldValue)}'!`;
|
|
12304
|
+
}
|
|
11926
12305
|
function insertOrdered(array, entity) {
|
|
11927
12306
|
const id = asText(entity["@id"]);
|
|
11928
12307
|
const index = array.findIndex((item) => isObject(item) && ordinal(asText(item["@id"]), id) > 0);
|
|
11929
12308
|
array.splice(index < 0 ? array.length : index, 0, entity);
|
|
11930
12309
|
}
|
|
11931
12310
|
var objectsOf4 = (value) => isArray(value) ? value.filter(isObject) : [];
|
|
12311
|
+
function names(stored, entityType, given2) {
|
|
12312
|
+
if (typeof stored !== "string")
|
|
12313
|
+
return false;
|
|
12314
|
+
if (stored === given2)
|
|
12315
|
+
return true;
|
|
12316
|
+
const parse = INFRASTRUCTURE_IDS[entityType];
|
|
12317
|
+
const left = parse?.(stored);
|
|
12318
|
+
const right = parse?.(given2);
|
|
12319
|
+
return left !== void 0 && left.key === right?.key;
|
|
12320
|
+
}
|
|
11932
12321
|
function find(operator, entityType, entityId2) {
|
|
11933
|
-
const
|
|
12322
|
+
const ownId = asText(operator["@id"]);
|
|
11934
12323
|
const childArray = OPERATOR_CHILD_ARRAYS[entityType];
|
|
11935
12324
|
if (childArray !== void 0) {
|
|
11936
12325
|
const children2 = get(operator, childArray);
|
|
11937
12326
|
for (const child of objectsOf4(children2))
|
|
11938
|
-
if (child["@id"]
|
|
11939
|
-
return { entity: child, container: children2, holder: operator, property: childArray, parentType: "ChargingStationOperator", parentId:
|
|
12327
|
+
if (names(child["@id"], entityType, entityId2))
|
|
12328
|
+
return { entity: child, container: children2, holder: operator, property: childArray, parentType: "ChargingStationOperator", parentId: ownId };
|
|
11940
12329
|
return void 0;
|
|
11941
12330
|
}
|
|
11942
12331
|
const pools = get(operator, "chargingPools");
|
|
11943
12332
|
for (const pool of objectsOf4(pools)) {
|
|
11944
12333
|
if (entityType === "ChargingPool") {
|
|
11945
|
-
if (pool["@id"]
|
|
11946
|
-
return { entity: pool, container: pools, holder: operator, property: "chargingPools", parentType: "ChargingStationOperator", parentId:
|
|
12334
|
+
if (names(pool["@id"], entityType, entityId2))
|
|
12335
|
+
return { entity: pool, container: pools, holder: operator, property: "chargingPools", parentType: "ChargingStationOperator", parentId: ownId };
|
|
11947
12336
|
continue;
|
|
11948
12337
|
}
|
|
11949
12338
|
const stations = get(pool, "chargingStations");
|
|
11950
12339
|
for (const station of objectsOf4(stations)) {
|
|
11951
12340
|
if (entityType === "ChargingStation") {
|
|
11952
|
-
if (station["@id"]
|
|
12341
|
+
if (names(station["@id"], entityType, entityId2))
|
|
11953
12342
|
return { entity: station, container: stations, holder: pool, property: "chargingStations", parentType: "ChargingPool", parentId: asText(pool["@id"]) };
|
|
11954
12343
|
continue;
|
|
11955
12344
|
}
|
|
11956
12345
|
const evses = get(station, "EVSEs");
|
|
11957
12346
|
for (const evse2 of objectsOf4(evses))
|
|
11958
|
-
if (evse2["@id"]
|
|
12347
|
+
if (names(evse2["@id"], entityType, entityId2))
|
|
11959
12348
|
return { entity: evse2, container: evses, holder: station, property: "EVSEs", parentType: "ChargingStation", parentId: asText(station["@id"]) };
|
|
11960
12349
|
}
|
|
11961
12350
|
}
|
|
11962
12351
|
return void 0;
|
|
11963
12352
|
}
|
|
11964
|
-
|
|
11965
|
-
|
|
11966
|
-
|
|
11967
|
-
|
|
11968
|
-
|
|
11969
|
-
|
|
12353
|
+
var operatorNamed = (content, id) => objectsOf4(get(content, "chargingStationOperators")).find((operator) => operatorId(asText(operator["@id"]))?.key === operatorId(id)?.key);
|
|
12354
|
+
function storedId(operator, entityType, entityId2) {
|
|
12355
|
+
if (entityId2 === void 0)
|
|
12356
|
+
return void 0;
|
|
12357
|
+
if (entityType === "ChargingStationOperator") {
|
|
12358
|
+
const given2 = operatorId(entityId2);
|
|
12359
|
+
return given2 !== void 0 && given2.key === operatorId(asText(operator["@id"]))?.key ? asText(operator["@id"]) : void 0;
|
|
11970
12360
|
}
|
|
11971
|
-
|
|
12361
|
+
const found = INFRASTRUCTURE_IDS[entityType] === void 0 ? void 0 : find(operator, entityType, entityId2);
|
|
12362
|
+
return found === void 0 ? void 0 : asText(found.entity["@id"]);
|
|
11972
12363
|
}
|
|
11973
12364
|
function touchParents(operator, parentType, parentId, lastChange) {
|
|
11974
12365
|
while ((parentType === "ChargingStation" || parentType === "ChargingPool") && parentId !== void 0) {
|
|
@@ -11986,7 +12377,7 @@ function checkOldValue(change, current, index, what) {
|
|
|
11986
12377
|
if (change.oldValue === void 0)
|
|
11987
12378
|
return;
|
|
11988
12379
|
if (!oldValueMatches(change.oldValue, current))
|
|
11989
|
-
throw new POIError(change.propertyName !== void 0 && (change.kind === "UpdateProperty" || change.kind === "RemoveProperty") ? `Change ${index}: the property '${change.propertyName}' of the ${what} is no longer the expected old value!` : `Change ${index}: the ${what} is no longer the expected old value${current === void 0 ? ": it does not exist" : ""}!`);
|
|
12380
|
+
throw new POIError(change.propertyName !== void 0 && (change.kind === "UpdateProperty" || change.kind === "RemoveProperty") ? `Change ${index}: the property '${change.propertyName}' of the ${what} is no longer the expected old value, but '${contentText(current)}'!` : `Change ${index}: the ${what} is no longer the expected old value${current === void 0 ? ": it does not exist" : ""}!`);
|
|
11990
12381
|
}
|
|
11991
12382
|
function resolveElementChange(change, entity, what, index) {
|
|
11992
12383
|
if (!isElementChange(change))
|
|
@@ -12000,20 +12391,21 @@ function resolveElementChange(change, entity, what, index) {
|
|
|
12000
12391
|
if (applied.error !== void 0)
|
|
12001
12392
|
throw new POIError(`Change ${index}: ${change.kind} of the ${what}: ${applied.error}`);
|
|
12002
12393
|
if (change.oldValue !== void 0 && !oldValueMatches(change.oldValue, applied.current))
|
|
12003
|
-
throw new POIError(`Change ${index}: '${pathText(change.elementPath ?? [], change.propertyName)}' of the ${what} is no longer the expected old value!`);
|
|
12394
|
+
throw new POIError(`Change ${index}: '${pathText(change.elementPath ?? [], change.propertyName)}' of the ${what} is no longer the expected old value, but '${contentText(applied.current)}'!`);
|
|
12004
12395
|
return {
|
|
12005
12396
|
...change,
|
|
12006
12397
|
kind: applied.newValue === void 0 ? "RemoveProperty" : "UpdateProperty",
|
|
12007
12398
|
propertyName: property,
|
|
12008
12399
|
oldValue: void 0,
|
|
12009
12400
|
newValue: applied.newValue,
|
|
12010
|
-
elementPath: void 0
|
|
12401
|
+
elementPath: void 0,
|
|
12402
|
+
elementChange: change
|
|
12011
12403
|
};
|
|
12012
12404
|
}
|
|
12013
12405
|
function applyProperty(entity, change, index, what, lastChange) {
|
|
12014
12406
|
const property = change.propertyName;
|
|
12015
12407
|
if (property === void 0 || property === "@id" || property === "created" || property === "lastChange")
|
|
12016
|
-
throw new POIError(`Change ${index}: the property '${property ?? ""}' of
|
|
12408
|
+
throw new POIError(`Change ${index}: the property '${property ?? ""}' of ${withArticle(what, false)} can not be changed!`);
|
|
12017
12409
|
if (change.kind === "RemoveProperty") {
|
|
12018
12410
|
if (get(entity, property) === void 0)
|
|
12019
12411
|
throw new POIError(`Change ${index}: the property '${property}' of the ${what} does not exist!`);
|
|
@@ -12021,27 +12413,31 @@ function applyProperty(entity, change, index, what, lastChange) {
|
|
|
12021
12413
|
} else {
|
|
12022
12414
|
if (change.newValue === void 0)
|
|
12023
12415
|
throw new POIError(`Change ${index}: an UpdateProperty needs its newValue!`);
|
|
12024
|
-
set(entity, property, asGiven(change.newValue, property,
|
|
12416
|
+
set(entity, property, asGiven(change.newValue, property, change, index, what));
|
|
12025
12417
|
}
|
|
12026
12418
|
if (lastChange !== void 0)
|
|
12027
12419
|
entity["lastChange"] = lastChange;
|
|
12028
12420
|
}
|
|
12029
|
-
function entityToAdd(change, index, what, createdAt) {
|
|
12421
|
+
function entityToAdd(change, index, what, createdAt, heldId) {
|
|
12030
12422
|
if (!isObject(change.newValue) || change.newValue["@id"] !== change.entityId)
|
|
12031
12423
|
throw new POIError(`Change ${index}: the ${what} to add must be a JSON object with the identification '${change.entityId}'!`);
|
|
12032
|
-
const added = asGiven(without(change.newValue, "lastChange"), void 0,
|
|
12424
|
+
const added = asGiven(without(change.newValue, "lastChange"), void 0, change, index, what, heldId);
|
|
12033
12425
|
if (get(added, "created") === void 0)
|
|
12034
12426
|
added["created"] = createdAt;
|
|
12035
12427
|
added["lastChange"] = createdAt;
|
|
12036
12428
|
return added;
|
|
12037
12429
|
}
|
|
12038
12430
|
function applyInfrastructureChange(content, change, index, createdAt) {
|
|
12039
|
-
const
|
|
12040
|
-
const
|
|
12431
|
+
const description = INFRASTRUCTURE[change.entityType]?.what ?? change.entityType;
|
|
12432
|
+
const what = `${description} '${change.entityId}'`;
|
|
12433
|
+
const ownerId = operatorIdOf(change.entityType, change.entityId);
|
|
12434
|
+
if (ownerId === void 0)
|
|
12435
|
+
throw new POIError(`Change ${index}: invalid ${description} identification '${change.entityId}'!`);
|
|
12436
|
+
const operator = operatorNamed(content, ownerId);
|
|
12041
12437
|
if (operator === void 0)
|
|
12042
|
-
throw new POIError(`Change ${index}: the charging station operator of the ${what} does not exist!`);
|
|
12438
|
+
throw new POIError(`Change ${index}: the charging station operator '${ownerId}' of the ${what} does not exist!`);
|
|
12043
12439
|
const found = find(operator, change.entityType, change.entityId);
|
|
12044
|
-
if (found !== void 0 && change.parentEntityType !== void 0 && (change.parentEntityType !== found.parentType || change.parentEntityId !== found.parentId))
|
|
12440
|
+
if (found !== void 0 && change.parentEntityType !== void 0 && (change.parentEntityType !== found.parentType || storedId(operator, change.parentEntityType, change.parentEntityId) !== found.parentId))
|
|
12045
12441
|
throw new POIError(`Change ${index}: the ${what} belongs to ${found.parentType} '${found.parentId}', not to ${change.parentEntityType} '${change.parentEntityId}'!`);
|
|
12046
12442
|
change = resolveElementChange(change, found?.entity, what, index);
|
|
12047
12443
|
if (change.kind !== "Add" && found === void 0)
|
|
@@ -12056,36 +12452,38 @@ function applyInfrastructureChange(content, change, index, createdAt) {
|
|
|
12056
12452
|
case "RemoveProperty": {
|
|
12057
12453
|
const infrastructure = required(INFRASTRUCTURE[change.entityType], change.entityType);
|
|
12058
12454
|
if (!infrastructure.changeable.includes(change.propertyName ?? ""))
|
|
12059
|
-
throw new POIError(`Change ${index}: the property '${change.propertyName ?? ""}' of
|
|
12455
|
+
throw new POIError(`Change ${index}: the property '${change.propertyName ?? ""}' of ${withArticle(infrastructure.what, false)} can not be changed!`);
|
|
12060
12456
|
applyProperty(existing().entity, change, index, what, createdAt);
|
|
12061
12457
|
break;
|
|
12062
12458
|
}
|
|
12063
12459
|
case "Add": {
|
|
12064
12460
|
if (found !== void 0)
|
|
12065
12461
|
throw new POIError(`Change ${index}: the ${what} already exists!`);
|
|
12066
|
-
const added = entityToAdd(change, index, what, createdAt);
|
|
12067
|
-
parentType = change.parentEntityType ?? "ChargingStationOperator";
|
|
12068
|
-
parentId = change.parentEntityId ?? asText(operator["@id"]);
|
|
12462
|
+
const added = entityToAdd(change, index, what, createdAt, INFRASTRUCTURE_IDS[change.entityType]?.(change.entityId)?.text);
|
|
12069
12463
|
let holder;
|
|
12070
12464
|
let property;
|
|
12071
12465
|
if (OPERATOR_CHILD_ARRAYS[change.entityType] !== void 0 || change.entityType === "ChargingPool") {
|
|
12072
|
-
if (
|
|
12073
|
-
throw new POIError(`Change ${index}:
|
|
12466
|
+
if (change.parentEntityType !== void 0 && (change.parentEntityType !== "ChargingStationOperator" || storedId(operator, "ChargingStationOperator", change.parentEntityId) === void 0))
|
|
12467
|
+
throw new POIError(`Change ${index}: ${withArticle(what, false)} belongs to ChargingStationOperator '${asText(operator["@id"])}', not to ${change.parentEntityType} '${change.parentEntityId ?? ""}'!`);
|
|
12074
12468
|
holder = operator;
|
|
12075
12469
|
property = OPERATOR_CHILD_ARRAYS[change.entityType] ?? "chargingPools";
|
|
12076
12470
|
} else if (change.entityType === "ChargingStation") {
|
|
12077
|
-
if (
|
|
12078
|
-
throw new POIError(`Change ${index}:
|
|
12079
|
-
holder = find(operator, "ChargingPool",
|
|
12471
|
+
if (change.parentEntityType !== "ChargingPool" || change.parentEntityId === void 0)
|
|
12472
|
+
throw new POIError(`Change ${index}: adding the charging station '${change.entityId}' needs its ChargingPool as its parent!`);
|
|
12473
|
+
holder = find(operator, "ChargingPool", change.parentEntityId)?.entity;
|
|
12080
12474
|
property = "chargingStations";
|
|
12475
|
+
if (holder === void 0)
|
|
12476
|
+
throw new POIError(`Change ${index}: the charging pool '${change.parentEntityId}' of the charging station '${change.entityId}' does not exist!`);
|
|
12081
12477
|
} else {
|
|
12082
|
-
if (
|
|
12083
|
-
throw new POIError(`Change ${index}:
|
|
12084
|
-
holder = find(operator, "ChargingStation",
|
|
12478
|
+
if (change.parentEntityType !== "ChargingStation" || change.parentEntityId === void 0)
|
|
12479
|
+
throw new POIError(`Change ${index}: adding the EVSE '${change.entityId}' needs its ChargingStation as its parent!`);
|
|
12480
|
+
holder = find(operator, "ChargingStation", change.parentEntityId)?.entity;
|
|
12085
12481
|
property = "EVSEs";
|
|
12482
|
+
if (holder === void 0)
|
|
12483
|
+
throw new POIError(`Change ${index}: the charging station '${change.parentEntityId}' of the EVSE '${change.entityId}' does not exist!`);
|
|
12086
12484
|
}
|
|
12087
|
-
|
|
12088
|
-
|
|
12485
|
+
parentType = change.parentEntityType ?? "ChargingStationOperator";
|
|
12486
|
+
parentId = storedId(operator, parentType, change.parentEntityId ?? asText(operator["@id"]));
|
|
12089
12487
|
const children2 = get(holder, property);
|
|
12090
12488
|
if (children2 === void 0)
|
|
12091
12489
|
set(holder, property, [added]);
|
|
@@ -12103,9 +12501,10 @@ function applyInfrastructureChange(content, change, index, createdAt) {
|
|
|
12103
12501
|
break;
|
|
12104
12502
|
}
|
|
12105
12503
|
default:
|
|
12106
|
-
throw new POIError(`Change ${index}: ${change.kind} of
|
|
12504
|
+
throw new POIError(`Change ${index}: ${change.kind} of ${withArticle(INFRASTRUCTURE[change.entityType]?.what ?? change.entityType, false)} is not supported by this library yet!`);
|
|
12107
12505
|
}
|
|
12108
12506
|
touchParents(operator, parentType, parentId, createdAt);
|
|
12507
|
+
return { type: "ChargingStationOperator", json: operator };
|
|
12109
12508
|
}
|
|
12110
12509
|
function applyNetworkArrayChange(content, change, index, createdAt) {
|
|
12111
12510
|
const property = required(NETWORK_ARRAYS[change.entityType], `Change ${index}: ${change.entityType} is no party!`);
|
|
@@ -12127,7 +12526,7 @@ function applyNetworkArrayChange(content, change, index, createdAt) {
|
|
|
12127
12526
|
case "UpdateProperty":
|
|
12128
12527
|
case "RemoveProperty":
|
|
12129
12528
|
applyProperty(existing(), change, index, what, createdAt);
|
|
12130
|
-
|
|
12529
|
+
return { type: change.entityType, json: existing() };
|
|
12131
12530
|
case "Add": {
|
|
12132
12531
|
if (entity !== void 0)
|
|
12133
12532
|
throw new POIError(`Change ${index}: the ${what} already exists!`);
|
|
@@ -12136,7 +12535,7 @@ function applyNetworkArrayChange(content, change, index, createdAt) {
|
|
|
12136
12535
|
set(content, property, [added]);
|
|
12137
12536
|
else if (isArray(array))
|
|
12138
12537
|
insertOrdered(array, added);
|
|
12139
|
-
|
|
12538
|
+
return { type: change.entityType, json: added };
|
|
12140
12539
|
}
|
|
12141
12540
|
case "Remove": {
|
|
12142
12541
|
if (entity === void 0)
|
|
@@ -12145,10 +12544,10 @@ function applyNetworkArrayChange(content, change, index, createdAt) {
|
|
|
12145
12544
|
items.splice(items.indexOf(entity), 1);
|
|
12146
12545
|
if (items.length === 0)
|
|
12147
12546
|
unset(content, property);
|
|
12148
|
-
|
|
12547
|
+
return void 0;
|
|
12149
12548
|
}
|
|
12150
12549
|
default:
|
|
12151
|
-
throw new POIError(`Change ${index}: ${change.kind} of
|
|
12550
|
+
throw new POIError(`Change ${index}: ${change.kind} of ${registry.article} ${registry.what} is not supported by this library yet!`);
|
|
12152
12551
|
}
|
|
12153
12552
|
}
|
|
12154
12553
|
function partyChildOf(content, type, childId) {
|
|
@@ -12182,7 +12581,7 @@ function applyPartyChildChange(content, change, index, createdAt) {
|
|
|
12182
12581
|
if (change.kind !== "Add" && found2 === void 0)
|
|
12183
12582
|
throw new POIError(`Change ${index}: the ${what} of the ${type.inParent} '${asText(party2["@id"])}' does not exist!`);
|
|
12184
12583
|
applyPartyChild(type, party2, found2, change, index, what, createdAt);
|
|
12185
|
-
return;
|
|
12584
|
+
return { type: type.parentType, json: party2 };
|
|
12186
12585
|
}
|
|
12187
12586
|
const found = partyChildOf(content, type, change.entityId);
|
|
12188
12587
|
let party;
|
|
@@ -12201,6 +12600,7 @@ function applyPartyChildChange(content, change, index, createdAt) {
|
|
|
12201
12600
|
party = found.party;
|
|
12202
12601
|
}
|
|
12203
12602
|
applyPartyChild(type, party, found, change, index, what, createdAt);
|
|
12603
|
+
return { type: type.parentType, json: party };
|
|
12204
12604
|
}
|
|
12205
12605
|
function applyPartyChild(type, party, found, change, index, what, createdAt) {
|
|
12206
12606
|
change = resolveElementChange(change, found?.child, what, index);
|
|
@@ -12214,7 +12614,7 @@ function applyPartyChild(type, party, found, change, index, what, createdAt) {
|
|
|
12214
12614
|
const property = change.propertyName ?? "";
|
|
12215
12615
|
const child = existing().child;
|
|
12216
12616
|
if (!type.changeable.includes(property))
|
|
12217
|
-
throw new POIError(type.keepsVersion === true && property === "version" ? `Change ${index}: the version of the ${what} can not be changed: a new version is a new release!` : `Change ${index}: the property '${property}' of
|
|
12617
|
+
throw new POIError(type.keepsVersion === true && property === "version" ? `Change ${index}: the version of the ${what} can not be changed: a new version is a new release!` : `Change ${index}: the property '${property}' of ${withArticle(type.what, false)} can not be changed!`);
|
|
12218
12618
|
if (change.kind === "RemoveProperty") {
|
|
12219
12619
|
if (get(child, property) === void 0)
|
|
12220
12620
|
throw new POIError(`Change ${index}: the property '${property}' of the ${what} does not exist!`);
|
|
@@ -12222,14 +12622,14 @@ function applyPartyChild(type, party, found, change, index, what, createdAt) {
|
|
|
12222
12622
|
} else {
|
|
12223
12623
|
if (change.newValue === void 0)
|
|
12224
12624
|
throw new POIError(`Change ${index}: an UpdateProperty needs its newValue!`);
|
|
12225
|
-
set(child, property, asGiven(change.newValue, property,
|
|
12625
|
+
set(child, property, asGiven(change.newValue, property, change, index, what));
|
|
12226
12626
|
}
|
|
12227
12627
|
break;
|
|
12228
12628
|
}
|
|
12229
12629
|
case "Add": {
|
|
12230
12630
|
if (!isObject(change.newValue) || typeof change.newValue["@id"] !== "string" || !sameId4(change.newValue["@id"], change.entityId))
|
|
12231
12631
|
throw new POIError(`Change ${index}: the ${type.what} to add must be a JSON object with the identification '${change.entityId}'!`);
|
|
12232
|
-
const added = asGiven(without(change.newValue, "lastChange"), void 0,
|
|
12632
|
+
const added = asGiven(without(change.newValue, "lastChange"), void 0, change, index, what);
|
|
12233
12633
|
const children2 = get(party, type.property);
|
|
12234
12634
|
if (children2 === void 0)
|
|
12235
12635
|
set(party, type.property, [added]);
|
|
@@ -12247,7 +12647,7 @@ function applyPartyChild(type, party, found, change, index, what, createdAt) {
|
|
|
12247
12647
|
break;
|
|
12248
12648
|
}
|
|
12249
12649
|
default:
|
|
12250
|
-
throw new POIError(`Change ${index}: ${change.kind} of
|
|
12650
|
+
throw new POIError(`Change ${index}: ${change.kind} of ${withArticle(type.what, false)} is not supported by this library yet!`);
|
|
12251
12651
|
}
|
|
12252
12652
|
party["lastChange"] = createdAt;
|
|
12253
12653
|
}
|
|
@@ -12259,15 +12659,17 @@ function applyEmbeddedChange(content, change, index, createdAt, type) {
|
|
|
12259
12659
|
const what = `${type.what} '${gridPoint ? id.text : change.entityId}'`;
|
|
12260
12660
|
const found = embeddedOf(content, type, change.entityId);
|
|
12261
12661
|
let party;
|
|
12662
|
+
let partyType;
|
|
12262
12663
|
let property;
|
|
12263
12664
|
if (change.kind === "Add") {
|
|
12264
12665
|
if (found !== void 0)
|
|
12265
12666
|
throw new POIError(gridPoint ? `Change ${index}: the ${what} already exists, at the grid operator '${asText(found.party["@id"])}'!` : `Change ${index}: the ${what} already exists!`);
|
|
12266
12667
|
const parentProperty = change.parentEntityType === void 0 ? void 0 : type.owners[change.parentEntityType];
|
|
12267
12668
|
const parent = change.parentEntityType === void 0 || parentProperty === void 0 ? void 0 : partyNamed(content, change.parentEntityType, change.parentEntityId);
|
|
12268
|
-
if (parent === void 0 || parentProperty === void 0)
|
|
12669
|
+
if (parent === void 0 || parentProperty === void 0 || change.parentEntityType === void 0)
|
|
12269
12670
|
throw new POIError(`Change ${index}: the ${what} to add needs its ${type.addNeeds(change.parentEntityType)}, an existing one!`);
|
|
12270
12671
|
party = parent;
|
|
12672
|
+
partyType = change.parentEntityType;
|
|
12271
12673
|
property = parentProperty;
|
|
12272
12674
|
} else {
|
|
12273
12675
|
if (found === void 0)
|
|
@@ -12275,6 +12677,7 @@ function applyEmbeddedChange(content, change, index, createdAt, type) {
|
|
|
12275
12677
|
if (change.parentEntityType !== void 0 && (change.parentEntityType !== found.partyType || change.parentEntityId === void 0 || !sameId4(change.parentEntityId, asText(found.party["@id"]))))
|
|
12276
12678
|
throw new POIError(`Change ${index}: the ${what} belongs to ${found.partyType} '${asText(found.party["@id"])}', not to ${change.parentEntityType} '${change.parentEntityId ?? ""}'!`);
|
|
12277
12679
|
party = found.party;
|
|
12680
|
+
partyType = found.partyType;
|
|
12278
12681
|
property = required(type.owners[found.partyType], found.partyType);
|
|
12279
12682
|
}
|
|
12280
12683
|
change = resolveElementChange(change, found?.child, what, index);
|
|
@@ -12285,14 +12688,14 @@ function applyEmbeddedChange(content, change, index, createdAt, type) {
|
|
|
12285
12688
|
case "UpdateProperty":
|
|
12286
12689
|
case "RemoveProperty":
|
|
12287
12690
|
if (!type.changeable.includes(change.propertyName ?? ""))
|
|
12288
|
-
throw new POIError(`Change ${index}: the property '${change.propertyName ?? ""}' of
|
|
12691
|
+
throw new POIError(`Change ${index}: the property '${change.propertyName ?? ""}' of ${withArticle(type.what, false)} can not be changed!`);
|
|
12289
12692
|
applyProperty(existing().child, change, index, what, type.timestamps ? createdAt : void 0);
|
|
12290
12693
|
break;
|
|
12291
12694
|
case "Add": {
|
|
12292
12695
|
const given2 = change.newValue;
|
|
12293
12696
|
if (!isObject(given2) || typeof given2["@id"] !== "string" || (gridPoint ? type.id(given2["@id"])?.key !== id.key : given2["@id"] !== change.entityId))
|
|
12294
12697
|
throw new POIError(`Change ${index}: the ${type.what} to add must be a JSON object with the identification '${gridPoint ? id.text : change.entityId}'!`);
|
|
12295
|
-
const added = type.timestamps ? entityToAdd(change, index, what, createdAt) : asGiven(given2, void 0,
|
|
12698
|
+
const added = type.timestamps ? entityToAdd(change, index, what, createdAt) : asGiven(given2, void 0, change, index, what);
|
|
12296
12699
|
const children2 = get(party, property);
|
|
12297
12700
|
if (children2 === void 0)
|
|
12298
12701
|
set(party, property, [added]);
|
|
@@ -12310,9 +12713,10 @@ function applyEmbeddedChange(content, change, index, createdAt, type) {
|
|
|
12310
12713
|
break;
|
|
12311
12714
|
}
|
|
12312
12715
|
default:
|
|
12313
|
-
throw new POIError(`Change ${index}: ${change.kind} of
|
|
12716
|
+
throw new POIError(`Change ${index}: ${change.kind} of ${withArticle(type.what, false)} is not supported by this library yet!`);
|
|
12314
12717
|
}
|
|
12315
12718
|
party["lastChange"] = createdAt;
|
|
12719
|
+
return { type: partyType, json: party };
|
|
12316
12720
|
}
|
|
12317
12721
|
function energyMeterChildOf(content, type, childId) {
|
|
12318
12722
|
for (const [partyType, parties] of [["ChargingStationOperator", "chargingStationOperators"], ["GridOperator", "gridOperators"]])
|
|
@@ -12329,19 +12733,22 @@ function applyEnergyMeterChildChange(content, change, index, createdAt) {
|
|
|
12329
12733
|
const what = `${type.what} '${change.entityId}'`;
|
|
12330
12734
|
const found = energyMeterChildOf(content, type, change.entityId);
|
|
12331
12735
|
let party;
|
|
12736
|
+
let partyType;
|
|
12332
12737
|
if (change.kind === "Add") {
|
|
12333
12738
|
if (found !== void 0)
|
|
12334
12739
|
throw new POIError(`Change ${index}: the ${what} already exists!`);
|
|
12335
12740
|
const parent = change.parentEntityType === "ChargingStationOperator" || change.parentEntityType === "GridOperator" ? partyNamed(content, change.parentEntityType, change.parentEntityId) : void 0;
|
|
12336
|
-
if (parent === void 0)
|
|
12741
|
+
if (parent === void 0 || change.parentEntityType === void 0)
|
|
12337
12742
|
throw new POIError(`Change ${index}: the ${what} to add needs its ChargingStationOperator or GridOperator, an existing one!`);
|
|
12338
12743
|
party = parent;
|
|
12744
|
+
partyType = change.parentEntityType;
|
|
12339
12745
|
} else {
|
|
12340
12746
|
if (found === void 0)
|
|
12341
12747
|
throw new POIError(`Change ${index}: the ${what} does not exist!`);
|
|
12342
12748
|
if (change.parentEntityType !== void 0 && (change.parentEntityType !== found.partyType || change.parentEntityId === void 0 || !sameId4(change.parentEntityId, asText(found.party["@id"]))))
|
|
12343
12749
|
throw new POIError(`Change ${index}: the ${what} belongs to ${found.partyType} '${asText(found.party["@id"])}', not to ${change.parentEntityType} '${change.parentEntityId ?? ""}'!`);
|
|
12344
12750
|
party = found.party;
|
|
12751
|
+
partyType = found.partyType;
|
|
12345
12752
|
}
|
|
12346
12753
|
change = resolveElementChange(change, found?.child, what, index);
|
|
12347
12754
|
const isProperty = change.kind === "UpdateProperty" || change.kind === "RemoveProperty";
|
|
@@ -12351,7 +12758,7 @@ function applyEnergyMeterChildChange(content, change, index, createdAt) {
|
|
|
12351
12758
|
case "UpdateProperty":
|
|
12352
12759
|
case "RemoveProperty":
|
|
12353
12760
|
if (!type.changeable.includes(change.propertyName ?? ""))
|
|
12354
|
-
throw new POIError(`Change ${index}: the property '${change.propertyName ?? ""}' of
|
|
12761
|
+
throw new POIError(`Change ${index}: the property '${change.propertyName ?? ""}' of ${withArticle(type.what, false)} can not be changed!`);
|
|
12355
12762
|
applyProperty(existing().child, change, index, what, createdAt);
|
|
12356
12763
|
break;
|
|
12357
12764
|
case "Add": {
|
|
@@ -12373,37 +12780,77 @@ function applyEnergyMeterChildChange(content, change, index, createdAt) {
|
|
|
12373
12780
|
break;
|
|
12374
12781
|
}
|
|
12375
12782
|
default:
|
|
12376
|
-
throw new POIError(`Change ${index}: ${change.kind} of
|
|
12783
|
+
throw new POIError(`Change ${index}: ${change.kind} of ${withArticle(type.what, false)} is not supported by this library yet!`);
|
|
12377
12784
|
}
|
|
12378
12785
|
party["lastChange"] = createdAt;
|
|
12786
|
+
return { type: partyType, json: party };
|
|
12379
12787
|
}
|
|
12380
12788
|
var NETWORK_PROPERTIES = ["name", "description", "dataSource", "dataLicenses", "treeHashAlgorithms", "customData"];
|
|
12789
|
+
function invalidNetworkValue(property, value) {
|
|
12790
|
+
switch (property) {
|
|
12791
|
+
case "name":
|
|
12792
|
+
case "description":
|
|
12793
|
+
return isObject(value) ? void 0 : `invalid ${property}: A multi-language text must be a JSON object!`;
|
|
12794
|
+
case "dataSource":
|
|
12795
|
+
return typeof value === "string" && trimmed(value) !== "" ? void 0 : "the data source must be a nonempty text!";
|
|
12796
|
+
case "dataLicenses":
|
|
12797
|
+
return dataLicenses({ dataLicenses: value });
|
|
12798
|
+
case "treeHashAlgorithms":
|
|
12799
|
+
return value === null ? "the tree hash algorithms must be an array of hash algorithms!" : invalidTreeHashAlgorithms(value);
|
|
12800
|
+
case "customData":
|
|
12801
|
+
return isObject(value) ? void 0 : "the custom data must be a JSON object!";
|
|
12802
|
+
case "signingKeys":
|
|
12803
|
+
case "identityKeys":
|
|
12804
|
+
return "a roaming network has no keys of its own: they are the keys of its RoamingNetworkOperator!";
|
|
12805
|
+
default:
|
|
12806
|
+
return `the property '${property}' of a roaming network can not be changed!`;
|
|
12807
|
+
}
|
|
12808
|
+
}
|
|
12381
12809
|
function applyNetworkChange(content, change, index, createdAt) {
|
|
12382
12810
|
const what = `roaming network '${asText(content["@id"])}'`;
|
|
12383
|
-
const property = entityPropertyName(change) ?? "";
|
|
12384
|
-
const held = NETWORK_PROPERTIES.includes(property) ? get(content, property) : void 0;
|
|
12385
12811
|
const own = {};
|
|
12812
|
+
const ownValue = (property2) => NETWORK_PROPERTIES.includes(property2) ? get(content, property2) : void 0;
|
|
12813
|
+
const given2 = entityPropertyName(change) ?? "";
|
|
12814
|
+
const held = ownValue(given2);
|
|
12386
12815
|
if (held !== void 0)
|
|
12387
|
-
set(own,
|
|
12816
|
+
set(own, given2, held);
|
|
12388
12817
|
change = resolveElementChange(change, own, what, index);
|
|
12389
|
-
|
|
12390
|
-
|
|
12391
|
-
if (!
|
|
12392
|
-
throw new POIError(`Change ${index}: the property '${
|
|
12393
|
-
|
|
12818
|
+
const property = change.propertyName ?? "";
|
|
12819
|
+
const current = ownValue(property);
|
|
12820
|
+
if (change.oldValue !== void 0 && !oldValueMatches(change.oldValue, current))
|
|
12821
|
+
throw new POIError(`Change ${index}: the property '${property}' is no longer the expected old value, but '${contentText(current)}'!`);
|
|
12822
|
+
switch (change.kind) {
|
|
12823
|
+
case "UpdateProperty": {
|
|
12824
|
+
const invalid = change.newValue === void 0 ? void 0 : invalidNetworkValue(property, change.newValue);
|
|
12825
|
+
if (invalid !== void 0)
|
|
12826
|
+
throw new POIError(`Change ${index}: ${invalid}`);
|
|
12827
|
+
break;
|
|
12828
|
+
}
|
|
12829
|
+
case "RemoveProperty":
|
|
12830
|
+
if (current === void 0)
|
|
12831
|
+
throw new POIError(`Change ${index}: the property '${property}' does not exist!`);
|
|
12832
|
+
break;
|
|
12833
|
+
default:
|
|
12834
|
+
throw new POIError(`Change ${index}: ${change.kind} of the roaming network itself is not supported yet!`);
|
|
12835
|
+
}
|
|
12394
12836
|
applyProperty(content, change, index, what, createdAt);
|
|
12395
12837
|
}
|
|
12396
12838
|
function applyOperatorChange(content, change, index, createdAt) {
|
|
12839
|
+
if (change.kind === "Add" || change.kind === "Remove")
|
|
12840
|
+
throw new POIError(`Change ${index}: the operator of a roaming network is changed, but neither added nor removed!`);
|
|
12841
|
+
if (change.parentEntityType !== void 0 && (change.parentEntityType !== "RoamingNetwork" || change.parentEntityId !== content["@id"]))
|
|
12842
|
+
throw new POIError(`Change ${index}: a roaming network operator of this roaming network belongs to RoamingNetwork '${asText(content["@id"])}', not to ${change.parentEntityType} '${change.parentEntityId}'!`);
|
|
12397
12843
|
const operator = get(content, "operator");
|
|
12398
12844
|
if (!isObject(operator) || operator["@id"] !== change.entityId)
|
|
12399
|
-
throw new POIError(`Change ${index}: the roaming network operator '${change.entityId}'
|
|
12845
|
+
throw new POIError(`Change ${index}: the roaming network operator '${change.entityId}' does not exist!`);
|
|
12400
12846
|
change = resolveElementChange(change, operator, `roaming network operator '${change.entityId}'`, index);
|
|
12401
12847
|
if (change.kind !== "UpdateProperty" && change.kind !== "RemoveProperty")
|
|
12402
|
-
throw new POIError(`Change ${index}: the roaming network
|
|
12848
|
+
throw new POIError(`Change ${index}: the operator of a roaming network is changed, but neither added nor removed!`);
|
|
12403
12849
|
if (!RNO_PROPERTIES.includes(change.propertyName ?? ""))
|
|
12404
12850
|
throw new POIError(`Change ${index}: the property '${change.propertyName ?? ""}' of a roaming network operator can not be changed!`);
|
|
12405
12851
|
checkOldValue(change, get(operator, change.propertyName ?? ""), index, `roaming network operator '${change.entityId}'`);
|
|
12406
12852
|
applyProperty(operator, change, index, `roaming network operator '${change.entityId}'`, createdAt);
|
|
12853
|
+
return { type: "RoamingNetworkOperator", json: operator };
|
|
12407
12854
|
}
|
|
12408
12855
|
function partiesOf(network) {
|
|
12409
12856
|
const parties = /* @__PURE__ */ new Map();
|
|
@@ -12418,6 +12865,26 @@ function partiesOf(network) {
|
|
|
12418
12865
|
});
|
|
12419
12866
|
return parties;
|
|
12420
12867
|
}
|
|
12868
|
+
var mayAll = (key2, usages) => usages.every((usage) => key2.maySign(usage));
|
|
12869
|
+
var WEB_PAYMENT_PAGES = /* @__PURE__ */ new Set(["ChargingStationOperator", "ChargingPool", "ChargingStation", "ChargingPoolTemplate", "ChargingStationTemplate"]);
|
|
12870
|
+
var isGiven4 = (value) => value !== void 0 && value !== null;
|
|
12871
|
+
function addsWebPaymentURL(change) {
|
|
12872
|
+
if (change.kind !== "Add" || !isObject(change.newValue))
|
|
12873
|
+
return false;
|
|
12874
|
+
const entity = change.newValue;
|
|
12875
|
+
const stations = entity["chargingStations"];
|
|
12876
|
+
switch (change.entityType) {
|
|
12877
|
+
case "ChargingPool":
|
|
12878
|
+
return isGiven4(entity["webPaymentURL"]) || isArray(stations) && stations.some((station) => isObject(station) && isGiven4(station["webPaymentURL"]));
|
|
12879
|
+
case "ChargingStation":
|
|
12880
|
+
case "ChargingPoolTemplate":
|
|
12881
|
+
case "ChargingStationTemplate":
|
|
12882
|
+
return isGiven4(entity["webPaymentURL"]);
|
|
12883
|
+
default:
|
|
12884
|
+
return false;
|
|
12885
|
+
}
|
|
12886
|
+
}
|
|
12887
|
+
var usagesOf = (change, usage) => WEB_PAYMENT_PAGES.has(change.entityType) && entityPropertyName(change) === "webPaymentURL" ? [KeyUsages.Payments] : usage !== KeyUsages.Payments && addsWebPaymentURL(change) ? [usage, KeyUsages.Payments] : [usage];
|
|
12421
12888
|
var partyKeyOf = (party) => `${party.type}:${party.id.toUpperCase()}`;
|
|
12422
12889
|
var partyRefOf = (content, type, id) => ({ type, id: asText(partyNamed(content, type, id)?.["@id"] ?? id) });
|
|
12423
12890
|
var notRemoved = (earlier, party) => earlier.removedParties.has(partyKeyOf(party)) ? null : party;
|
|
@@ -12572,13 +13039,13 @@ function ownerOf(content, change, index, earlier) {
|
|
|
12572
13039
|
if (embeddedOwners !== void 0)
|
|
12573
13040
|
return embeddedOwners;
|
|
12574
13041
|
if (INFRASTRUCTURE_TYPES.has(change.entityType)) {
|
|
12575
|
-
const
|
|
12576
|
-
if (
|
|
12577
|
-
throw new POIError(`Change ${index}: the
|
|
13042
|
+
const ownerId = operatorIdOf(change.entityType, change.entityId);
|
|
13043
|
+
if (ownerId === void 0)
|
|
13044
|
+
throw new POIError(`Change ${index}: the identification '${change.entityId}' of the ${change.entityType} names no charging station operator!`);
|
|
12578
13045
|
return {
|
|
12579
13046
|
kind: "party",
|
|
12580
13047
|
type: "ChargingStationOperator",
|
|
12581
|
-
id:
|
|
13048
|
+
id: ownerId,
|
|
12582
13049
|
usage: TARIFF_TYPES.has(change.entityType) ? KeyUsages.Tariffs : KeyUsages.Infrastructure,
|
|
12583
13050
|
keys: "signing"
|
|
12584
13051
|
};
|
|
@@ -12664,24 +13131,32 @@ function checkOwnership(before, changeSet) {
|
|
|
12664
13131
|
if (!valid2.has(key2.id))
|
|
12665
13132
|
throw new POIError(`The new identity key '${key2.id}' did not sign the change set: no proof of possession!`);
|
|
12666
13133
|
const signedValid = (key2) => valid2.has(key2.id) && key2.isValidAt(createdAt);
|
|
12667
|
-
const rnoHolders = (keys,
|
|
12668
|
-
...keys !== "identity" ? rnoSigning.filter((key2) =>
|
|
13134
|
+
const rnoHolders = (keys, usages = []) => new Set([
|
|
13135
|
+
...keys !== "identity" ? rnoSigning.filter((key2) => key2.maySign(KeyUsages.Party) || usages.length > 0 && mayAll(key2, usages)) : [],
|
|
12669
13136
|
...keys !== "signing" ? rnoIdentity : []
|
|
12670
13137
|
].filter(signedValid).map((key2) => key2.holderOrUnnamed));
|
|
12671
|
-
const signs = (owner) => {
|
|
13138
|
+
const signs = (owner, change) => {
|
|
12672
13139
|
if (owner.kind === "rno")
|
|
12673
13140
|
return rno !== void 0 && rnoHolders(owner.keys).size >= minConsensus;
|
|
12674
13141
|
const party = parties.get(`${owner.type}:${owner.id}`);
|
|
12675
|
-
|
|
13142
|
+
const usages = usagesOf(change, owner.usage);
|
|
13143
|
+
return party !== void 0 && (owner.keys !== "identity" && party.signingKeys.some((key2) => mayAll(key2, usages) && signedValid(key2)) || owner.keys !== "signing" && party.identityKeys.some(signedValid) || owner.keys !== "signing" && rnoHolders("identity").size >= minConsensus && rnoIdentity.some(signedValid) || owner.keys === "signing" && owner.inPlace !== false && party.signingKeys.length === 0 && rnoHolders("signing", usages).size >= minConsensus);
|
|
13144
|
+
};
|
|
13145
|
+
const inPlaceOf = (owner) => owner.kind === "party" && owner.keys === "signing" && owner.inPlace !== false && parties.get(`${owner.type}:${owner.id}`)?.signingKeys.length === 0;
|
|
13146
|
+
const rnoInWords = rno === void 0 ? "the roaming network operator, of which this roaming network has none" : `the roaming network operator '${rno.id}'`;
|
|
13147
|
+
const byQuorum = (owner) => minConsensus > 1 && (owner.kind === "rno" || inPlaceOf(owner));
|
|
13148
|
+
const signatureOf2 = (owner) => {
|
|
13149
|
+
const kind = owner.keys === "identity" ? "identity" : "signing";
|
|
13150
|
+
return owner.kind === "rno" || inPlaceOf(owner) ? byQuorum(owner) ? `${kind} keys of ${minConsensus} holders of ${rnoInWords}` : `a${kind === "identity" ? "n" : ""} ${kind} key of ${rnoInWords}` : owner.keys === "identity" ? `an identity key of the ${owner.type} '${owner.id}'` : `a signing key of the ${owner.type} '${owner.id}'`;
|
|
12676
13151
|
};
|
|
12677
|
-
const
|
|
13152
|
+
const signaturesOf = (owners) => `${owners.some(byQuorum) ? "signatures" : "a signature"} by ${[...new Set(owners.map(signatureOf2))].join(" or ")}`;
|
|
12678
13153
|
changeSet.changes.forEach((change, index) => {
|
|
12679
13154
|
checkPartyChange(change, index);
|
|
12680
13155
|
const owned = ownerOf(before.content, change, index, earlier);
|
|
12681
13156
|
const owners = isOwnerList(owned) ? owned : [owned];
|
|
12682
13157
|
if (owners.length > 1) {
|
|
12683
|
-
if (!owners.some(signs))
|
|
12684
|
-
throw new POIError(`${describeChange(change, index)} needs
|
|
13158
|
+
if (!owners.some((owner2) => signs(owner2, change)))
|
|
13159
|
+
throw new POIError(`${describeChange(change, index)} needs ${signaturesOf(owners)}!`);
|
|
12685
13160
|
return;
|
|
12686
13161
|
}
|
|
12687
13162
|
const owner = required(owners[0], `Change ${index} has no owner!`);
|
|
@@ -12695,14 +13170,21 @@ function checkOwnership(before, changeSet) {
|
|
|
12695
13170
|
}
|
|
12696
13171
|
const party = parties.get(`${owner.type}:${owner.id}`);
|
|
12697
13172
|
if (party === void 0)
|
|
12698
|
-
throw new POIError(`${describeChange(change, index)}
|
|
12699
|
-
const
|
|
13173
|
+
throw new POIError(owner.keys === "identity" ? `${describeChange(change, index)} needs a signature by an identity key of the ${owner.type} '${owner.id}'!` : `${describeChange(change, index)} needs a signature by a signing key of the ${owner.type} '${owner.id}'!`);
|
|
13174
|
+
const usages = usagesOf(change, owner.usage);
|
|
13175
|
+
const bySigningKey = owner.keys !== "identity" && party.signingKeys.some((key2) => mayAll(key2, usages) && signedValid(key2));
|
|
12700
13176
|
const byIdentityKey = owner.keys !== "signing" && party.identityKeys.some(signedValid);
|
|
12701
13177
|
const byRecovery = owner.keys !== "signing" && rnoHolders("identity").size >= minConsensus && rnoIdentity.some(signedValid);
|
|
12702
|
-
const byRNO = owner.keys === "signing" && owner.inPlace !== false && party.signingKeys.length === 0 && rnoHolders("signing",
|
|
13178
|
+
const byRNO = owner.keys === "signing" && owner.inPlace !== false && party.signingKeys.length === 0 && rnoHolders("signing", usages).size >= minConsensus;
|
|
12703
13179
|
if (!bySigningKey && !byIdentityKey && !byRecovery && !byRNO) {
|
|
13180
|
+
const allOf = usages.map((usage) => `'${usage}'`).join(" and ");
|
|
13181
|
+
if (inPlaceOf(owner)) {
|
|
13182
|
+
const anyOf2 = usages.length === 1 && usages[0] === KeyUsages.Party ? allOf : `${allOf} or '${KeyUsages.Party}'`;
|
|
13183
|
+
const named2 = rnoSigning.some((key2) => signedValid(key2) && !mayAll(key2, usages) && !key2.maySign(KeyUsages.Party));
|
|
13184
|
+
throw new POIError(`${describeChange(change, index)} needs ${signaturesOf([owner])}${named2 ? ` that may sign ${anyOf2}` : ""}!`);
|
|
13185
|
+
}
|
|
12704
13186
|
const mayAnyway = party.signingKeys.some(signedValid);
|
|
12705
|
-
throw new POIError(owner.keys === "identity" ? `${describeChange(change, index)} needs a signature by an identity key of the ${owner.type} '${owner.id}'!` : mayAnyway ? `${describeChange(change, index)} needs a signature by a signing key of the ${owner.type} '${owner.id}' that may sign
|
|
13187
|
+
throw new POIError(owner.keys === "identity" ? `${describeChange(change, index)} needs a signature by an identity key of the ${owner.type} '${owner.id}'!` : mayAnyway ? `${describeChange(change, index)} needs a signature by a signing key of the ${owner.type} '${owner.id}' that may sign ${allOf}!` : `${describeChange(change, index)} needs a signature by a signing key of the ${owner.type} '${owner.id}'!`);
|
|
12706
13188
|
}
|
|
12707
13189
|
});
|
|
12708
13190
|
}
|
|
@@ -12721,7 +13203,7 @@ function stampOf(before, changeSet) {
|
|
|
12721
13203
|
return last !== void 0 && last > changeSet.createdAt ? last : changeSet.createdAt;
|
|
12722
13204
|
}
|
|
12723
13205
|
function applyChangeSet(before, changeSet, options = {}) {
|
|
12724
|
-
if (changeSet.roamingNetworkId !== before.id)
|
|
13206
|
+
if (ignoringCase(changeSet.roamingNetworkId) !== ignoringCase(before.id))
|
|
12725
13207
|
throw new POIError(`The change set is for the roaming network '${changeSet.roamingNetworkId}', not for '${before.id}'!`);
|
|
12726
13208
|
if (options.checkOwnership ?? true)
|
|
12727
13209
|
checkOwnership(before, changeSet);
|
|
@@ -12731,23 +13213,37 @@ function applyChangeSet(before, changeSet, options = {}) {
|
|
|
12731
13213
|
throw new POIError(`The change set does not fit this version of the roaming network: ${broken}`);
|
|
12732
13214
|
const content = clone(before.content);
|
|
12733
13215
|
const createdAt = toTimestamp(stampOf(before, changeSet));
|
|
12734
|
-
|
|
13216
|
+
function applyChange(change, index) {
|
|
13217
|
+
let changed;
|
|
12735
13218
|
if (change.entityType === "RoamingNetwork" && change.entityId === before.id)
|
|
12736
13219
|
applyNetworkChange(content, change, index, createdAt);
|
|
12737
13220
|
else if (change.entityType === "RoamingNetworkOperator")
|
|
12738
|
-
applyOperatorChange(content, change, index, createdAt);
|
|
13221
|
+
changed = applyOperatorChange(content, change, index, createdAt);
|
|
12739
13222
|
else if (NETWORK_ARRAYS[change.entityType] !== void 0)
|
|
12740
|
-
applyNetworkArrayChange(content, change, index, createdAt);
|
|
13223
|
+
changed = applyNetworkArrayChange(content, change, index, createdAt);
|
|
12741
13224
|
else if (PARTY_CHILD_TYPES[change.entityType] !== void 0)
|
|
12742
|
-
applyPartyChildChange(content, change, index, createdAt);
|
|
13225
|
+
changed = applyPartyChildChange(content, change, index, createdAt);
|
|
12743
13226
|
else if (ENERGY_METER_CHILD_TYPES[change.entityType] !== void 0)
|
|
12744
|
-
applyEnergyMeterChildChange(content, change, index, createdAt);
|
|
13227
|
+
changed = applyEnergyMeterChildChange(content, change, index, createdAt);
|
|
12745
13228
|
else if (embeddedTypeOf(content, change) !== void 0)
|
|
12746
|
-
applyEmbeddedChange(content, change, index, createdAt, required(embeddedTypeOf(content, change), change.entityType));
|
|
13229
|
+
changed = applyEmbeddedChange(content, change, index, createdAt, required(embeddedTypeOf(content, change), change.entityType));
|
|
12747
13230
|
else if (INFRASTRUCTURE_TYPES.has(change.entityType))
|
|
12748
|
-
applyInfrastructureChange(content, change, index, createdAt);
|
|
13231
|
+
changed = applyInfrastructureChange(content, change, index, createdAt);
|
|
12749
13232
|
else
|
|
12750
13233
|
throw new POIError(`Change ${index}: changes of ${change.entityType} '${change.entityId}' are not supported by this library yet!`);
|
|
13234
|
+
const invalid = changed === void 0 ? void 0 : changed.type === "RoamingNetworkOperator" ? invalidRoamingNetworkOperator(changed.json, before.id) : invalidParty(changed.type, changed.json);
|
|
13235
|
+
if (invalid !== void 0)
|
|
13236
|
+
throw new POIError(`Change ${index}: ${invalid}`);
|
|
13237
|
+
for (const check2 of heldChecks ?? [])
|
|
13238
|
+
check2();
|
|
13239
|
+
}
|
|
13240
|
+
changeSet.changes.forEach((change, index) => {
|
|
13241
|
+
heldChecks = [];
|
|
13242
|
+
try {
|
|
13243
|
+
applyChange(change, index);
|
|
13244
|
+
} finally {
|
|
13245
|
+
heldChecks = void 0;
|
|
13246
|
+
}
|
|
12751
13247
|
});
|
|
12752
13248
|
const groupOrOffer = objectsOf4(get(content, "chargingStationOperators")).sort((left, right) => ordinal(asText(left["@id"]), asText(right["@id"]))).map((operator) => invalidGroupOrOffer(operator) ?? invalidPaymentOption(operator)).find((error) => error !== void 0);
|
|
12753
13249
|
if (groupOrOffer !== void 0)
|
|
@@ -13712,7 +14208,7 @@ function manufacturerOf(network, kind, id) {
|
|
|
13712
14208
|
}
|
|
13713
14209
|
var CHARGING_STATION_ID = /^([a-zA-Z]{2}\*?[a-zA-Z0-9]{3})\*?S([a-zA-Z0-9][a-zA-Z0-9*]{0,29})$/u;
|
|
13714
14210
|
var OPERATOR_ID = /^([A-Z]{2})\*?([A-Z0-9]{3})$/u;
|
|
13715
|
-
function
|
|
14211
|
+
function operatorIdOf2(text2) {
|
|
13716
14212
|
const match = OPERATOR_ID.exec((idOf2(text2) ?? "").toUpperCase());
|
|
13717
14213
|
return match === null ? void 0 : `${match[1] ?? ""}*${match[2] ?? ""}`;
|
|
13718
14214
|
}
|
|
@@ -13720,13 +14216,13 @@ function chargingStationIdOf(text2) {
|
|
|
13720
14216
|
const match = CHARGING_STATION_ID.exec(idOf2(text2) ?? "");
|
|
13721
14217
|
if (match === null)
|
|
13722
14218
|
return void 0;
|
|
13723
|
-
const operatorId2 =
|
|
14219
|
+
const operatorId2 = operatorIdOf2(match[1] ?? "");
|
|
13724
14220
|
return operatorId2 === void 0 ? void 0 : { operatorId: operatorId2, suffix: match[2] ?? "" };
|
|
13725
14221
|
}
|
|
13726
14222
|
var chargingStationIdText = (id) => `${id.operatorId}*S${id.suffix}`;
|
|
13727
14223
|
var sameChargingStation = (left, right) => left.operatorId === right.operatorId && sameId(left.suffix.replaceAll("*", ""), right.suffix.replaceAll("*", ""));
|
|
13728
14224
|
function effectiveChargingStationOf(network, id) {
|
|
13729
|
-
const operator = objectsOf5(get(network.effectiveContent, "chargingStationOperators")).find((item) =>
|
|
14225
|
+
const operator = objectsOf5(get(network.effectiveContent, "chargingStationOperators")).find((item) => operatorIdOf2(entityId(item)) === id.operatorId);
|
|
13730
14226
|
for (const pool of objectsOf5(get(operator ?? {}, "chargingPools")))
|
|
13731
14227
|
for (const station of objectsOf5(get(pool, "chargingStations"))) {
|
|
13732
14228
|
const stationId2 = chargingStationIdOf(entityId(station));
|
|
@@ -16125,6 +16621,16 @@ var EVTalerContractTerms = class _EVTalerContractTerms {
|
|
|
16125
16621
|
};
|
|
16126
16622
|
}
|
|
16127
16623
|
};
|
|
16624
|
+
function evTalerSessionPrices(station, evseId2, priceStatements, at) {
|
|
16625
|
+
const tariff2 = evTalerTariff(station, evseId2);
|
|
16626
|
+
const current = verifyPriceStatements(station, priceStatements, { at });
|
|
16627
|
+
const tariffId2 = idOf7(tariff2);
|
|
16628
|
+
const specificity = (entityType) => entityType === "EVSE" ? 0 : entityType === "ChargingStation" ? 1 : 2;
|
|
16629
|
+
const [priceStatement] = [...current.values()].filter((candidate) => candidate.statement.prices.some((prices) => tariffId(textOf4(get(prices, "chargingTariffId")))?.text === tariffId2)).sort((left, right) => specificity(left.statement.entityType) - specificity(right.statement.entityType));
|
|
16630
|
+
const objects4 = (value) => isArray(value) ? value.filter(isObject) : [];
|
|
16631
|
+
const elements = priceStatement !== void 0 ? objects4(get(objects4(get(priceStatement.statement.priceStatus, "prices")).find((prices) => get(prices, "chargingTariffId") === tariffId2) ?? {}, "elements")) : objects4(get(tariff2, "elements"));
|
|
16632
|
+
return { tariff: tariff2, ...priceStatement === void 0 ? {} : { priceStatement }, elements };
|
|
16633
|
+
}
|
|
16128
16634
|
function evTalerTariff(station, evseId2) {
|
|
16129
16635
|
const tariffs = station.tariffs.get(evseId2) ?? [];
|
|
16130
16636
|
const typeOf2 = (tariff3) => {
|
|
@@ -17118,10 +17624,33 @@ function verifyPricePublication(receipts, policy, subject) {
|
|
|
17118
17624
|
});
|
|
17119
17625
|
}
|
|
17120
17626
|
|
|
17627
|
+
// src/verifier/grossRates.ts
|
|
17628
|
+
function grossRates(currency2, elements) {
|
|
17629
|
+
if (elements.length !== 1) return void 0;
|
|
17630
|
+
const element = elements[0];
|
|
17631
|
+
if (element === void 0 || Object.keys(element).some((key2) => key2 !== "priceComponents" && key2 !== "restrictions")) return void 0;
|
|
17632
|
+
if (element["restrictions"] !== void 0 && (!isObject(element["restrictions"]) || Object.keys(element["restrictions"]).length > 0)) return void 0;
|
|
17633
|
+
const components = element["priceComponents"];
|
|
17634
|
+
if (!Array.isArray(components) || components.length === 0) return void 0;
|
|
17635
|
+
const rates = { currency: currency2 };
|
|
17636
|
+
for (const raw of components) {
|
|
17637
|
+
if (!isObject(raw) || Object.keys(raw).some((key2) => !["type", "price", "stepSize"].includes(key2))) return void 0;
|
|
17638
|
+
const type = raw["type"], value = raw["price"], step = raw["stepSize"];
|
|
17639
|
+
if (!isNumber(value) || Decimal.parse(asText(value)).mantissa < 0n) return void 0;
|
|
17640
|
+
if (type === "FLAT" ? "stepSize" in raw : typeof step !== "number" || !Number.isSafeInteger(step) || step < 1) return void 0;
|
|
17641
|
+
const field = type === "ENERGY" ? "energyPerKWh" : type === "FLAT" ? "flatFee" : type === "TIME" ? "timePerHour" : void 0;
|
|
17642
|
+
if (field === void 0 || rates[field] !== void 0) return void 0;
|
|
17643
|
+
rates[field] = asText(value);
|
|
17644
|
+
}
|
|
17645
|
+
return rates;
|
|
17646
|
+
}
|
|
17647
|
+
|
|
17121
17648
|
// src/verifier/sessionPrices.ts
|
|
17122
17649
|
var SESSION_PRICE_EVIDENCE_CONTEXT = "https://open.charging.cloud/contexts/wwcp/sessionPriceEvidence/v1";
|
|
17123
17650
|
var SESSION_PRICE_AGREEMENT_CONTEXT = "https://open.charging.cloud/contexts/wwcp/sessionPriceAgreement/v1";
|
|
17124
17651
|
var SIMPLE_GROSS_PRICE_PROFILE = "chargy-gross-rates/v1";
|
|
17652
|
+
var CONTRACT_GROSS_PRICE_PROFILE = "chargy-contract-gross-rates/v1";
|
|
17653
|
+
var GROSS_PRICE_PROFILES = /* @__PURE__ */ new Map([["adhoc", SIMPLE_GROSS_PRICE_PROFILE], ["contract", CONTRACT_GROSS_PRICE_PROFILE]]);
|
|
17125
17654
|
var SessionPriceAgreement = class _SessionPriceAgreement {
|
|
17126
17655
|
constructor(json, chargingStarted, signedAt) {
|
|
17127
17656
|
this.json = json;
|
|
@@ -17172,24 +17701,6 @@ function parseSessionPriceEvidence(value) {
|
|
|
17172
17701
|
})
|
|
17173
17702
|
};
|
|
17174
17703
|
}
|
|
17175
|
-
function grossRates(currency2, elements) {
|
|
17176
|
-
if (elements.length !== 1) return void 0;
|
|
17177
|
-
const element = elements[0];
|
|
17178
|
-
if (element === void 0 || Object.keys(element).some((key2) => key2 !== "priceComponents" && key2 !== "restrictions")) return void 0;
|
|
17179
|
-
if (element["restrictions"] !== void 0 && (!isObject(element["restrictions"]) || Object.keys(element["restrictions"]).length > 0)) return void 0;
|
|
17180
|
-
const components = element["priceComponents"];
|
|
17181
|
-
if (!Array.isArray(components) || components.length === 0) return void 0;
|
|
17182
|
-
const rates = { currency: currency2 };
|
|
17183
|
-
for (const raw of components) {
|
|
17184
|
-
if (!isObject(raw) || Object.keys(raw).some((key2) => !["type", "price", "stepSize"].includes(key2))) return void 0;
|
|
17185
|
-
const type = raw["type"], value = raw["price"], step = raw["stepSize"];
|
|
17186
|
-
if (!isNumber(value) || Decimal.parse(asText(value)).mantissa < 0n || typeof step !== "number" || !Number.isSafeInteger(step) || step < 1) return void 0;
|
|
17187
|
-
const field = type === "ENERGY" ? "energyPerKWh" : type === "FLAT" ? "flatFee" : type === "TIME" ? "timePerHour" : void 0;
|
|
17188
|
-
if (field === void 0 || rates[field] !== void 0) return void 0;
|
|
17189
|
-
rates[field] = asText(value);
|
|
17190
|
-
}
|
|
17191
|
-
return rates;
|
|
17192
|
-
}
|
|
17193
17704
|
function verifySessionPriceEvidence(current, value, request, policy = {}) {
|
|
17194
17705
|
if (!(current instanceof TrustContext) && !(current instanceof HistoricalTrustContext)) throw new POIError("Session prices require current local authorization");
|
|
17195
17706
|
if (!Number.isFinite(request.chargingStarted) || request.chargingStarted > current.evaluatedAt || !isLowerHex(request.startDocumentSHA256, 32)) throw new POIError("Invalid original price context");
|
|
@@ -17240,7 +17751,7 @@ function verifySessionPriceEvidence(current, value, request, policy = {}) {
|
|
|
17240
17751
|
if (selected === void 0) throw new POIError("Missing selected price");
|
|
17241
17752
|
const currency2 = requireString(selected.tariff, "currency"), elements = requireArray(selected.price["elements"], "Signed price elements").map((item) => requireObject(item, "A signed price element")), rates = grossRates(currency2, elements);
|
|
17242
17753
|
let applicability = agreement === void 0 ? "unbound" : "bound";
|
|
17243
|
-
if (agreement !== void 0 && (agreement.json["
|
|
17754
|
+
if (agreement !== void 0 && (agreement.json["pricingProfile"] !== GROSS_PRICE_PROFILES.get(asText(agreement.json["chargingMode"])) || agreement.json["priceBinding"] !== "fixed-at-start" || rates === void 0)) {
|
|
17244
17755
|
applicability = "unsupported";
|
|
17245
17756
|
diagnostics.push("EMP/contract terms, variable binding, unknown price profile or conditional elements are not established by this profile");
|
|
17246
17757
|
}
|
|
@@ -17315,7 +17826,7 @@ function verifySessionPriceEvidence(current, value, request, policy = {}) {
|
|
|
17315
17826
|
diagnostics,
|
|
17316
17827
|
checkpointIds,
|
|
17317
17828
|
witnessedBy: [...witnessed],
|
|
17318
|
-
selected: { statement: selected.statement.json, digest: selected.digest, tariff: selected.tariff, currency: currency2, elements, ...rates === void 0 || agreement?.json["pricingProfile"]
|
|
17829
|
+
selected: { statement: selected.statement.json, digest: selected.digest, tariff: selected.tariff, currency: currency2, elements, ...rates === void 0 || ![...GROSS_PRICE_PROFILES.values()].includes(asText(agreement?.json["pricingProfile"])) ? {} : { rates } }
|
|
17319
17830
|
};
|
|
17320
17831
|
}
|
|
17321
17832
|
|
|
@@ -17761,6 +18272,6 @@ function applyVerifiedTrustTransition(before, verified, at) {
|
|
|
17761
18272
|
}
|
|
17762
18273
|
var initialTrustEpoch = () => ({ number: 1, profiles: EpochProfiles.FIRST });
|
|
17763
18274
|
|
|
17764
|
-
export { ATTESTATION_CONTEXT, ArchiveSegment, Attestation, CHANGE_SET_CONTEXT, CHARGING_DOCUMENT_USAGE, CHECKPOINT_CONTEXT2 as CHECKPOINT_CONTEXT, CHILD_ARRAYS, COMMIT_CONTEXT2 as COMMIT_CONTEXT, CONTEXT_PREFIX, ChangeSet, ChargingStationProof, Checkpoint, CheckpointProof, Commit, DCCMeasurementResult, DCCResult, DCCStatement, DCC_PERFORMANCE_LOCATIONS, DCOC_MODULES, DDoCNotifiedBody, Decimal, DigitalCalibrationCertificate, DigitalCertificateOfConformity, DigitalDeclarationOfConformity, EPOCH_CONTEXT, EPOCH_LINK_CONTEXT, EPOCH_PROFILES_CONTEXT, EVTalerAmountChecks, EVTalerContractTerms, EVTalerCovers, EVTalerPayURI, EVTalerRates, EVTalerSettlement, EVTalerSignedMeterValue, EVTalerStep, EV_TALER_EXCHANGE_CONTEXT, EV_TALER_MERCHANT_CONTEXT, EV_TALER_PAYMENT_MEANS, EV_TALER_PAYMENT_OPTION, EV_TALER_SETTLEMENT_CONTEXT, EV_TALER_STEP_CONTEXT, EpochProfiles, FIRST_EPOCH, HISTORICAL_METER_EVIDENCE_CONTEXT, HistoricalTrustContext, History, KEY_STATEMENT_CONTEXT, KeyStatement, KeyUsages, LIVE_TOPICS, MAX_DECIMAL_SCALE, MAX_PRICE_STATEMENT_SEQUENCE, MERGE_CHANGE_SET_ID_PREFIX, MeasurementKeyError, NetDecimal, OperatorTrust, POIClient, POIError, POIPublicKey, PRICE_PUBLICATION_RECEIPT_CONTEXT, PROOF_CONTEXT, PricePublicationReceipt, PriceStatement, PriceStatementProof, QIDigitalDocument, QIDigitalItem, QIDigitalLegislation, QIDigitalManufacturer, QIDigitalModel, QIDigitalPerson, QIDigitalQuantity, QIDigitalSignature, QIDigitalStandard, QI_DIGITAL_CONFORMITIES, ROAMING_NETWORK_CONTEXT, RUNTIME_STATUS_KINDS, RoamingNetwork, RoamingNetworkOperator, RuntimeStatus, SESSION_PRICE_AGREEMENT_CONTEXT, SESSION_PRICE_EVIDENCE_CONTEXT, SIGNATURE_ALGORITHMS, SIGNING_KEY_CERTIFICATE_CONTEXT, SIMPLE_GROSS_PRICE_PROFILE, STATUS_UPDATE_CONTEXT, STYX_CANONICAL_JSON, SessionPriceAgreement, SignatureRoles, SigningKeyCertificate, TRUST_ANCHOR_CONTEXT, TRUST_ANCHOR_QR_PREFIX, TRUST_TRANSITION_CONTEXT, TrustAnchor, TrustContext, TrustTransition, VerifiedTrustTransition, WITNESS_PUBLICATION_POLICY_CONTEXT, applyChangeSet, applyVerifiedTrustTransition, approvesQualitySystem, auditPath, canonicalJSON, canonicalJSONBytes, canonicalString, cborETag, cborToJson, changeSetIdentification, check, checkOwnership, checkpointRootVersionObservation, checkpointVersionObservation, clone, commitsRoot, compareObservedVersions, decodeDeterministicCbor, describeVersion, deterministicCbor, effectiveChargingStationOperator, effectiveContent, effectiveTreeETag, emptyObservedVersions, entityDigest, etagToJSON, etagToText, evTalerExchangesAt, evTalerMerchantOf, evTalerTariff, evTalerTariffOf, fromBase45, fromBase64, fromHex, fromJavaScript, get, givesCompletely, hash, historicalOperatorContext, initialTrustEpoch, isArray, isEVTalerSessionId, isObject, isTalerPublicKey, jsonETag, jsonToCbor, keyMaySignIn, leafHash, liveRequest, merkleRoot, merkleRootOfLeafHashes, minorUnitDigits, nodeHash, observedVersionsChecksum, parseArchiveSegmentInfo, parseETag, parseETags, parseEpoch, parseEpochLink, parseEvidence, parseFrame, parseHistoricalMeterEvidence, parseJSON, parseJSONBytes, parseJSONObject, parseMeasurementPublicKey, parsePriceStatements, parseSessionPriceEvidence, parseStatusUpdate, parseTimestamp, parseTrustedWitnesses, parseWitnessPublicationPolicy, paymentOptionName, prettyJSON, pricePublicationOfferHashes, priceStatementChainOf, priceStatementsRoot, priceVersionObservation, prunedTree, publicPublicationURL, qiDigitalContext, rootFromAuditPath, roundToNearest, roundUp, sameBaseURL, sameETag, sameETags, sameEpoch, sameValue, sizeOf, skeleton, stationVersionObservation, subscribeRequest, talerAmountOf, toBase45, toBase64, toHex, toTimestamp, trustPolicyId, trustStatementDigest, verifyAuthorizedCheckpoint, verifyChargingDocumentKeys, verifyChargingStation, verifyCheckpointLine, verifyCheckpointPriceStatements, verifyCheckpointSignatures, verifyEvidence, verifyHistoricalMeterEvidence, verifyMeterKey, verifyMeterValue, verifyPricePublication, verifyPriceStatementChain, verifyPriceStatements, verifySegmentLine, verifySessionPriceEvidence, verifySignature, verifyVersion, writeAmount, writeDecimal };
|
|
18275
|
+
export { ATTESTATION_CONTEXT, ArchiveSegment, Attestation, CHANGE_SET_CONTEXT, CHARGING_DOCUMENT_USAGE, CHECKPOINT_CONTEXT2 as CHECKPOINT_CONTEXT, CHILD_ARRAYS, COMMIT_CONTEXT2 as COMMIT_CONTEXT, CONTEXT_PREFIX, CONTRACT_GROSS_PRICE_PROFILE, ChangeSet, ChargingStationProof, Checkpoint, CheckpointProof, Commit, DCCMeasurementResult, DCCResult, DCCStatement, DCC_PERFORMANCE_LOCATIONS, DCOC_MODULES, DDoCNotifiedBody, Decimal, DigitalCalibrationCertificate, DigitalCertificateOfConformity, DigitalDeclarationOfConformity, EPOCH_CONTEXT, EPOCH_LINK_CONTEXT, EPOCH_PROFILES_CONTEXT, EVTalerAmountChecks, EVTalerContractTerms, EVTalerCovers, EVTalerPayURI, EVTalerRates, EVTalerSettlement, EVTalerSignedMeterValue, EVTalerStep, EV_TALER_EXCHANGE_CONTEXT, EV_TALER_MERCHANT_CONTEXT, EV_TALER_PAYMENT_MEANS, EV_TALER_PAYMENT_OPTION, EV_TALER_SETTLEMENT_CONTEXT, EV_TALER_STEP_CONTEXT, EpochProfiles, FIRST_EPOCH, HISTORICAL_METER_EVIDENCE_CONTEXT, HistoricalTrustContext, History, KEY_STATEMENT_CONTEXT, KeyStatement, KeyUsages, LIVE_TOPICS, MAX_DECIMAL_SCALE, MAX_PRICE_STATEMENT_SEQUENCE, MERGE_CHANGE_SET_ID_PREFIX, MeasurementKeyError, NetDecimal, OperatorTrust, POIClient, POIError, POIPublicKey, PRICE_PUBLICATION_RECEIPT_CONTEXT, PROOF_CONTEXT, PricePublicationReceipt, PriceStatement, PriceStatementProof, QIDigitalDocument, QIDigitalItem, QIDigitalLegislation, QIDigitalManufacturer, QIDigitalModel, QIDigitalPerson, QIDigitalQuantity, QIDigitalSignature, QIDigitalStandard, QI_DIGITAL_CONFORMITIES, ROAMING_NETWORK_CONTEXT, RUNTIME_STATUS_KINDS, RoamingNetwork, RoamingNetworkOperator, RuntimeStatus, SESSION_PRICE_AGREEMENT_CONTEXT, SESSION_PRICE_EVIDENCE_CONTEXT, SIGNATURE_ALGORITHMS, SIGNING_KEY_CERTIFICATE_CONTEXT, SIMPLE_GROSS_PRICE_PROFILE, STATUS_UPDATE_CONTEXT, STYX_CANONICAL_JSON, SessionPriceAgreement, SignatureRoles, SigningKeyCertificate, TRUST_ANCHOR_CONTEXT, TRUST_ANCHOR_QR_PREFIX, TRUST_TRANSITION_CONTEXT, TrustAnchor, TrustContext, TrustTransition, VerifiedTrustTransition, WITNESS_PUBLICATION_POLICY_CONTEXT, applyChangeSet, applyVerifiedTrustTransition, approvesQualitySystem, auditPath, canonicalJSON, canonicalJSONBytes, canonicalString, cborETag, cborToJson, changeSetIdentification, check, checkOwnership, checkpointRootVersionObservation, checkpointVersionObservation, clone, commitsRoot, compareObservedVersions, decodeDeterministicCbor, describeVersion, deterministicCbor, effectiveChargingStationOperator, effectiveContent, effectiveTreeETag, emptyObservedVersions, entityDigest, etagToJSON, etagToText, evTalerExchangesAt, evTalerMerchantOf, evTalerSessionPrices, evTalerTariff, evTalerTariffOf, fromBase45, fromBase64, fromHex, fromJavaScript, get, givesCompletely, hash, historicalOperatorContext, initialTrustEpoch, isArray, isEVTalerSessionId, isObject, isTalerPublicKey, jsonETag, jsonToCbor, keyMaySignIn, leafHash, liveRequest, merkleRoot, merkleRootOfLeafHashes, minorUnitDigits, nodeHash, observedVersionsChecksum, parseArchiveSegmentInfo, parseETag, parseETags, parseEpoch, parseEpochLink, parseEvidence, parseFrame, parseHistoricalMeterEvidence, parseJSON, parseJSONBytes, parseJSONObject, parseMeasurementPublicKey, parsePriceStatements, parseSessionPriceEvidence, parseStatusUpdate, parseTimestamp, parseTrustedWitnesses, parseWitnessPublicationPolicy, paymentOptionName, prettyJSON, pricePublicationOfferHashes, priceStatementChainOf, priceStatementsRoot, priceVersionObservation, prunedTree, publicPublicationURL, qiDigitalContext, rootFromAuditPath, roundToNearest, roundUp, sameBaseURL, sameETag, sameETags, sameEpoch, sameValue, sizeOf, skeleton, stationVersionObservation, subscribeRequest, talerAmountOf, toBase45, toBase64, toHex, toTimestamp, trustPolicyId, trustStatementDigest, verifyAuthorizedCheckpoint, verifyChargingDocumentKeys, verifyChargingStation, verifyCheckpointLine, verifyCheckpointPriceStatements, verifyCheckpointSignatures, verifyEvidence, verifyHistoricalMeterEvidence, verifyMeterKey, verifyMeterValue, verifyPricePublication, verifyPriceStatementChain, verifyPriceStatements, verifySegmentLine, verifySessionPriceEvidence, verifySignature, verifyVersion, writeAmount, writeDecimal };
|
|
17765
18276
|
//# sourceMappingURL=index.js.map
|
|
17766
18277
|
//# sourceMappingURL=index.js.map
|