@atmosx/event-product-parser 3.0.54 → 3.0.55

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.
@@ -1124,7 +1124,7 @@ module.exports = __toCommonJS(index_exports);
1124
1124
  var import_path = __toESM(require("path"));
1125
1125
  var import_node_events = require("events");
1126
1126
  var bootstrap = {
1127
- version: `3.0.54`,
1127
+ version: `3.0.55`,
1128
1128
  isReady: true,
1129
1129
  ratelimits: {},
1130
1130
  session_xmpp: null,
@@ -1378,6 +1378,7 @@ var setTimeoutAction = (options) => {
1378
1378
  }
1379
1379
  if (options == null ? void 0 : options.expire) {
1380
1380
  delete bootstrap.ratelimits[options == null ? void 0 : options.identifier];
1381
+ return { limited: false };
1381
1382
  }
1382
1383
  if ((target == null ? void 0 : target.length) > 0) {
1383
1384
  bootstrap.ratelimits[options == null ? void 0 : options.identifier] = target.filter((ts) => Date.now() - ts < (options == null ? void 0 : options.interval) * 1e3);
@@ -5815,6 +5816,9 @@ var dict_enhanced = {
5815
5816
  "Considerable Severe Thunderstorm Warning (TPROB)": { damage: `CONSIDERABLE`, tornado: `POSSIBLE` },
5816
5817
  "Considerable Severe Thunderstorm Warning": { damage: `CONSIDERABLE` },
5817
5818
  "Severe Thunderstorm Warning (TPROB)": { tornado: `POSSIBLE` }
5819
+ },
5820
+ "Special Weather Statement": {
5821
+ "Convective Special Weather Statement": { description: "strong thunderstorm" }
5818
5822
  }
5819
5823
  };
5820
5824
 
@@ -6595,12 +6599,13 @@ var updateListener = (event) => __async(null, null, function* () {
6595
6599
  if (uploads == null ? void 0 : uploads.File) {
6596
6600
  const fDestination = settings.GlobalSettings.ArchiveSettings.TextDirectory;
6597
6601
  if (fDestination) {
6598
- const file = `${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6602
+ const file = `${fDestination}/${metadata.name}_${metadata.tracking}.txt`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6599
6603
  if (!(0, import_fs3.existsSync)(fDestination)) {
6600
6604
  (0, import_fs3.mkdirSync)(fDestination, { recursive: true });
6601
6605
  }
6602
6606
  if ((0, import_fs3.existsSync)(file)) {
6603
- (0, import_fs3.appendFileSync)(file, metadata.raw);
6607
+ (0, import_fs3.appendFileSync)(file, `${`
6608
+ `.repeat(10)}${metadata.raw}`);
6604
6609
  } else {
6605
6610
  (0, import_fs3.writeFileSync)(file, metadata.raw);
6606
6611
  }
@@ -6610,7 +6615,7 @@ var updateListener = (event) => __async(null, null, function* () {
6610
6615
  if (uploads == null ? void 0 : uploads.JSON) {
6611
6616
  const eDestination = settings.GlobalSettings.ArchiveSettings.EventDirectory;
6612
6617
  if (eDestination) {
6613
- const file = `${eDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.json`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6618
+ const file = `${eDestination}/${metadata.name}_${metadata.tracking}.json`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6614
6619
  if (!(0, import_fs3.existsSync)(eDestination)) {
6615
6620
  (0, import_fs3.mkdirSync)(eDestination, { recursive: true });
6616
6621
  }
@@ -6622,19 +6627,22 @@ var updateListener = (event) => __async(null, null, function* () {
6622
6627
  const server = settings == null ? void 0 : settings.NotifyServer;
6623
6628
  const auth = ((_b = server == null ? void 0 : server.Credentials) == null ? void 0 : _b.Username) && ((_c = server == null ? void 0 : server.Credentials) == null ? void 0 : _c.Password) ? { username: (_e = (_d = settings == null ? void 0 : settings.NotifyServer) == null ? void 0 : _d.Credentials) == null ? void 0 : _e.Username, password: (_f = server == null ? void 0 : server.Credentials) == null ? void 0 : _f.Password } : void 0;
6624
6629
  const attachment = metadata.eas && (server == null ? void 0 : server.Attachments) ? `${server == null ? void 0 : server.Attachments}/${metadata.name}_${metadata.status}_${metadata.tracking}.wav` : void 0;
6625
- yield createHttp(__spreadProps(__spreadValues({
6626
- url: `${(_g = server == null ? void 0 : server.Server) == null ? void 0 : _g.replace(/\/$/, "")}/${(_h = listener2 == null ? void 0 : listener2.NotificationServer) == null ? void 0 : _h.Topic}`,
6627
- timeout: 15e3,
6628
- method: "POST"
6629
- }, auth && { auth }), {
6630
- headers: __spreadValues({
6631
- "Title": `${metadata.name} (${metadata.status})`,
6632
- "Tags": (_j = (_i = properties2.parameters.tags) == null ? void 0 : _i.join(",")) != null ? _j : "N/A",
6633
- "Expires": new Date(properties2.expires).getTime(),
6634
- "Priority": (notify == null ? void 0 : notify.Priority) ? notify.Priority.toString() : "5"
6635
- }, attachment && { "Attach": attachment }),
6636
- body: getStringText(event)
6637
- }));
6630
+ const isRatelimited = setTimeoutAction({ identifier: metadata.tracking + `notify.server`, interval: 1, max: 1, addTime: true });
6631
+ if (!isRatelimited.limited) {
6632
+ yield createHttp(__spreadProps(__spreadValues({
6633
+ url: `${(_g = server == null ? void 0 : server.Server) == null ? void 0 : _g.replace(/\/$/, "")}/${(_h = listener2 == null ? void 0 : listener2.NotificationServer) == null ? void 0 : _h.Topic}`,
6634
+ timeout: 15e3,
6635
+ method: "POST"
6636
+ }, auth && { auth }), {
6637
+ headers: __spreadValues({
6638
+ "Title": `${metadata.name} (${metadata.status})`,
6639
+ "Tags": (_j = (_i = properties2.parameters.tags) == null ? void 0 : _i.join(",")) != null ? _j : "N/A",
6640
+ "Expires": new Date(properties2.expires).getTime(),
6641
+ "Priority": (notify == null ? void 0 : notify.Priority) ? notify.Priority.toString() : "5"
6642
+ }, attachment && { "Attach": attachment }),
6643
+ body: getStringText(event)
6644
+ }));
6645
+ }
6638
6646
  }
6639
6647
  if ((webhook == null ? void 0 : webhook.Enabled) && (webhook == null ? void 0 : webhook.Destination)) {
6640
6648
  const isRatelimited = setTimeoutAction({ identifier: webhook.Destination, interval: ((_k = webhook.Ratelimit) != null ? _k : 2) * 2, max: (_l = webhook.Ratelimit) != null ? _l : 2, addTime: true });
@@ -6921,33 +6929,42 @@ var mkEvent = (event) => __async(null, null, function* () {
6921
6929
  }
6922
6930
  });
6923
6931
 
6932
+ // src/@dictionaries/dictionaries.strings.ts
6933
+ var dict_strings = {
6934
+ cancellation: `{EVENT} has been allowed to expire. This product is no longer in effect.`
6935
+ };
6936
+
6924
6937
  // src/@manager/manager.rmEvent.ts
6925
- var rmEvent = (event) => __async(null, null, function* () {
6926
- const gSelect = event;
6927
- const gEvent = bootstrap.cache.events.features.find((f) => {
6928
- var _a, _b, _c, _d;
6929
- return ((_b = (_a = f == null ? void 0 : f.properties) == null ? void 0 : _a.metadata) == null ? void 0 : _b.tracking) === ((_d = (_c = event == null ? void 0 : event.properties) == null ? void 0 : _c.metadata) == null ? void 0 : _d.tracking);
6938
+ var rmEvent = (event, isTimeBasedExpiration) => __async(null, null, function* () {
6939
+ const gTracking = event.properties.metadata.tracking;
6940
+ const isTrackingEventLogged = bootstrap.cache.events.features.find((f) => {
6941
+ var _a, _b;
6942
+ return ((_b = (_a = f == null ? void 0 : f.properties) == null ? void 0 : _a.metadata) == null ? void 0 : _b.tracking) === gTracking;
6930
6943
  });
6931
- const gStatement = event.properties.status_metadata.is_statement;
6932
- gSelect.properties.expires = (/* @__PURE__ */ new Date()).toISOString();
6933
- gSelect.properties.status = `Expired`;
6934
- gSelect.properties.status_metadata.is_expired = true;
6935
- if (gEvent) {
6936
- if (!gStatement) {
6944
+ const isStatement = event.properties.status_metadata.is_statement;
6945
+ if (isTrackingEventLogged) {
6946
+ event.properties.expires = (/* @__PURE__ */ new Date()).toISOString();
6947
+ event.properties.status = `Expired`;
6948
+ event.properties.status_metadata.is_expired = true;
6949
+ const description = isTimeBasedExpiration ? dict_strings.cancellation.replace(`{SENDER}`, event.properties.geocode.office.name).replace(`{EVENT}`, event.properties.event) : event.properties.metadata.raw;
6950
+ event.properties.description = event.properties.metadata.raw = description;
6951
+ event.properties.metadata.history.push({
6952
+ description,
6953
+ issued: event.properties.expires,
6954
+ status: event.properties.status
6955
+ });
6956
+ bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(isTrackingEventLogged), 1);
6957
+ bootstrap.cache.hashes = bootstrap.cache.hashes.filter((hash) => hash.tracking !== gTracking);
6958
+ if (!isStatement) {
6937
6959
  setEventEmit({
6938
6960
  event: `onEventStatus`,
6939
- metadata: {
6940
- type: `Removed`,
6941
- event
6942
- },
6943
- message: `[Removed] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
6961
+ metadata: { type: `Removed`, event },
6962
+ message: `[Removed] ${event.properties.event} (${event.properties.status}) (${gTracking})`
6944
6963
  });
6945
- setEventEmit({ event: `onExpiredProduct`, metadata: event });
6964
+ yield updateListener(event);
6946
6965
  }
6947
- bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(gEvent), 1);
6948
- bootstrap.cache.hashes = bootstrap.cache.hashes.filter((hash) => hash.tracking !== event.properties.metadata.tracking);
6949
- setTimeoutAction({ identifier: event.properties.metadata.tracking, expire: true });
6950
- if (!gStatement) yield updateListener(gSelect);
6966
+ setTimeoutAction({ identifier: gTracking, expire: true });
6967
+ setTimeoutAction({ identifier: gTracking + `notify.server`, expire: true });
6951
6968
  }
6952
6969
  setEventEmit({
6953
6970
  event: `onEventCache`,
@@ -7100,7 +7117,7 @@ var validateEvents = (events) => __async(null, null, function* () {
7100
7117
  }
7101
7118
  if (properties2.status_metadata.is_expired) {
7102
7119
  setEventEmit({ event: `onExpiredProduct`, metadata: define2 });
7103
- rmEvent(define2);
7120
+ rmEvent(define2, false);
7104
7121
  return true;
7105
7122
  }
7106
7123
  if (((_b = (_a = properties2.metadata) == null ? void 0 : _a.vtec) == null ? void 0 : _b.is_watch) && properties2.metadata.source != `events.api`) {
@@ -7162,18 +7179,19 @@ var validateEvents = (events) => __async(null, null, function* () {
7162
7179
  return false;
7163
7180
  };
7164
7181
  const filtering = events.filter((event) => {
7165
- var _a;
7166
7182
  bootstrap.cache.processed = bootstrap.cache.processed.filter((e) => e !== event);
7167
7183
  const define2 = getEventSignature(event);
7184
+ const pre = __spreadProps(__spreadValues({}, define2), { properties: __spreadProps(__spreadValues({}, define2.properties), { metadata: __spreadValues({}, define2.properties.metadata) }) });
7168
7185
  const properties2 = define2.properties;
7169
- (_a = properties2 == null ? void 0 : properties2.metadata) == null ? true : delete _a.ms;
7186
+ delete pre.properties.metadata.ms;
7187
+ delete pre.properties.metadata.header;
7170
7188
  const enhanced = properties2.event = getEventEnhancedName(event);
7171
7189
  const filtered = isFiltered(define2);
7172
7190
  if (!filtered) {
7173
7191
  event.geometry = !(bools == null ? void 0 : bools.DisableGeometryParsing) ? getEventGeometry(event) : null;
7174
7192
  properties2.metadata.attachments = getEventAttachments(event);
7175
7193
  }
7176
- properties2.metadata.hash = (0, import_crypto.createHash)("sha256").update(JSON.stringify(properties2)).digest("hex");
7194
+ properties2.metadata.hash = (0, import_crypto.createHash)("sha256").update(JSON.stringify(pre)).digest("hex");
7177
7195
  setEventEmit({ event: `onProductType${enhanced.replace(/\s+/g, "")}`, metadata: define2 });
7178
7196
  return !filtered;
7179
7197
  });
@@ -7609,16 +7627,17 @@ var setCronSchedule = () => __async(null, null, function* () {
7609
7627
  // src/@manager/manager.updateEvents.ts
7610
7628
  var updateEvents = (selectedEvent) => __async(null, null, function* () {
7611
7629
  const events = bootstrap.cache.events.features;
7612
- function update(evt) {
7630
+ function update(event) {
7613
7631
  return __async(this, null, function* () {
7614
- if (new Date(evt.properties.expires) < /* @__PURE__ */ new Date()) {
7615
- yield rmEvent(evt);
7632
+ if (new Date(event.properties.expires) < /* @__PURE__ */ new Date()) {
7633
+ setEventEmit({ event: `onExpiredProduct`, metadata: event });
7634
+ yield rmEvent(event, true);
7616
7635
  }
7617
7636
  });
7618
7637
  }
7619
7638
  if (!selectedEvent) {
7620
- yield Promise.all(events.map((evt) => __async(null, null, function* () {
7621
- yield update(evt);
7639
+ yield Promise.all(events.map((event) => __async(null, null, function* () {
7640
+ yield update(event);
7622
7641
  })));
7623
7642
  }
7624
7643
  if (selectedEvent) {
@@ -1104,7 +1104,7 @@ var require_main3 = __commonJS({
1104
1104
  import path from "path";
1105
1105
  import { EventEmitter } from "events";
1106
1106
  var bootstrap = {
1107
- version: `3.0.54`,
1107
+ version: `3.0.55`,
1108
1108
  isReady: true,
1109
1109
  ratelimits: {},
1110
1110
  session_xmpp: null,
@@ -1358,6 +1358,7 @@ var setTimeoutAction = (options) => {
1358
1358
  }
1359
1359
  if (options == null ? void 0 : options.expire) {
1360
1360
  delete bootstrap.ratelimits[options == null ? void 0 : options.identifier];
1361
+ return { limited: false };
1361
1362
  }
1362
1363
  if ((target == null ? void 0 : target.length) > 0) {
1363
1364
  bootstrap.ratelimits[options == null ? void 0 : options.identifier] = target.filter((ts) => Date.now() - ts < (options == null ? void 0 : options.interval) * 1e3);
@@ -5795,6 +5796,9 @@ var dict_enhanced = {
5795
5796
  "Considerable Severe Thunderstorm Warning (TPROB)": { damage: `CONSIDERABLE`, tornado: `POSSIBLE` },
5796
5797
  "Considerable Severe Thunderstorm Warning": { damage: `CONSIDERABLE` },
5797
5798
  "Severe Thunderstorm Warning (TPROB)": { tornado: `POSSIBLE` }
5799
+ },
5800
+ "Special Weather Statement": {
5801
+ "Convective Special Weather Statement": { description: "strong thunderstorm" }
5798
5802
  }
5799
5803
  };
5800
5804
 
@@ -6575,12 +6579,13 @@ var updateListener = (event) => __async(null, null, function* () {
6575
6579
  if (uploads == null ? void 0 : uploads.File) {
6576
6580
  const fDestination = settings.GlobalSettings.ArchiveSettings.TextDirectory;
6577
6581
  if (fDestination) {
6578
- const file = `${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6582
+ const file = `${fDestination}/${metadata.name}_${metadata.tracking}.txt`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6579
6583
  if (!existsSync2(fDestination)) {
6580
6584
  mkdirSync2(fDestination, { recursive: true });
6581
6585
  }
6582
6586
  if (existsSync2(file)) {
6583
- appendFileSync(file, metadata.raw);
6587
+ appendFileSync(file, `${`
6588
+ `.repeat(10)}${metadata.raw}`);
6584
6589
  } else {
6585
6590
  writeFileSync3(file, metadata.raw);
6586
6591
  }
@@ -6590,7 +6595,7 @@ var updateListener = (event) => __async(null, null, function* () {
6590
6595
  if (uploads == null ? void 0 : uploads.JSON) {
6591
6596
  const eDestination = settings.GlobalSettings.ArchiveSettings.EventDirectory;
6592
6597
  if (eDestination) {
6593
- const file = `${eDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.json`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6598
+ const file = `${eDestination}/${metadata.name}_${metadata.tracking}.json`.replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
6594
6599
  if (!existsSync2(eDestination)) {
6595
6600
  mkdirSync2(eDestination, { recursive: true });
6596
6601
  }
@@ -6602,19 +6607,22 @@ var updateListener = (event) => __async(null, null, function* () {
6602
6607
  const server = settings == null ? void 0 : settings.NotifyServer;
6603
6608
  const auth = ((_b = server == null ? void 0 : server.Credentials) == null ? void 0 : _b.Username) && ((_c = server == null ? void 0 : server.Credentials) == null ? void 0 : _c.Password) ? { username: (_e = (_d = settings == null ? void 0 : settings.NotifyServer) == null ? void 0 : _d.Credentials) == null ? void 0 : _e.Username, password: (_f = server == null ? void 0 : server.Credentials) == null ? void 0 : _f.Password } : void 0;
6604
6609
  const attachment = metadata.eas && (server == null ? void 0 : server.Attachments) ? `${server == null ? void 0 : server.Attachments}/${metadata.name}_${metadata.status}_${metadata.tracking}.wav` : void 0;
6605
- yield createHttp(__spreadProps(__spreadValues({
6606
- url: `${(_g = server == null ? void 0 : server.Server) == null ? void 0 : _g.replace(/\/$/, "")}/${(_h = listener2 == null ? void 0 : listener2.NotificationServer) == null ? void 0 : _h.Topic}`,
6607
- timeout: 15e3,
6608
- method: "POST"
6609
- }, auth && { auth }), {
6610
- headers: __spreadValues({
6611
- "Title": `${metadata.name} (${metadata.status})`,
6612
- "Tags": (_j = (_i = properties2.parameters.tags) == null ? void 0 : _i.join(",")) != null ? _j : "N/A",
6613
- "Expires": new Date(properties2.expires).getTime(),
6614
- "Priority": (notify == null ? void 0 : notify.Priority) ? notify.Priority.toString() : "5"
6615
- }, attachment && { "Attach": attachment }),
6616
- body: getStringText(event)
6617
- }));
6610
+ const isRatelimited = setTimeoutAction({ identifier: metadata.tracking + `notify.server`, interval: 1, max: 1, addTime: true });
6611
+ if (!isRatelimited.limited) {
6612
+ yield createHttp(__spreadProps(__spreadValues({
6613
+ url: `${(_g = server == null ? void 0 : server.Server) == null ? void 0 : _g.replace(/\/$/, "")}/${(_h = listener2 == null ? void 0 : listener2.NotificationServer) == null ? void 0 : _h.Topic}`,
6614
+ timeout: 15e3,
6615
+ method: "POST"
6616
+ }, auth && { auth }), {
6617
+ headers: __spreadValues({
6618
+ "Title": `${metadata.name} (${metadata.status})`,
6619
+ "Tags": (_j = (_i = properties2.parameters.tags) == null ? void 0 : _i.join(",")) != null ? _j : "N/A",
6620
+ "Expires": new Date(properties2.expires).getTime(),
6621
+ "Priority": (notify == null ? void 0 : notify.Priority) ? notify.Priority.toString() : "5"
6622
+ }, attachment && { "Attach": attachment }),
6623
+ body: getStringText(event)
6624
+ }));
6625
+ }
6618
6626
  }
6619
6627
  if ((webhook == null ? void 0 : webhook.Enabled) && (webhook == null ? void 0 : webhook.Destination)) {
6620
6628
  const isRatelimited = setTimeoutAction({ identifier: webhook.Destination, interval: ((_k = webhook.Ratelimit) != null ? _k : 2) * 2, max: (_l = webhook.Ratelimit) != null ? _l : 2, addTime: true });
@@ -6901,33 +6909,42 @@ var mkEvent = (event) => __async(null, null, function* () {
6901
6909
  }
6902
6910
  });
6903
6911
 
6912
+ // src/@dictionaries/dictionaries.strings.ts
6913
+ var dict_strings = {
6914
+ cancellation: `{EVENT} has been allowed to expire. This product is no longer in effect.`
6915
+ };
6916
+
6904
6917
  // src/@manager/manager.rmEvent.ts
6905
- var rmEvent = (event) => __async(null, null, function* () {
6906
- const gSelect = event;
6907
- const gEvent = bootstrap.cache.events.features.find((f) => {
6908
- var _a, _b, _c, _d;
6909
- return ((_b = (_a = f == null ? void 0 : f.properties) == null ? void 0 : _a.metadata) == null ? void 0 : _b.tracking) === ((_d = (_c = event == null ? void 0 : event.properties) == null ? void 0 : _c.metadata) == null ? void 0 : _d.tracking);
6918
+ var rmEvent = (event, isTimeBasedExpiration) => __async(null, null, function* () {
6919
+ const gTracking = event.properties.metadata.tracking;
6920
+ const isTrackingEventLogged = bootstrap.cache.events.features.find((f) => {
6921
+ var _a, _b;
6922
+ return ((_b = (_a = f == null ? void 0 : f.properties) == null ? void 0 : _a.metadata) == null ? void 0 : _b.tracking) === gTracking;
6910
6923
  });
6911
- const gStatement = event.properties.status_metadata.is_statement;
6912
- gSelect.properties.expires = (/* @__PURE__ */ new Date()).toISOString();
6913
- gSelect.properties.status = `Expired`;
6914
- gSelect.properties.status_metadata.is_expired = true;
6915
- if (gEvent) {
6916
- if (!gStatement) {
6924
+ const isStatement = event.properties.status_metadata.is_statement;
6925
+ if (isTrackingEventLogged) {
6926
+ event.properties.expires = (/* @__PURE__ */ new Date()).toISOString();
6927
+ event.properties.status = `Expired`;
6928
+ event.properties.status_metadata.is_expired = true;
6929
+ const description = isTimeBasedExpiration ? dict_strings.cancellation.replace(`{SENDER}`, event.properties.geocode.office.name).replace(`{EVENT}`, event.properties.event) : event.properties.metadata.raw;
6930
+ event.properties.description = event.properties.metadata.raw = description;
6931
+ event.properties.metadata.history.push({
6932
+ description,
6933
+ issued: event.properties.expires,
6934
+ status: event.properties.status
6935
+ });
6936
+ bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(isTrackingEventLogged), 1);
6937
+ bootstrap.cache.hashes = bootstrap.cache.hashes.filter((hash) => hash.tracking !== gTracking);
6938
+ if (!isStatement) {
6917
6939
  setEventEmit({
6918
6940
  event: `onEventStatus`,
6919
- metadata: {
6920
- type: `Removed`,
6921
- event
6922
- },
6923
- message: `[Removed] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
6941
+ metadata: { type: `Removed`, event },
6942
+ message: `[Removed] ${event.properties.event} (${event.properties.status}) (${gTracking})`
6924
6943
  });
6925
- setEventEmit({ event: `onExpiredProduct`, metadata: event });
6944
+ yield updateListener(event);
6926
6945
  }
6927
- bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(gEvent), 1);
6928
- bootstrap.cache.hashes = bootstrap.cache.hashes.filter((hash) => hash.tracking !== event.properties.metadata.tracking);
6929
- setTimeoutAction({ identifier: event.properties.metadata.tracking, expire: true });
6930
- if (!gStatement) yield updateListener(gSelect);
6946
+ setTimeoutAction({ identifier: gTracking, expire: true });
6947
+ setTimeoutAction({ identifier: gTracking + `notify.server`, expire: true });
6931
6948
  }
6932
6949
  setEventEmit({
6933
6950
  event: `onEventCache`,
@@ -7080,7 +7097,7 @@ var validateEvents = (events) => __async(null, null, function* () {
7080
7097
  }
7081
7098
  if (properties2.status_metadata.is_expired) {
7082
7099
  setEventEmit({ event: `onExpiredProduct`, metadata: define2 });
7083
- rmEvent(define2);
7100
+ rmEvent(define2, false);
7084
7101
  return true;
7085
7102
  }
7086
7103
  if (((_b = (_a = properties2.metadata) == null ? void 0 : _a.vtec) == null ? void 0 : _b.is_watch) && properties2.metadata.source != `events.api`) {
@@ -7142,18 +7159,19 @@ var validateEvents = (events) => __async(null, null, function* () {
7142
7159
  return false;
7143
7160
  };
7144
7161
  const filtering = events.filter((event) => {
7145
- var _a;
7146
7162
  bootstrap.cache.processed = bootstrap.cache.processed.filter((e) => e !== event);
7147
7163
  const define2 = getEventSignature(event);
7164
+ const pre = __spreadProps(__spreadValues({}, define2), { properties: __spreadProps(__spreadValues({}, define2.properties), { metadata: __spreadValues({}, define2.properties.metadata) }) });
7148
7165
  const properties2 = define2.properties;
7149
- (_a = properties2 == null ? void 0 : properties2.metadata) == null ? true : delete _a.ms;
7166
+ delete pre.properties.metadata.ms;
7167
+ delete pre.properties.metadata.header;
7150
7168
  const enhanced = properties2.event = getEventEnhancedName(event);
7151
7169
  const filtered = isFiltered(define2);
7152
7170
  if (!filtered) {
7153
7171
  event.geometry = !(bools == null ? void 0 : bools.DisableGeometryParsing) ? getEventGeometry(event) : null;
7154
7172
  properties2.metadata.attachments = getEventAttachments(event);
7155
7173
  }
7156
- properties2.metadata.hash = createHash("sha256").update(JSON.stringify(properties2)).digest("hex");
7174
+ properties2.metadata.hash = createHash("sha256").update(JSON.stringify(pre)).digest("hex");
7157
7175
  setEventEmit({ event: `onProductType${enhanced.replace(/\s+/g, "")}`, metadata: define2 });
7158
7176
  return !filtered;
7159
7177
  });
@@ -7589,16 +7607,17 @@ var setCronSchedule = () => __async(null, null, function* () {
7589
7607
  // src/@manager/manager.updateEvents.ts
7590
7608
  var updateEvents = (selectedEvent) => __async(null, null, function* () {
7591
7609
  const events = bootstrap.cache.events.features;
7592
- function update(evt) {
7610
+ function update(event) {
7593
7611
  return __async(this, null, function* () {
7594
- if (new Date(evt.properties.expires) < /* @__PURE__ */ new Date()) {
7595
- yield rmEvent(evt);
7612
+ if (new Date(event.properties.expires) < /* @__PURE__ */ new Date()) {
7613
+ setEventEmit({ event: `onExpiredProduct`, metadata: event });
7614
+ yield rmEvent(event, true);
7596
7615
  }
7597
7616
  });
7598
7617
  }
7599
7618
  if (!selectedEvent) {
7600
- yield Promise.all(events.map((evt) => __async(null, null, function* () {
7601
- yield update(evt);
7619
+ yield Promise.all(events.map((event) => __async(null, null, function* () {
7620
+ yield update(event);
7602
7621
  })));
7603
7622
  }
7604
7623
  if (selectedEvent) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atmosx/event-product-parser",
3
- "version": "3.0.54",
3
+ "version": "3.0.55",
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",
@@ -57,7 +57,7 @@ export const validateEvents = async (events: TypeEvent[]): Promise<void> => {
57
57
 
58
58
  if (properties.status_metadata.is_expired) {
59
59
  setEventEmit({ event: `onExpiredProduct`, metadata: define })
60
- rmEvent(define)
60
+ rmEvent(define, false)
61
61
  return true;
62
62
  }
63
63
 
@@ -124,14 +124,16 @@ export const validateEvents = async (events: TypeEvent[]): Promise<void> => {
124
124
  const filtering = events.filter((event: TypeEvent) => {
125
125
  bootstrap.cache.processed = bootstrap.cache.processed.filter((e) => e !== event);
126
126
  const define = getEventSignature(event) as TypeEvent;
127
- const properties = define.properties; delete properties?.metadata?.ms;
127
+ // make a copy of the define object with properites so we can delete values to make hash
128
+ const pre = {...define,properties: {...define.properties, metadata: {...define.properties.metadata }}};
129
+ const properties = define.properties; delete pre.properties.metadata.ms; delete pre.properties.metadata.header;
128
130
  const enhanced = properties.event = getEventEnhancedName(event)
129
131
  const filtered = isFiltered(define)
130
132
  if (!filtered) {
131
133
  event.geometry = !bools?.DisableGeometryParsing ? getEventGeometry(event) : null;
132
134
  properties.metadata.attachments = getEventAttachments(event)
133
135
  }
134
- properties.metadata.hash = createHash("sha256").update(JSON.stringify(properties)).digest("hex")
136
+ properties.metadata.hash = createHash("sha256").update(JSON.stringify(pre)).digest("hex")
135
137
  setEventEmit({ event: `onProductType${enhanced.replace(/\s+/g, '')}`, metadata: define });
136
138
  return !filtered
137
139
  })
@@ -64,4 +64,7 @@ export const dict_enhanced: Record<string, Record<string, EnhancedEventType>> =
64
64
  "Considerable Severe Thunderstorm Warning": { damage: `CONSIDERABLE` },
65
65
  "Severe Thunderstorm Warning (TPROB)": { tornado: `POSSIBLE` },
66
66
  },
67
+ "Special Weather Statement": {
68
+ "Convective Special Weather Statement": { description: "strong thunderstorm" },
69
+ }
67
70
  }
@@ -0,0 +1,22 @@
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
+ export const dict_strings: Record<string, string> = {
21
+ cancellation: `{EVENT} has been allowed to expire. This product is no longer in effect.`,
22
+ }
@@ -18,39 +18,52 @@
18
18
  */
19
19
 
20
20
  import { TypeEvent } from "../@types/type.event";
21
+ import { dict_strings } from "../@dictionaries/dictionaries.strings";
21
22
  import { bootstrap } from "../bootstrap"
22
23
  import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
23
24
  import { setTimeoutAction } from "../@modules/@utilities/utilities.setTimeoutAction";
24
25
  import { updateListener } from "./manager.updateListener";
25
26
 
26
- export const rmEvent = async (event: TypeEvent): Promise<void> => {
27
- const gSelect = event;
28
- const gEvent = bootstrap.cache.events.features.find(f => f?.properties?.metadata?.tracking === event?.properties?.metadata?.tracking);
29
- const gStatement = event.properties.status_metadata.is_statement
30
27
 
31
- gSelect.properties.expires = new Date().toISOString();
32
- gSelect.properties.status = `Expired`;
33
- gSelect.properties.status_metadata.is_expired = true;
28
+ export const rmEvent = async (event: TypeEvent, isTimeBasedExpiration: boolean):Promise<void> => {
29
+ const gTracking = event.properties.metadata.tracking;
30
+ const isTrackingEventLogged = bootstrap.cache.events.features
31
+ .find(f => f?.properties?.metadata?.tracking === gTracking);
32
+ const isStatement = event.properties.status_metadata.is_statement;
34
33
 
35
- if (gEvent) {
36
- if (!gStatement) {
34
+ if (isTrackingEventLogged) {
35
+ event.properties.expires = new Date().toISOString();
36
+ event.properties.status = `Expired`;
37
+ event.properties.status_metadata.is_expired = true;
38
+
39
+
40
+ const description = isTimeBasedExpiration ? dict_strings.cancellation
41
+ .replace(`{SENDER}`, event.properties.geocode.office.name)
42
+ .replace(`{EVENT}`, event.properties.event) : event.properties.metadata.raw;
43
+ event.properties.description = event.properties.metadata.raw = description;
44
+ event.properties.metadata.history.push({
45
+ description: description,
46
+ issued: event.properties.expires,
47
+ status: event.properties.status
48
+ })
49
+
50
+
51
+ bootstrap.cache.events.features
52
+ .splice(bootstrap.cache.events.features.indexOf(isTrackingEventLogged), 1);
53
+ bootstrap.cache.hashes = bootstrap.cache.hashes
54
+ .filter(hash => hash.tracking !== gTracking);
55
+
56
+ if (!isStatement) {
37
57
  setEventEmit({
38
58
  event: `onEventStatus`,
39
- metadata: {
40
- type: `Removed`,
41
- event: event
42
- },
43
- message: `[Removed] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
59
+ metadata: { type: `Removed`, event: event },
60
+ message: `[Removed] ${event.properties.event} (${event.properties.status}) (${gTracking})`
44
61
  })
45
- setEventEmit({ event: `onExpiredProduct`, metadata: event })
62
+ await updateListener(event)
46
63
  }
47
-
48
- bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(gEvent), 1);
49
- bootstrap.cache.hashes = bootstrap.cache.hashes.filter(hash => hash.tracking !== event.properties.metadata.tracking);
50
- setTimeoutAction({ identifier: event.properties.metadata.tracking, expire: true })
51
- if (!gStatement) await updateListener(gSelect)
64
+ setTimeoutAction({ identifier: gTracking, expire: true })
65
+ setTimeoutAction({ identifier: gTracking + `notify.server`, expire: true })
52
66
  }
53
-
54
67
  setEventEmit({
55
68
  event: `onEventCache`,
56
69
  metadata: bootstrap.cache.events,
@@ -19,15 +19,17 @@
19
19
 
20
20
  import { TypeEvent } from "../@types/type.event";
21
21
  import { bootstrap } from "../bootstrap"
22
+ import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
22
23
  import { rmEvent } from "./manager.rmEvent";
23
24
 
24
25
  export const updateEvents = async (selectedEvent?: TypeEvent): Promise<void> => {
25
26
  const events = bootstrap.cache.events.features;
26
- async function update(evt: TypeEvent) {
27
- if (new Date(evt.properties.expires) < new Date()) {
28
- await rmEvent(evt);
27
+ async function update(event: TypeEvent) {
28
+ if (new Date(event.properties.expires) < new Date()) {
29
+ setEventEmit({ event: `onExpiredProduct`, metadata: event })
30
+ await rmEvent(event, true)
29
31
  }
30
32
  }
31
- if (!selectedEvent) { await Promise.all(events.map(async (evt) => { await update(evt) })) }
33
+ if (!selectedEvent) { await Promise.all(events.map(async (event) => { await update(event) })) }
32
34
  if (selectedEvent) { await update(selectedEvent) }
33
35
  }
@@ -68,10 +68,10 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
68
68
  if (uploads?.File) {
69
69
  const fDestination = settings.GlobalSettings.ArchiveSettings.TextDirectory;
70
70
  if (fDestination) {
71
- const file = (`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
71
+ const file = (`${fDestination}/${metadata.name}_${metadata.tracking}.txt`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
72
72
  if (!existsSync(fDestination)) { mkdirSync(fDestination, { recursive: true }); }
73
73
  if (existsSync(file)) {
74
- appendFileSync(file, metadata.raw);
74
+ appendFileSync(file, `${(`\n`).repeat(10)}${metadata.raw}`);
75
75
  } else {
76
76
  writeFileSync(file, metadata.raw);
77
77
  }
@@ -82,7 +82,7 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
82
82
  if (uploads?.JSON) {
83
83
  const eDestination = settings.GlobalSettings.ArchiveSettings.EventDirectory;
84
84
  if (eDestination) {
85
- const file = (`${eDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.json`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
85
+ const file = (`${eDestination}/${metadata.name}_${metadata.tracking}.json`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
86
86
  if (!existsSync(eDestination)) { mkdirSync(eDestination, { recursive: true }); }
87
87
  writeFileSync(file, JSON.stringify(getCleanedEvent(event), null, 2));
88
88
  }
@@ -93,20 +93,23 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
93
93
  const server = settings?.NotifyServer;
94
94
  const auth = server?.Credentials?.Username && server?.Credentials?.Password ? { username: settings?.NotifyServer?.Credentials?.Username, password: server?.Credentials?.Password } : undefined;
95
95
  const attachment = metadata.eas && server?.Attachments ? `${server?.Attachments}/${metadata.name}_${metadata.status}_${metadata.tracking}.wav` : undefined;
96
- await createHttp({
97
- url: `${server?.Server?.replace(/\/$/, "")}/${listener?.NotificationServer?.Topic}`,
98
- timeout: 15_000,
99
- method: "POST",
100
- ...(auth && { auth }),
101
- headers: {
102
- "Title": `${metadata.name} (${metadata.status})`,
103
- "Tags": properties.parameters.tags?.join(",") ?? "N/A",
104
- "Expires": new Date(properties.expires).getTime(),
105
- "Priority": notify?.Priority ? notify.Priority.toString() : "5",
106
- ... (attachment && { "Attach": attachment }),
107
- },
108
- body: getStringText(event)
109
- })
96
+ const isRatelimited = setTimeoutAction({ identifier: metadata.tracking + `notify.server`, interval: 1, max: 1, addTime: true })
97
+ if (!isRatelimited.limited) {
98
+ await createHttp({
99
+ url: `${server?.Server?.replace(/\/$/, "")}/${listener?.NotificationServer?.Topic}`,
100
+ timeout: 15_000,
101
+ method: "POST",
102
+ ...(auth && { auth }),
103
+ headers: {
104
+ "Title": `${metadata.name} (${metadata.status})`,
105
+ "Tags": properties.parameters.tags?.join(",") ?? "N/A",
106
+ "Expires": new Date(properties.expires).getTime(),
107
+ "Priority": notify?.Priority ? notify.Priority.toString() : "5",
108
+ ... (attachment && { "Attach": attachment }),
109
+ },
110
+ body: getStringText(event)
111
+ })
112
+ }
110
113
  }
111
114
 
112
115
  if (webhook?.Enabled && webhook?.Destination) {
@@ -41,6 +41,7 @@ export const setTimeoutAction = (options: SetTimeoutActionOptions): SetTimeoutAc
41
41
  }
42
42
  if (options?.expire) {
43
43
  delete bootstrap.ratelimits[options?.identifier];
44
+ return { limited: false };
44
45
  }
45
46
  if (target?.length > 0) {
46
47
  bootstrap.ratelimits[options?.identifier] = target.filter((ts: number) => Date.now() - ts < options?.interval * 1000);
package/src/bootstrap.ts CHANGED
@@ -21,7 +21,7 @@ import path from 'path'
21
21
  import { EventEmitter } from 'node:events';
22
22
 
23
23
  export const bootstrap = {
24
- version: `3.0.54`,
24
+ version: `3.0.55`,
25
25
  isReady: true,
26
26
  ratelimits: {},
27
27
  session_xmpp: null,