@atmosx/event-product-parser 3.0.4 → 3.0.42
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/README.md +9 -0
- package/dist/cjs/index.cjs +75 -57
- package/dist/esm/index.mjs +74 -57
- package/dist/index.d.mts +28 -3
- package/dist/index.d.ts +28 -3
- package/package.json +1 -1
- package/src/@building/building.office.ts +1 -1
- package/src/@building/building.properties.ts +5 -1
- package/src/@building/building.signature.ts +1 -1
- package/src/@building/building.tracking.ts +7 -7
- package/src/@building/building.validate.ts +1 -3
- package/src/@core/core.query.ts +39 -0
- package/src/@core/core.setNode.ts +2 -2
- package/src/@core/core.start.ts +1 -1
- package/src/@dictionaries/dictionaries.officeICAOs.ts +2 -0
- package/src/{@modules/@utilities/utilities.createWebhook.ts → @manager/manager.createWebhook.ts} +12 -10
- package/src/@manager/manager.mkEvent.ts +5 -12
- package/src/@manager/manager.setHash.ts +1 -1
- package/src/@manager/manager.updateWebhooks.ts +1 -2
- package/src/@modules/@utilities/utilities.setTimeoutAction.ts +1 -1
- package/src/@modules/@xmpp/xmpp.xReconnect.ts +1 -1
- package/src/@parsers/@pvtec/pvtec.extract.ts +1 -1
- package/src/@parsers/@ugc/ugc.coordinates.ts +2 -2
- package/src/bootstrap.ts +1 -1
- package/src/index.ts +3 -2
package/dist/esm/index.mjs
CHANGED
|
@@ -10491,7 +10491,7 @@ var require_form_data = __commonJS({
|
|
|
10491
10491
|
import path from "path";
|
|
10492
10492
|
import { EventEmitter } from "events";
|
|
10493
10493
|
var bootstrap = {
|
|
10494
|
-
version: `3.0.
|
|
10494
|
+
version: `3.0.42`,
|
|
10495
10495
|
isReady: true,
|
|
10496
10496
|
ratelimits: {},
|
|
10497
10497
|
session_xmpp: null,
|
|
@@ -10605,6 +10605,7 @@ var getSettings = () => {
|
|
|
10605
10605
|
// src/@parsers/@ugc/ugc.coordinates.ts
|
|
10606
10606
|
import { union } from "polygon-clipping";
|
|
10607
10607
|
var getZonePolygon = (options) => {
|
|
10608
|
+
var _a, _b;
|
|
10608
10609
|
const list = [...new Set(options.zones.map((z) => z.trim()))].filter((z) => z === "XX000" ? false : true);
|
|
10609
10610
|
if (list.length === 0) return null;
|
|
10610
10611
|
const placeholders = list.map(() => "?").join(",");
|
|
@@ -10640,7 +10641,7 @@ var getZonePolygon = (options) => {
|
|
|
10640
10641
|
}
|
|
10641
10642
|
if (!bestPoly || bestPoly.length === 0) return null;
|
|
10642
10643
|
const outerRing = bestPoly[0];
|
|
10643
|
-
const skip = Math.max(1, parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10)
|
|
10644
|
+
const skip = Math.max(1, (_a = parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10)) != null ? _a : 1);
|
|
10644
10645
|
let skipped = outerRing.filter((_, idx) => idx % skip === 0);
|
|
10645
10646
|
if (skipped.length < 4) {
|
|
10646
10647
|
skipped = outerRing.slice();
|
|
@@ -10659,7 +10660,7 @@ var getZonePolygon = (options) => {
|
|
|
10659
10660
|
}
|
|
10660
10661
|
}
|
|
10661
10662
|
if (multi.length === 0) return null;
|
|
10662
|
-
const skip = Math.max(1, parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10)
|
|
10663
|
+
const skip = Math.max(1, (_b = parseInt(String(bootstrap.settings.GlobalSettings.ShapefileSkipPoints), 10)) != null ? _b : 1);
|
|
10663
10664
|
if (skip > 1) {
|
|
10664
10665
|
for (let p = 0; p < multi.length; p++) {
|
|
10665
10666
|
for (let r = 0; r < multi[p].length; r++) {
|
|
@@ -10716,7 +10717,7 @@ var getCleanedEvent = (event) => {
|
|
|
10716
10717
|
|
|
10717
10718
|
// src/@modules/@utilities/utilities.setTimeoutAction.ts
|
|
10718
10719
|
var setTimeoutAction = (options) => {
|
|
10719
|
-
var _a, _b;
|
|
10720
|
+
var _a, _b, _c;
|
|
10720
10721
|
let target = (_b = (_a = bootstrap) == null ? void 0 : _a.ratelimits) == null ? void 0 : _b[options == null ? void 0 : options.identifier];
|
|
10721
10722
|
if (!target) {
|
|
10722
10723
|
bootstrap.ratelimits[options == null ? void 0 : options.identifier] = [];
|
|
@@ -10728,7 +10729,7 @@ var setTimeoutAction = (options) => {
|
|
|
10728
10729
|
}
|
|
10729
10730
|
const oldestTimestamp = target == null ? void 0 : target[0];
|
|
10730
10731
|
const getWait = oldestTimestamp ? Math.ceil((options == null ? void 0 : options.interval) * 1e3 - (Date.now() - oldestTimestamp)) : 0;
|
|
10731
|
-
const max = (options == null ? void 0 : options.max)
|
|
10732
|
+
const max = (_c = options == null ? void 0 : options.max) != null ? _c : 1;
|
|
10732
10733
|
if ((target == null ? void 0 : target.length) >= max && getWait > 0) {
|
|
10733
10734
|
return {
|
|
10734
10735
|
limited: true,
|
|
@@ -14060,6 +14061,7 @@ var getTextFromProduct = (options) => {
|
|
|
14060
14061
|
|
|
14061
14062
|
// src/@dictionaries/dictionaries.officeICAOs.ts
|
|
14062
14063
|
var officeICAOs = {
|
|
14064
|
+
"KLUB": "Lubbock, TX",
|
|
14063
14065
|
"KLCH": "Lake Charles, LA",
|
|
14064
14066
|
"TSTL": "St. Louis, MO",
|
|
14065
14067
|
"PABC": "Bethel, AK",
|
|
@@ -14295,14 +14297,15 @@ var officeICAOs = {
|
|
|
14295
14297
|
"KCAR": "Caribou, ME",
|
|
14296
14298
|
"KMFR": "Medford, OR",
|
|
14297
14299
|
"PGUM": "Guam, GU",
|
|
14300
|
+
"PACR": "Cordova, AK",
|
|
14298
14301
|
"PAJK": "Juneau, AK"
|
|
14299
14302
|
};
|
|
14300
14303
|
|
|
14301
14304
|
// src/@building/building.office.ts
|
|
14302
14305
|
var getEventOffice = (options) => {
|
|
14303
|
-
var _a, _b, _c, _d, _e, _f;
|
|
14304
|
-
const office = options.pVtec != null ? (_b = (_a = options.pVtec) == null ? void 0 : _a.tracking) == null ? void 0 : _b.split(
|
|
14305
|
-
const name = (
|
|
14306
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
14307
|
+
const office = options.pVtec != null ? (_b = (_a = options.pVtec) == null ? void 0 : _a.tracking) == null ? void 0 : _b.split(`.`)[0] : (_e = (_c = options.attributes) == null ? void 0 : _c.cccc) != null ? _e : options.organization != null ? Array.isArray(options.organization) ? (_d = options.organization) == null ? void 0 : _d[0] : options.organization : null;
|
|
14308
|
+
const name = (_g = (_f = officeICAOs) == null ? void 0 : _f[office]) != null ? _g : null;
|
|
14306
14309
|
return { office, name };
|
|
14307
14310
|
};
|
|
14308
14311
|
|
|
@@ -14392,7 +14395,7 @@ var properties = (options) => {
|
|
|
14392
14395
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J;
|
|
14393
14396
|
const organization = (_b = (_a = options.message.match(regExp.wmo)) == null ? void 0 : _a[0]) != null ? _b : null;
|
|
14394
14397
|
const polygons = getPolygonFromProduct(options.message);
|
|
14395
|
-
|
|
14398
|
+
const properties2 = {
|
|
14396
14399
|
locations: (_e = (_d = (_c = options == null ? void 0 : options.ugc) == null ? void 0 : _c.locations) == null ? void 0 : _d.join(`; `)) != null ? _e : null,
|
|
14397
14400
|
description: getDescriptionFromProduct({ message: options.message, handle: (_g = (_f = options == null ? void 0 : options.pVtec) == null ? void 0 : _f.vtec) != null ? _g : null }),
|
|
14398
14401
|
attributes: options.attributes,
|
|
@@ -14438,6 +14441,10 @@ var properties = (options) => {
|
|
|
14438
14441
|
pds_watch: getTextFromProduct({ message: options.message, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`
|
|
14439
14442
|
}
|
|
14440
14443
|
};
|
|
14444
|
+
if (isNaN(Number(properties2.watch_parameters.watch_number))) {
|
|
14445
|
+
properties2.watch_parameters.watch_number = null;
|
|
14446
|
+
}
|
|
14447
|
+
return properties2;
|
|
14441
14448
|
};
|
|
14442
14449
|
|
|
14443
14450
|
// src/@building/building.headers.ts
|
|
@@ -14471,16 +14478,16 @@ var eventsMatchText = {
|
|
|
14471
14478
|
// src/@building/building.tracking.ts
|
|
14472
14479
|
var getEventTracking = (options) => {
|
|
14473
14480
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
14474
|
-
const
|
|
14481
|
+
const properties2 = options.properties;
|
|
14475
14482
|
const attributes = options.attributes;
|
|
14476
14483
|
const stanza = options.stanza;
|
|
14477
14484
|
const vtec2 = options.vtec;
|
|
14478
14485
|
if (options.type === `RAW`) {
|
|
14479
|
-
const getWatchNumber = (_a =
|
|
14486
|
+
const getWatchNumber = (_a = properties2.watch_parameters.watch_number) != null ? _a : null;
|
|
14480
14487
|
if (getWatchNumber) {
|
|
14481
|
-
return `${
|
|
14488
|
+
return `${properties2.geocode.office.office}.${stanza.getType.prefix}.A.${getWatchNumber}`;
|
|
14482
14489
|
}
|
|
14483
|
-
return `${
|
|
14490
|
+
return `${properties2.geocode.office.office}.${attributes.ttaaii}.${(_b = attributes.id.slice(-4).replace(`.`, ``)) != null ? _b : "0"}`;
|
|
14484
14491
|
}
|
|
14485
14492
|
if (options.type === `VTEC`) {
|
|
14486
14493
|
return vtec2.tracking;
|
|
@@ -14489,16 +14496,16 @@ var getEventTracking = (options) => {
|
|
|
14489
14496
|
if (options.vtec) {
|
|
14490
14497
|
const vtecValue = Array.isArray(options.vtec) ? options.vtec[0] : options.vtec;
|
|
14491
14498
|
const splitPVTEC = vtecValue.split(".");
|
|
14492
|
-
return `${splitPVTEC[2]}
|
|
14499
|
+
return `${splitPVTEC[2]}.${splitPVTEC[3]}.${splitPVTEC[4]}.${splitPVTEC[5]}`;
|
|
14493
14500
|
}
|
|
14494
14501
|
const wmoMatch = (_d = (_c = options.organization) == null ? void 0 : _c.wmoidentifier) == null ? void 0 : _d.match(/([A-Z]{4}\d{2})\s+([A-Z]{4})/);
|
|
14495
14502
|
const station = (_e = wmoMatch == null ? void 0 : wmoMatch[2]) != null ? _e : "N/A";
|
|
14496
14503
|
if (options.organization.featureId) {
|
|
14497
14504
|
const idMatch = options.organization.featureId.match(/([a-f0-9]+)\.(\d+)\.(\d+)$/);
|
|
14498
|
-
return `${station}
|
|
14505
|
+
return `${station}.${(_f = idMatch == null ? void 0 : idMatch[1]) != null ? _f : "N/A"}`;
|
|
14499
14506
|
}
|
|
14500
14507
|
const id2 = (_g = wmoMatch == null ? void 0 : wmoMatch[1]) != null ? _g : "N/A";
|
|
14501
|
-
return `${station}
|
|
14508
|
+
return `${station}.${id2}`;
|
|
14502
14509
|
}
|
|
14503
14510
|
};
|
|
14504
14511
|
|
|
@@ -14694,8 +14701,8 @@ var getEventSignature = (event) => {
|
|
|
14694
14701
|
const getProduct = (_f = (_e = vtec2 == null ? void 0 : vtec2.vtec) == null ? void 0 : _e.split(`.`)[0]) == null ? void 0 : _f.replace(`/`, ``);
|
|
14695
14702
|
const isTestProduct = eventProducts[getProduct] == `Test Product`;
|
|
14696
14703
|
if (isTestProduct || testSignatures.some((sig) => {
|
|
14697
|
-
var _a2, _b2, _c2;
|
|
14698
|
-
return ((_a2 = properties2.description) == null ? void 0 : _a2.toLowerCase().includes(sig.toLowerCase()))
|
|
14704
|
+
var _a2, _b2, _c2, _d2;
|
|
14705
|
+
return (_d2 = (_a2 = properties2.description) == null ? void 0 : _a2.toLowerCase().includes(sig.toLowerCase())) != null ? _d2 : (_c2 = (_b2 = properties2 == null ? void 0 : properties2.parameters) == null ? void 0 : _b2.instructions) == null ? void 0 : _c2.toLowerCase().includes(sig.toLowerCase());
|
|
14699
14706
|
})) {
|
|
14700
14707
|
properties2.status_metadata = __spreadProps(__spreadValues({}, properties2.status_metadata), { is_test: true });
|
|
14701
14708
|
}
|
|
@@ -14707,7 +14714,7 @@ var getEventSignature = (event) => {
|
|
|
14707
14714
|
};
|
|
14708
14715
|
|
|
14709
14716
|
// src/@manager/manager.setHash.ts
|
|
14710
|
-
var setHash = (event, entry) =>
|
|
14717
|
+
var setHash = (event, entry) => {
|
|
14711
14718
|
if (entry) {
|
|
14712
14719
|
entry.hashes.push(event.properties.metadata.hash);
|
|
14713
14720
|
entry.expires = event.properties.expires;
|
|
@@ -14718,7 +14725,7 @@ var setHash = (event, entry) => __async(null, null, function* () {
|
|
|
14718
14725
|
expires: event.properties.expires
|
|
14719
14726
|
});
|
|
14720
14727
|
}
|
|
14721
|
-
}
|
|
14728
|
+
};
|
|
14722
14729
|
|
|
14723
14730
|
// src/@modules/@utilities/utilities.createHttp.ts
|
|
14724
14731
|
import request from "request";
|
|
@@ -14778,15 +14785,15 @@ var createHttp = (options) => __async(null, null, function* () {
|
|
|
14778
14785
|
});
|
|
14779
14786
|
});
|
|
14780
14787
|
|
|
14781
|
-
// src/@
|
|
14788
|
+
// src/@manager/manager.createWebhook.ts
|
|
14782
14789
|
var import_form_data = __toESM(require_form_data());
|
|
14783
14790
|
var createWebhook = (options) => __async(null, null, function* () {
|
|
14784
|
-
var _a, _b, _c, _d;
|
|
14791
|
+
var _a, _b, _c, _d, _e, _f;
|
|
14785
14792
|
const event = options.event.properties;
|
|
14786
14793
|
const settings = options.webhook;
|
|
14787
14794
|
let body = [
|
|
14788
14795
|
event.locations ? `**Locations**: ${event.locations.slice(0, 100)}` : null,
|
|
14789
|
-
event.issued ? `**Issued**: <t:${Math.floor(new Date(event.issued).getTime() / 1e3)}:R>` : null,
|
|
14796
|
+
event.issued && event.status != `Expired` ? `**Issued**: <t:${Math.floor(new Date(event.issued).getTime() / 1e3)}:R>` : null,
|
|
14790
14797
|
event.expires && event.status != `Statement` ? `**Expires**: <t:${Math.floor(new Date(event.expires).getTime() / 1e3)}:R>` : null,
|
|
14791
14798
|
(() => {
|
|
14792
14799
|
var _a2, _b2;
|
|
@@ -14799,7 +14806,7 @@ var createWebhook = (options) => __async(null, null, function* () {
|
|
|
14799
14806
|
var _a2, _b2;
|
|
14800
14807
|
const val = (_a2 = event.parameters.estimated_hail_size) != null ? _a2 : null;
|
|
14801
14808
|
const th = (_b2 = event.parameters.hail_threat) != null ? _b2 : null;
|
|
14802
|
-
return val
|
|
14809
|
+
return (val != null ? val : th) ? `**Hail Threat**: ${val} ${th ? `(${th})` : ""}` : null;
|
|
14803
14810
|
})(),
|
|
14804
14811
|
event.parameters.damage_threat ? `**Damage Threat**: ${event.parameters.damage_threat}` : null,
|
|
14805
14812
|
event.parameters.flood_threat ? `**Flood Threat**: ${event.parameters.flood_threat}` : null,
|
|
@@ -14820,14 +14827,19 @@ var createWebhook = (options) => __async(null, null, function* () {
|
|
|
14820
14827
|
event.watch_parameters.max_tops_x100feet ? `**Max Tops (x100 feet)**: ${event.watch_parameters.max_tops_x100feet}` : null,
|
|
14821
14828
|
((_a = event.parameters.tags) == null ? void 0 : _a.length) > 0 ? `**Tags**: ${event.parameters.tags.join(", ")}` : null,
|
|
14822
14829
|
(() => {
|
|
14823
|
-
var _a2, _b2, _c2, _d2,
|
|
14830
|
+
var _a2, _b2, _c2, _d2, _e2, _f2;
|
|
14824
14831
|
const val = (_c2 = (_b2 = (_a2 = event.geocode) == null ? void 0 : _a2.office) == null ? void 0 : _b2.name) != null ? _c2 : `N/A`;
|
|
14825
|
-
const th = (
|
|
14826
|
-
return val
|
|
14832
|
+
const th = (_f2 = (_e2 = (_d2 = event.geocode) == null ? void 0 : _d2.office) == null ? void 0 : _e2.office) != null ? _f2 : null;
|
|
14833
|
+
return (val != null ? val : th) ? `**Sender**: ${val} ${th ? `(${th})` : ""}` : null;
|
|
14827
14834
|
})(),
|
|
14828
14835
|
((_b = event.metadata) == null ? void 0 : _b.tracking) ? `**Tracking**: ${event.metadata.tracking}` : null,
|
|
14836
|
+
((_c = event.metadata.history) == null ? void 0 : _c.length) > 0 ? `**Logs**: ${event.metadata.history.length}` : null,
|
|
14829
14837
|
(() => {
|
|
14830
|
-
|
|
14838
|
+
var _a2;
|
|
14839
|
+
if (event.status == `Expired`) {
|
|
14840
|
+
return null;
|
|
14841
|
+
}
|
|
14842
|
+
const desc = ((_a2 = event.description) != null ? _a2 : "").split("\n").map((l) => l.trim()).filter(Boolean).join("\n");
|
|
14831
14843
|
return desc ? "```\n" + desc + "\n```" : null;
|
|
14832
14844
|
})()
|
|
14833
14845
|
].filter(Boolean).join("\n");
|
|
@@ -14837,7 +14849,7 @@ var createWebhook = (options) => __async(null, null, function* () {
|
|
|
14837
14849
|
}
|
|
14838
14850
|
if (body.length > 1900) {
|
|
14839
14851
|
body = body.substring(0, 1900) + "\n\n[Message truncated due to length]";
|
|
14840
|
-
const blocks = (body.match(/```/g)
|
|
14852
|
+
const blocks = ((_d = body.match(/```/g)) != null ? _d : []).length;
|
|
14841
14853
|
if (blocks % 2 !== 0) body += "```";
|
|
14842
14854
|
}
|
|
14843
14855
|
const form = new import_form_data.default();
|
|
@@ -14849,8 +14861,8 @@ var createWebhook = (options) => __async(null, null, function* () {
|
|
|
14849
14861
|
footer: { text: settings.title }
|
|
14850
14862
|
};
|
|
14851
14863
|
form.append("payload_json", JSON.stringify({
|
|
14852
|
-
username: (
|
|
14853
|
-
content: (
|
|
14864
|
+
username: (_e = settings.title) != null ? _e : "AtmosphericX",
|
|
14865
|
+
content: (_f = settings.message) != null ? _f : "",
|
|
14854
14866
|
embeds: [embed]
|
|
14855
14867
|
}));
|
|
14856
14868
|
if (settings.upload) {
|
|
@@ -15062,22 +15074,16 @@ var updateNode = (selectedEvent) => __async(null, null, function* () {
|
|
|
15062
15074
|
|
|
15063
15075
|
// src/@manager/manager.mkEvent.ts
|
|
15064
15076
|
var mkEvent = (event) => __async(null, null, function* () {
|
|
15065
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w
|
|
15077
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
|
|
15066
15078
|
const settings = bootstrap.settings;
|
|
15067
15079
|
const features = bootstrap.cache.events.features;
|
|
15068
|
-
const map2 = /* @__PURE__ */ new Map();
|
|
15069
|
-
for (const f of features) {
|
|
15070
|
-
const key = (_b = (_a = f == null ? void 0 : f.properties) == null ? void 0 : _a.metadata) == null ? void 0 : _b.tracking;
|
|
15071
|
-
if (!key) continue;
|
|
15072
|
-
map2.set(key, f);
|
|
15073
|
-
}
|
|
15074
15080
|
const getHash = event.properties.metadata.hash;
|
|
15075
15081
|
const getTracking = event.properties.metadata.tracking;
|
|
15076
|
-
const isEntry = (
|
|
15077
|
-
const isHashed = (
|
|
15078
|
-
const getFeature =
|
|
15082
|
+
const isEntry = (_a = bootstrap.cache.hashes) == null ? void 0 : _a.find((hash) => hash.tracking === getTracking);
|
|
15083
|
+
const isHashed = (_c = (_b = isEntry == null ? void 0 : isEntry.hashes) == null ? void 0 : _b.includes(getHash)) != null ? _c : false;
|
|
15084
|
+
const getFeature = features.find((feature) => feature.properties.metadata.tracking === getTracking);
|
|
15079
15085
|
if (isHashed || event.properties.status_metadata.is_expired) return;
|
|
15080
|
-
|
|
15086
|
+
setHash(event, isEntry);
|
|
15081
15087
|
const isFilteredLocation = yield updateNode(event).then(() => event.properties.metadata.filtered_proximity);
|
|
15082
15088
|
if (!isFilteredLocation && settings.GlobalSettings.EventFiltering.NodeLocationFiltering) {
|
|
15083
15089
|
return;
|
|
@@ -15094,22 +15100,22 @@ var mkEvent = (event) => __async(null, null, function* () {
|
|
|
15094
15100
|
if (event.properties.status_metadata.is_issued || event.properties.status_metadata.is_updated) {
|
|
15095
15101
|
if (getFeature) {
|
|
15096
15102
|
const getIndex = features.indexOf(getFeature);
|
|
15097
|
-
const cHistory = (
|
|
15098
|
-
const cLocations = (
|
|
15099
|
-
const cUgc = (
|
|
15100
|
-
const iHistory = (
|
|
15101
|
-
const iLocations = (
|
|
15102
|
-
const iUgc = (
|
|
15103
|
-
const mHistory = [...cHistory, ...iHistory].filter((v, i, a) => a.indexOf(v) === i);
|
|
15103
|
+
const cHistory = (_f = (_e = (_d = getFeature == null ? void 0 : getFeature.properties) == null ? void 0 : _d.metadata) == null ? void 0 : _e.history) != null ? _f : [];
|
|
15104
|
+
const cLocations = (_i = (_h = (_g = getFeature == null ? void 0 : getFeature.properties) == null ? void 0 : _g.locations) == null ? void 0 : _h.split(";").map((l) => l.trim())) != null ? _i : [];
|
|
15105
|
+
const cUgc = (_l = (_k = (_j = getFeature == null ? void 0 : getFeature.properties) == null ? void 0 : _j.geocode) == null ? void 0 : _k.ugc) != null ? _l : [];
|
|
15106
|
+
const iHistory = (_o = (_n = (_m = event.properties) == null ? void 0 : _m.metadata) == null ? void 0 : _n.history) != null ? _o : [];
|
|
15107
|
+
const iLocations = (_r = (_q = (_p = event.properties) == null ? void 0 : _p.locations) == null ? void 0 : _q.split(";").map((l) => l.trim())) != null ? _r : [];
|
|
15108
|
+
const iUgc = (_u = (_t = (_s = event.properties) == null ? void 0 : _s.geocode) == null ? void 0 : _t.ugc) != null ? _u : [];
|
|
15109
|
+
const mHistory = [...cHistory, ...iHistory].filter((v, i, a) => a.indexOf(v) === i).filter((v, i, a) => a.findIndex((h) => h.description === v.description && h.issued === v.issued) === i);
|
|
15104
15110
|
const mLocations = [...cLocations, ...iLocations].filter((v, i, a) => a.indexOf(v) === i).join("; ");
|
|
15105
15111
|
const mUgc = [...cUgc, ...iUgc].filter((v, i, a) => a.indexOf(v) === i);
|
|
15106
15112
|
bootstrap.cache.events.features[getIndex] = __spreadProps(__spreadValues({}, event), {
|
|
15107
15113
|
properties: __spreadProps(__spreadValues({}, event.properties), {
|
|
15108
|
-
metadata: __spreadProps(__spreadValues({}, (
|
|
15114
|
+
metadata: __spreadProps(__spreadValues({}, (_v = event == null ? void 0 : event.properties) == null ? void 0 : _v.metadata), {
|
|
15109
15115
|
history: mHistory
|
|
15110
15116
|
}),
|
|
15111
15117
|
locations: mLocations,
|
|
15112
|
-
geocode: __spreadProps(__spreadValues({}, (
|
|
15118
|
+
geocode: __spreadProps(__spreadValues({}, (_w = event == null ? void 0 : event.properties) == null ? void 0 : _w.geocode), {
|
|
15113
15119
|
ugc: mUgc
|
|
15114
15120
|
})
|
|
15115
15121
|
})
|
|
@@ -15182,7 +15188,7 @@ var validateEvents = (events) => __async(null, null, function* () {
|
|
|
15182
15188
|
delete filteredProperties.metadata.ms;
|
|
15183
15189
|
}
|
|
15184
15190
|
filteredProperties.metadata = (_a2 = filteredProperties.metadata) != null ? _a2 : {};
|
|
15185
|
-
|
|
15191
|
+
properties2.metadata.hash = createHash("sha256").update(JSON.stringify(filteredProperties)).digest("hex");
|
|
15186
15192
|
setEventEmit({ event: `onProductType${enhancedEventName.replace(/\s+/g, "")}`, metadata: define2 });
|
|
15187
15193
|
if (properties2.status_metadata.is_test) {
|
|
15188
15194
|
setEventEmit({ event: `onTestProduct`, metadata: define2 });
|
|
@@ -15569,7 +15575,7 @@ var pvExtract = (message) => {
|
|
|
15569
15575
|
vtecs.push({
|
|
15570
15576
|
vtec: vtec2,
|
|
15571
15577
|
product: eventProducts[sub[0]],
|
|
15572
|
-
tracking: `${sub[2]}
|
|
15578
|
+
tracking: `${sub[2]}.${sub[3]}.${sub[4]}.${sub[5]}`,
|
|
15573
15579
|
event: `${eventTypes[sub[3]]} ${eventActions[sub[4]]}`,
|
|
15574
15580
|
status: eventStatus[sub[1]],
|
|
15575
15581
|
organization: (_d = (_c = message.match(regExp.wmo)) == null ? void 0 : _c[0]) != null ? _d : null,
|
|
@@ -16032,7 +16038,7 @@ var xReconnect = (interval) => __async(null, null, function* () {
|
|
|
16032
16038
|
const settings = bootstrap.settings;
|
|
16033
16039
|
const lastStanza = Date.now() - bootstrap.cache.lastStanza;
|
|
16034
16040
|
if (interval < 15) {
|
|
16035
|
-
setWarning({ message: `Reconnection
|
|
16041
|
+
setWarning({ message: `Reconnection interval of ${interval} seconds is too low, setting to 15 seconds` });
|
|
16036
16042
|
interval = 15;
|
|
16037
16043
|
bootstrap.settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.ReconnectionInterval = 15;
|
|
16038
16044
|
}
|
|
@@ -16149,7 +16155,7 @@ var startService = (configurations) => __async(null, null, function* () {
|
|
|
16149
16155
|
yield setCronSchedule();
|
|
16150
16156
|
let scheduleInterval = !settings.EnableWireService ? settings.NationalWeatherServiceSettings.CallbackInterval : 1;
|
|
16151
16157
|
if (!settings.EnableWireService && scheduleInterval < 15) {
|
|
16152
|
-
setWarning({ message: `Schedule
|
|
16158
|
+
setWarning({ message: `Schedule interval of ${scheduleInterval} seconds is too low, setting to 15 seconds` });
|
|
16153
16159
|
bootstrap.settings.NationalWeatherServiceSettings.CallbackInterval = 15;
|
|
16154
16160
|
scheduleInterval = 15;
|
|
16155
16161
|
}
|
|
@@ -16634,6 +16640,16 @@ var getRandomEvent = () => {
|
|
|
16634
16640
|
return bootstrap.cache.events.features[Math.floor(Math.random() * bootstrap.cache.events.features.length)];
|
|
16635
16641
|
};
|
|
16636
16642
|
|
|
16643
|
+
// src/@core/core.query.ts
|
|
16644
|
+
var query = (options) => __async(null, null, function* () {
|
|
16645
|
+
var _a;
|
|
16646
|
+
const get = yield bootstrap.database.prepare(
|
|
16647
|
+
`SELECT * FROM stanzas WHERE stanza LIKE ? LIMIT ?`
|
|
16648
|
+
).all(`%${options.search}%`, (_a = options.max) != null ? _a : 100);
|
|
16649
|
+
const events = get.map((row) => JSON.parse(row.stanza));
|
|
16650
|
+
return events;
|
|
16651
|
+
});
|
|
16652
|
+
|
|
16637
16653
|
// src/@core/core.clearEvents.ts
|
|
16638
16654
|
var clearEvents = () => {
|
|
16639
16655
|
bootstrap.cache.events.features = [];
|
|
@@ -16656,7 +16672,7 @@ var Manager = class {
|
|
|
16656
16672
|
}
|
|
16657
16673
|
trycatch() {
|
|
16658
16674
|
process.on("uncaughtException", (err) => {
|
|
16659
|
-
var _a;
|
|
16675
|
+
var _a, _b;
|
|
16660
16676
|
const ignored = ["ETIMEDOUT", "ECONNRESET", "EHOSTUNREACH", "ENOTFOUND", "ECONNREFUSED", "EPIPE", "EADDRINUSE", "EALREADY", "EACCES", "EAGAIN", "EHOSTDOWN", "STARTTLS_FAILURE"];
|
|
16661
16677
|
if (ignored.includes(err == null ? void 0 : err.code)) {
|
|
16662
16678
|
setEventEmit({
|
|
@@ -16670,7 +16686,7 @@ var Manager = class {
|
|
|
16670
16686
|
});
|
|
16671
16687
|
return;
|
|
16672
16688
|
}
|
|
16673
|
-
setWarning({ message: `Uncaught Exception: ${err instanceof Error ? err.stack
|
|
16689
|
+
setWarning({ message: `Uncaught Exception: ${err instanceof Error ? (_b = err.stack) != null ? _b : err.message : String(err)}` });
|
|
16674
16690
|
});
|
|
16675
16691
|
}
|
|
16676
16692
|
};
|
|
@@ -16684,6 +16700,7 @@ export {
|
|
|
16684
16700
|
getEvents,
|
|
16685
16701
|
getNodes,
|
|
16686
16702
|
getRandomEvent,
|
|
16703
|
+
query,
|
|
16687
16704
|
setEasTone,
|
|
16688
16705
|
setNode,
|
|
16689
16706
|
setSettings,
|
package/dist/index.d.mts
CHANGED
|
@@ -212,7 +212,7 @@ interface GenerateEASOptions {
|
|
|
212
212
|
}
|
|
213
213
|
declare const setEasTone: (options: GenerateEASOptions) => Promise<string>;
|
|
214
214
|
|
|
215
|
-
interface
|
|
215
|
+
interface GetNodeOptions {
|
|
216
216
|
identifier: string;
|
|
217
217
|
delete?: boolean;
|
|
218
218
|
coordinates: {
|
|
@@ -220,7 +220,7 @@ interface GetAddChaserOptions {
|
|
|
220
220
|
latitude: number;
|
|
221
221
|
};
|
|
222
222
|
}
|
|
223
|
-
declare const setNode: (options:
|
|
223
|
+
declare const setNode: (options: GetNodeOptions) => void;
|
|
224
224
|
|
|
225
225
|
declare const getEvents: () => any;
|
|
226
226
|
|
|
@@ -228,6 +228,31 @@ declare const getNodes: () => any;
|
|
|
228
228
|
|
|
229
229
|
declare const getRandomEvent: () => any;
|
|
230
230
|
|
|
231
|
+
type TypeStanza = {
|
|
232
|
+
getChild(arg0: string): unknown;
|
|
233
|
+
is(arg0: string): unknown;
|
|
234
|
+
name: string;
|
|
235
|
+
parent: TypeStanza | null;
|
|
236
|
+
children: any;
|
|
237
|
+
attrs: {
|
|
238
|
+
xmlns: string;
|
|
239
|
+
id: string;
|
|
240
|
+
issue: string;
|
|
241
|
+
ttaaii: string;
|
|
242
|
+
cccc: string;
|
|
243
|
+
awipsid: string;
|
|
244
|
+
from: string;
|
|
245
|
+
to: string;
|
|
246
|
+
type: string;
|
|
247
|
+
};
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
interface QueryOptions {
|
|
251
|
+
search: string;
|
|
252
|
+
max?: number;
|
|
253
|
+
}
|
|
254
|
+
declare const query: (options: QueryOptions) => Promise<TypeStanza[]>;
|
|
255
|
+
|
|
231
256
|
declare const clearEvents: () => void;
|
|
232
257
|
|
|
233
258
|
declare class Manager {
|
|
@@ -236,4 +261,4 @@ declare class Manager {
|
|
|
236
261
|
trycatch(): void;
|
|
237
262
|
}
|
|
238
263
|
|
|
239
|
-
export { Manager, type TypeEvent, clearEvents, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, setEasTone, setNode, setSettings, startService, stopService };
|
|
264
|
+
export { Manager, type TypeEvent, clearEvents, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, query, setEasTone, setNode, setSettings, startService, stopService };
|
package/dist/index.d.ts
CHANGED
|
@@ -212,7 +212,7 @@ interface GenerateEASOptions {
|
|
|
212
212
|
}
|
|
213
213
|
declare const setEasTone: (options: GenerateEASOptions) => Promise<string>;
|
|
214
214
|
|
|
215
|
-
interface
|
|
215
|
+
interface GetNodeOptions {
|
|
216
216
|
identifier: string;
|
|
217
217
|
delete?: boolean;
|
|
218
218
|
coordinates: {
|
|
@@ -220,7 +220,7 @@ interface GetAddChaserOptions {
|
|
|
220
220
|
latitude: number;
|
|
221
221
|
};
|
|
222
222
|
}
|
|
223
|
-
declare const setNode: (options:
|
|
223
|
+
declare const setNode: (options: GetNodeOptions) => void;
|
|
224
224
|
|
|
225
225
|
declare const getEvents: () => any;
|
|
226
226
|
|
|
@@ -228,6 +228,31 @@ declare const getNodes: () => any;
|
|
|
228
228
|
|
|
229
229
|
declare const getRandomEvent: () => any;
|
|
230
230
|
|
|
231
|
+
type TypeStanza = {
|
|
232
|
+
getChild(arg0: string): unknown;
|
|
233
|
+
is(arg0: string): unknown;
|
|
234
|
+
name: string;
|
|
235
|
+
parent: TypeStanza | null;
|
|
236
|
+
children: any;
|
|
237
|
+
attrs: {
|
|
238
|
+
xmlns: string;
|
|
239
|
+
id: string;
|
|
240
|
+
issue: string;
|
|
241
|
+
ttaaii: string;
|
|
242
|
+
cccc: string;
|
|
243
|
+
awipsid: string;
|
|
244
|
+
from: string;
|
|
245
|
+
to: string;
|
|
246
|
+
type: string;
|
|
247
|
+
};
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
interface QueryOptions {
|
|
251
|
+
search: string;
|
|
252
|
+
max?: number;
|
|
253
|
+
}
|
|
254
|
+
declare const query: (options: QueryOptions) => Promise<TypeStanza[]>;
|
|
255
|
+
|
|
231
256
|
declare const clearEvents: () => void;
|
|
232
257
|
|
|
233
258
|
declare class Manager {
|
|
@@ -236,4 +261,4 @@ declare class Manager {
|
|
|
236
261
|
trycatch(): void;
|
|
237
262
|
}
|
|
238
263
|
|
|
239
|
-
export { Manager, type TypeEvent, clearEvents, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, setEasTone, setNode, setSettings, startService, stopService };
|
|
264
|
+
export { Manager, type TypeEvent, clearEvents, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, query, setEasTone, setNode, setSettings, startService, stopService };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@atmosx/event-product-parser",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.42",
|
|
4
4
|
"description": "NOAA Weather Wire & NWS API Parser - Built for standalone and Project AtmosphericX Integration.",
|
|
5
5
|
"main": "dist/cjs/index.cjs",
|
|
6
6
|
"module": "dist/esm/index.mjs",
|
|
@@ -34,7 +34,7 @@ interface GetOfficeResponse {
|
|
|
34
34
|
|
|
35
35
|
export const getEventOffice = (options: GetOfficeOptions): GetOfficeResponse => {
|
|
36
36
|
const office = options.pVtec != null
|
|
37
|
-
? options.pVtec?.tracking?.split(
|
|
37
|
+
? options.pVtec?.tracking?.split(`.`)[0] : (options.attributes?.cccc ??
|
|
38
38
|
(options.organization != null ?
|
|
39
39
|
(Array.isArray(options.organization) ? options.organization?.[0] : options.organization)
|
|
40
40
|
: null));
|
|
@@ -40,7 +40,7 @@ interface GetPropertiesOptions {
|
|
|
40
40
|
export const properties = (options: GetPropertiesOptions): TypeEventProperties => {
|
|
41
41
|
const organization = options.message.match(regExp.wmo)?.[0] ?? null
|
|
42
42
|
const polygons = getPolygonFromProduct(options.message)
|
|
43
|
-
|
|
43
|
+
const properties = {
|
|
44
44
|
locations: options?.ugc?.locations?.join(`; `) ?? null,
|
|
45
45
|
description: getDescriptionFromProduct({ message: options.message, handle: options?.pVtec?.vtec ?? null }),
|
|
46
46
|
attributes: options.attributes,
|
|
@@ -86,4 +86,8 @@ export const properties = (options: GetPropertiesOptions): TypeEventProperties =
|
|
|
86
86
|
pds_watch: (getTextFromProduct({ message: options.message, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`)
|
|
87
87
|
}
|
|
88
88
|
}
|
|
89
|
+
if (isNaN(Number(properties.watch_parameters.watch_number))) {
|
|
90
|
+
properties.watch_parameters.watch_number = null
|
|
91
|
+
}
|
|
92
|
+
return properties;
|
|
89
93
|
}
|
|
@@ -47,7 +47,7 @@ export const getEventSignature = (event: TypeEvent): TypeEvent => {
|
|
|
47
47
|
|
|
48
48
|
const getProduct = vtec?.vtec?.split(`.`)[0]?.replace(`/`, ``)
|
|
49
49
|
const isTestProduct = eventProducts[getProduct] == `Test Product`
|
|
50
|
-
if (isTestProduct || testSignatures.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase())
|
|
50
|
+
if (isTestProduct || testSignatures.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase()) ?? properties?.parameters?.instructions?.toLowerCase().includes(sig.toLowerCase()))) {
|
|
51
51
|
properties.status_metadata = { ...properties.status_metadata, is_test: true }
|
|
52
52
|
}
|
|
53
53
|
|
|
@@ -35,16 +35,16 @@ interface GetTrackingOptions {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
export const getEventTracking = (options: GetTrackingOptions): string => {
|
|
38
|
-
const
|
|
38
|
+
const properties = options.properties
|
|
39
39
|
const attributes = options.attributes
|
|
40
40
|
const stanza = options.stanza
|
|
41
41
|
const vtec = options.vtec
|
|
42
42
|
if (options.type === `RAW`) {
|
|
43
|
-
const getWatchNumber =
|
|
43
|
+
const getWatchNumber = properties.watch_parameters.watch_number ?? null
|
|
44
44
|
if (getWatchNumber) {
|
|
45
|
-
return `${
|
|
45
|
+
return `${properties.geocode.office.office}.${stanza.getType.prefix}.A.${getWatchNumber}`
|
|
46
46
|
}
|
|
47
|
-
return `${
|
|
47
|
+
return `${properties.geocode.office.office}.${attributes.ttaaii}.${attributes.id.slice(-4).replace(`.`, ``) ?? '0'}`
|
|
48
48
|
}
|
|
49
49
|
if (options.type === `VTEC`) {
|
|
50
50
|
return vtec.tracking;
|
|
@@ -54,15 +54,15 @@ export const getEventTracking = (options: GetTrackingOptions): string => {
|
|
|
54
54
|
const vtecValue = Array.isArray(options.vtec)
|
|
55
55
|
? options.vtec[0] : options.vtec;
|
|
56
56
|
const splitPVTEC = vtecValue.split('.');
|
|
57
|
-
return `${splitPVTEC[2]}
|
|
57
|
+
return `${splitPVTEC[2]}.${splitPVTEC[3]}.${splitPVTEC[4]}.${splitPVTEC[5]}`;
|
|
58
58
|
}
|
|
59
59
|
const wmoMatch = options.organization?.wmoidentifier?.match(/([A-Z]{4}\d{2})\s+([A-Z]{4})/);
|
|
60
60
|
const station = wmoMatch?.[2] ?? 'N/A';
|
|
61
61
|
if (options.organization.featureId) {
|
|
62
62
|
const idMatch = options.organization.featureId.match(/([a-f0-9]+)\.(\d+)\.(\d+)$/);
|
|
63
|
-
return `${station}
|
|
63
|
+
return `${station}.${idMatch?.[1] ?? 'N/A'}`;
|
|
64
64
|
}
|
|
65
65
|
const id = wmoMatch?.[1] ?? 'N/A';
|
|
66
|
-
return `${station}
|
|
66
|
+
return `${station}.${id}`;
|
|
67
67
|
}
|
|
68
68
|
}
|
|
@@ -51,8 +51,7 @@ export const validateEvents = async (events: TypeEvent[]): Promise<void> => {
|
|
|
51
51
|
delete filteredProperties.metadata.ms;
|
|
52
52
|
}
|
|
53
53
|
filteredProperties.metadata = filteredProperties.metadata ?? {} as any;
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
properties.metadata.hash = createHash("sha256").update(JSON.stringify(filteredProperties)).digest("hex")
|
|
56
55
|
setEventEmit({ event: `onProductType${enhancedEventName.replace(/\s+/g, '')}`, metadata: define });
|
|
57
56
|
|
|
58
57
|
if (properties.status_metadata.is_test) {
|
|
@@ -76,7 +75,6 @@ export const validateEvents = async (events: TypeEvent[]): Promise<void> => {
|
|
|
76
75
|
return false
|
|
77
76
|
}
|
|
78
77
|
}
|
|
79
|
-
|
|
80
78
|
|
|
81
79
|
for (const key in sets) {
|
|
82
80
|
const setting = sets[key]
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/*
|
|
2
|
+
_ _ _ __ __
|
|
3
|
+
/\ | | | | (_) \ \ / /
|
|
4
|
+
/ \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
|
|
5
|
+
/ /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
|
|
6
|
+
/ ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
|
|
7
|
+
/_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
|
|
8
|
+
| |
|
|
9
|
+
|_|
|
|
10
|
+
|
|
11
|
+
Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
|
|
12
|
+
Discord: https://atmosphericx-discord.scriptkitty.cafe
|
|
13
|
+
Ko-Fi: https://ko-fi.com/k3yomi
|
|
14
|
+
Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
|
|
15
|
+
|
|
16
|
+
Internal Package: @atmosx/event-product-parser
|
|
17
|
+
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
import { TypeStanza } from "../@types/types.stanza";
|
|
21
|
+
import { bootstrap } from "../bootstrap";
|
|
22
|
+
|
|
23
|
+
interface QueryOptions {
|
|
24
|
+
search: string
|
|
25
|
+
max?: number
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
type RowQuery = {
|
|
29
|
+
rowid: number
|
|
30
|
+
stanza: string
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const query = async (options: QueryOptions): Promise<TypeStanza[]> => {
|
|
34
|
+
const get = await bootstrap.database.prepare(
|
|
35
|
+
`SELECT * FROM stanzas WHERE stanza LIKE ? LIMIT ?`)
|
|
36
|
+
.all(`%${options.search}%`, options.max ?? 100) as RowQuery[];
|
|
37
|
+
const events = get.map((row) => JSON.parse(row.stanza));
|
|
38
|
+
return events as TypeStanza[];
|
|
39
|
+
}
|
|
@@ -21,13 +21,13 @@ import { bootstrap } from "../bootstrap";
|
|
|
21
21
|
import { setWarning } from "../@modules/@utilities/utilities.setWarning"
|
|
22
22
|
import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
|
|
23
23
|
|
|
24
|
-
interface
|
|
24
|
+
interface GetNodeOptions {
|
|
25
25
|
identifier: string
|
|
26
26
|
delete?: boolean
|
|
27
27
|
coordinates: { longitude: number; latitude: number }
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
export const setNode = (options:
|
|
30
|
+
export const setNode = (options: GetNodeOptions) => {
|
|
31
31
|
const nodes = bootstrap.cache.nodes.features;
|
|
32
32
|
const exists = nodes.find((node) => node.properties.identifier === options.identifier);
|
|
33
33
|
if (options.delete) {
|