@atmosx/event-product-parser 3.0.53 → 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.
package/.github/README.md CHANGED
@@ -23,7 +23,7 @@ const { Manager } = require(`@atmosx/event-product-parser`) // CJS Importing
23
23
  import { Manager } from '@atmosx/event-product-parser' // EJS Importing
24
24
 
25
25
  const Client = new Manager({
26
- Database: `shapefiles.db`,
26
+ Database: `event-product-parser.db`,
27
27
  EnableWireService: false,
28
28
  EnableJournal: true,
29
29
  EnableDebugging: false,
@@ -39,8 +39,8 @@ const Client = new Manager({
39
39
  },
40
40
  CacheSettings: {
41
41
  Enabled: true,
42
- MaxDatabaseHistory: 5000,
43
- MaxRetentionHistory: 555,
42
+ MaxDatabaseHistory: 50000,
43
+ MaxRetentionHistory: 1500,
44
44
  },
45
45
  StanzaSettings: {
46
46
  DisableUGC: false,
@@ -54,12 +54,13 @@ const Client = new Manager({
54
54
  },
55
55
  BroadcastifySettings: {
56
56
  BroadcastifyAttachments: true,
57
+ BroadcastifyDatabase: `https://scriptkitty.cafe/ftp/@atmosphericx/assets/broadcastify.json`,
57
58
  BroadcastifyTags: [`Public Safety`, `Amateur Radio`, `Other`, `Rail`, `Aviation`, `Marine`, `Disaster Event`, `Special Event`]
58
59
  },
59
60
  NotifyServer: {
60
61
  Enabled: false,
61
- Server: "https://ntfy.domainname.com",
62
- Attachments: "https://domainname.com/Storage/EasScenarios",
62
+ Server: "https://ntfy.scriptkitty.cafe",
63
+ Attachments: "https://scriptkitty.cafe/ftp/@bucket/EAS/encoded",
63
64
  Credentials: {
64
65
  Username: "username",
65
66
  Password: "password"
@@ -67,22 +68,16 @@ const Client = new Manager({
67
68
  },
68
69
  ListenerSettings: [
69
70
  {
70
- events: [`*Thunderstorm Warning*`, `* Watch`],
71
- webhook: {
72
- enabled: true,
73
- destination: "https://discord.com/api/XXXXXXXXXX/XXXXXXXXXXX",
74
- title: "AtmosphericX - (Thunderstorm Warnings and Watches)",
75
- message: "<@&XXXXXXXXXXXXXXXXXXXXX>",
76
- ratelimit: 1
71
+ Events: ["*Extreme Heat Warning*"],
72
+ NotificationServer: {
73
+ Enabled: false,
74
+ Topic: "heat-warnings",
75
+ Priority: 5
77
76
  },
78
- notify: {
79
- enabled: false,
80
- topic: "thunderstorm_events",
81
- },
82
- uploads: {
83
- eas: true,
84
- file: true,
85
- event: true
77
+ Uploads: {
78
+ EAS: true,
79
+ File: true,
80
+ JSON: true
86
81
  }
87
82
  }
88
83
  ],
@@ -94,106 +89,29 @@ const Client = new Manager({
94
89
  SPCWatchesOnly: true,
95
90
  ShapefileSkipPoints: 0,
96
91
  NodeTTL: 60,
97
- NodeMinDistance: 120,
92
+ NodeMinDistance: 125,
98
93
  EventFiltering: {
99
94
  ListeningEvents: [
100
- "*Severe Thunderstorm Warning*",
101
- "*Blizzard*", "*Ice Storm*", "*Winter Storm*", "*Snow Squall*",
102
- "Tornado Emergency", "*Tornado Warning*",
103
- "Special Weather Statement", "Marine Weather Statement",
104
- "*Tsunami*", "*Hurricane*", "*Tropical Storm*", "*Special Marine*",
105
- "*Flash Flood Warning*", "*Flash Flood Watch*", "*Flash Flood Advisory*",
106
- "Mesoscale Discussion",
107
- "*Storm Prediction Center*",
108
- "PDS Tornado Watch", "Tornado Watch", "Severe Thunderstorm Watch", "Flash Flood Watch", "PDS Severe Thunderstorm Watch",
109
- "*Administrative*", "National Weather Service Policy",
110
- "Fire Weather Warning", "Fire Weather Watch", "Fire Weather Advisory",
95
+ "*Warning*"
111
96
  ],
112
- ListeningICAO: [`KLOT`],
97
+ ListeningICAO: [],
98
+ ListeningUGC: [],
99
+ ListeningStates: [],
113
100
  IgnoredICAO: [],
114
101
  IgnoredEvents: [],
115
- ListeningUGC: [`WIC001`],
116
- ListeningStates: [`MO`, `IA`],
117
102
  NodeLocationFiltering: false,
118
103
  IgnoreTestProducts: true,
119
104
  },
120
105
  ArchiveSettings: {
121
- TTL: 600,
122
- EventDirectory: `Storage/EventProducts`,
123
- TextDirectory: `Storage/TextProducts`,
124
- EasDirectory: `Storage/EasScenarios`,
125
- EasToneout: `tone.wav`,
106
+ TTL: 30,
107
+ EventDirectory: `@bucket/ParsedProducts`,
108
+ TextDirectory: `@bucket/RawTextProducts`,
109
+ EasDirectory: `@bucket/EAS`,
110
+ EasToneout: `eas-toneout.wav`,
126
111
  }
127
112
  }
128
113
  })
129
114
  ```
130
- ### General Settings
131
- - **Database**: The database file name and location, please make sure to include the `.db` extension.
132
- - **EnableWireService**: Whether to enable `NOAA Weather Wire Service` within the parser. This requires credentials from [NOAA Weather Wire Service](https://www.weather.gov/nwws/).
133
- - **EnableJournal**: Whether to output logs without requiring event `listeners`.
134
-
135
- ### NOAAWeatherWireServiceSettings
136
- - **ReconnectionSettings**: When the XMPP client gets disconnected or has an error, choose to reconnect to the service again. This contains a reconnection check interval.
137
- - **CredentialSettings**: The username (nickname) and password that is required for using `NOAA Weather Wire Service`.
138
- - **CacheSettings**: The ability to use the cache system so when you relaunch the parser, it will have a event retention history of all the stanzas collected.
139
- - **StanzaSettings**: Modify what type of products metadata you'd like to receive. (UGC, VTEC, RawText)
140
-
141
- ### NationalWeatherServiceSettings
142
- - **CallbackInterval**: The interval at which the parser will check for new alerts from the National Weather Service API.
143
- - **EventsEndpoint**: The URL that directs to the API.
144
-
145
- ## BroadcastifySettings
146
- - **BroadcastifyAttachments**: Whether to enable broadcastify attachments for events.
147
- - **BroadcastifyDatabase**: The download url to point to for the collection of broadcastify feeds. (Stored locally once downloaded)
148
- - **BroadcastifyTags**: An array of tags to filter broadcastify feeds. (`Public Safety`, `Amateur Radio`, `Other`, `Rail`, `Aviation`, `Marine`, `Disaster Event`, `Special Event`)
149
-
150
- ## NotifyServer
151
- - **Enabled**: Whether to enable the notify server for events. This uses the [ntfy.sh](https://ntfy.sh/) service to send notifications for events. This is optional and can be disabled if not needed.
152
- - **Server**: The notify server URL (Ex. `https://ntfy.domainname.com`)
153
- - **Attachments**: The URL to the attachments directory (Ex. `https://domainname.com/Storage/EasScenarios`)
154
- - **Credentials**: The username and password for the notify server if required. (Optional)
155
-
156
- ### ListenerSettings
157
- - **events**: An array of event types that will trigger the listener when they are received by the parser. If this array is empty, the listener will be triggered for all events.
158
-
159
- #### Webhook
160
- - **enabled**: If the webhook is enabled or not
161
- - **destination**: Webhook URL
162
- - **title**: The title of the webhook
163
- - **message**: The message you'd like to use for the webhook
164
- - **ratelimit**: How many messages can it send before being ratelimited
165
-
166
- #### Notify
167
- - **enabled**: If the notify server is enabled or not
168
- - **topic**: The topic you'd like to use for the notify server. This is used to send notifications for events. (Ex. `thunderstorm_events`)
169
-
170
- #### Uploads
171
- - **eas**: Whether to enable auto eas generated audio files
172
- - **file**: Wheather to generate text files
173
-
174
-
175
- ### GlobalSettings
176
- - **EventManagement**: Whether to enable the event management system which includes filtering, tracking nodes, and custom messages.
177
- - **BetterEventNames**: Changes events to a more specific version depending on parameters, message types, etc. `(Ex. "Tornado Warning" -> "Observed Tornado Warning")`
178
- - **DisableGeometryParsing**: Disable automatically appending GeoJSON geometry data to the events to save on memory consumption.
179
- - **UseShapefileCoordinates**: Whether to use the shapefile database to obtain the coordinates for events with specified UGC zones.
180
- - **SPCWatchesOnly**: Whether to only listen for SPC watches only (TOR/SVR) (If using the API, this is ignored).
181
- - **ShapefileSkipPoints**: When using the shapefile database to obtain coordinates, you can choose to skip a certain amount of points to reduce the number of coordinates for large events. (Ex. If an event has 1000 coordinates and you set this to `2`, it will only use every other coordinate, therefore using 500 coordinates instead of 1000).
182
- - **NodeTTL**: How often nodes should be checked per event. (Tracking/Filtering)
183
- - **NodeMinDistance**: The minimum distance to filter events from the node (Miles)
184
- - **ListeningEvents**: Events you'd like to listen for. If this array is left empty, it will listen for **ALL** events and products.
185
- - **ListeningICAO**: ICAO codes for the weather stations you'd like to listen for. Filtering all events that do not contain the codes. `(Ex. ["KLOT", "TORD"])`
186
- - **IgnoredICAO**: Ignored ICAO codes `(Ex. ["KWNS"])`
187
- - **IgnoredEvents**: Ignored events / products.
188
- - **ListeningUGC**: Zones you'd like to listen to `(Ex. ["ILZ001"])`
189
- - **ListeningStates**: States you'd like to listen to `(Ex. ["IL"])`
190
- - **NodeLocationFiltering**: If you want tracking nodes to filter out events based on radius. (Miles)\
191
- - **IgnoreTextProducts**: If you want to ignore test products and events.
192
- - **TTL**: How long files live for before getting automatically deleted
193
- - **TextDirectory**: The location to store text products that are generated.
194
- - **EasDirectory**: The location to store audio eas files that are generated.
195
- - **EasToneout**: The toneout prefix to use for generated eas messages.
196
-
197
115
 
198
116
  ## How do custom listeners work?
199
117
 
@@ -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.53`,
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
 
@@ -6424,8 +6428,8 @@ var setEasTone = (options) => __async(null, null, function* () {
6424
6428
  return outTTS;
6425
6429
  });
6426
6430
 
6427
- // src/@parsers/@text/text.getEmbed.ts
6428
- var getEmebed = (event) => {
6431
+ // src/@parsers/@text/text.getEmbedText.ts
6432
+ var getEmebedText = (event) => {
6429
6433
  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, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da, _Ea, _Fa, _Ga, _Ha, _Ia, _Ja, _Ka, _La, _Ma, _Na;
6430
6434
  const line = (label, value, condition = true) => condition && value ? `${label} ${value}` : null;
6431
6435
  const isStatement = event.properties.status_metadata.is_statement;
@@ -6462,8 +6466,8 @@ var getEmebed = (event) => {
6462
6466
  ].filter(Boolean).join("\n");
6463
6467
  };
6464
6468
 
6465
- // src/@parsers/@text/text.getRaw.ts
6466
- var getRaw = (event) => {
6469
+ // src/@parsers/@text/text.getStringText.ts
6470
+ var getStringText = (event) => {
6467
6471
  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, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la, _ma, _na, _oa, _pa, _qa, _ra, _sa, _ta, _ua, _va, _wa, _xa, _ya, _za, _Aa, _Ba, _Ca, _Da;
6468
6472
  const line = (label, value, condition = true) => condition && value ? `${label} ${value}` : null;
6469
6473
  const isStatement = event.properties.status_metadata.is_statement;
@@ -6560,7 +6564,7 @@ var getMatched = (strings, string) => {
6560
6564
  // src/@manager/manager.updateListener.ts
6561
6565
  var import_fs3 = require("fs");
6562
6566
  var updateListener = (event) => __async(null, null, function* () {
6563
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
6567
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
6564
6568
  const tick = performance.now();
6565
6569
  const settings = bootstrap.settings;
6566
6570
  const listeners2 = settings.ListenerSettings;
@@ -6579,37 +6583,39 @@ var updateListener = (event) => __async(null, null, function* () {
6579
6583
  attachments: properties2.metadata.attachments
6580
6584
  };
6581
6585
  for (const listener2 of listeners2) {
6582
- const events = listener2 == null ? void 0 : listener2.events;
6583
- const webhook = listener2 == null ? void 0 : listener2.webhook;
6584
- const uploads = listener2 == null ? void 0 : listener2.uploads;
6586
+ const events = listener2 == null ? void 0 : listener2.Events;
6587
+ const webhook = listener2 == null ? void 0 : listener2.Webhook;
6588
+ const notify = listener2 == null ? void 0 : listener2.NotificationServer;
6589
+ const uploads = listener2 == null ? void 0 : listener2.Uploads;
6585
6590
  const isMatched = getMatched(events != null ? events : [], metadata.name);
6586
6591
  if ((events == null ? void 0 : events.length) == 0 || isMatched) {
6587
- if (uploads == null ? void 0 : uploads.eas) {
6592
+ if (uploads == null ? void 0 : uploads.EAS) {
6588
6593
  metadata.eas = yield setEasTone({
6589
6594
  title: `${metadata.name}_${metadata.status}_${metadata.tracking}`,
6590
6595
  message: metadata.description,
6591
6596
  header: metadata.header
6592
6597
  });
6593
6598
  }
6594
- if (uploads == null ? void 0 : uploads.file) {
6599
+ if (uploads == null ? void 0 : uploads.File) {
6595
6600
  const fDestination = settings.GlobalSettings.ArchiveSettings.TextDirectory;
6596
6601
  if (fDestination) {
6597
- 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();
6598
6603
  if (!(0, import_fs3.existsSync)(fDestination)) {
6599
6604
  (0, import_fs3.mkdirSync)(fDestination, { recursive: true });
6600
6605
  }
6601
6606
  if ((0, import_fs3.existsSync)(file)) {
6602
- (0, import_fs3.appendFileSync)(file, metadata.raw);
6607
+ (0, import_fs3.appendFileSync)(file, `${`
6608
+ `.repeat(10)}${metadata.raw}`);
6603
6609
  } else {
6604
6610
  (0, import_fs3.writeFileSync)(file, metadata.raw);
6605
6611
  }
6606
6612
  }
6607
6613
  metadata.file = metadata.raw;
6608
6614
  }
6609
- if (uploads == null ? void 0 : uploads.event) {
6615
+ if (uploads == null ? void 0 : uploads.JSON) {
6610
6616
  const eDestination = settings.GlobalSettings.ArchiveSettings.EventDirectory;
6611
6617
  if (eDestination) {
6612
- 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();
6613
6619
  if (!(0, import_fs3.existsSync)(eDestination)) {
6614
6620
  (0, import_fs3.mkdirSync)(eDestination, { recursive: true });
6615
6621
  }
@@ -6617,37 +6623,37 @@ var updateListener = (event) => __async(null, null, function* () {
6617
6623
  }
6618
6624
  metadata.json = JSON.stringify(getCleanedEvent(event), null, 2);
6619
6625
  }
6620
- if (settings.NotifyServer.Enabled && ((_a = listener2 == null ? void 0 : listener2.notify) == null ? void 0 : _a.enabled) && ((_b = listener2 == null ? void 0 : listener2.notify) == null ? void 0 : _b.topic)) {
6621
- const auth = ((_c = settings.NotifyServer.Credentials) == null ? void 0 : _c.Username) && ((_d = settings.NotifyServer.Credentials) == null ? void 0 : _d.Password) ? {
6622
- username: settings.NotifyServer.Credentials.Username,
6623
- password: settings.NotifyServer.Credentials.Password
6624
- } : void 0;
6625
- const attachment = metadata.eas && settings.NotifyServer.Attachments ? `${settings.NotifyServer.Attachments}/${metadata.name}_${metadata.status}_${metadata.tracking}.wav` : null;
6626
- yield createHttp(__spreadProps(__spreadValues({
6627
- url: `${settings.NotifyServer.Server.replace(/\/$/, "")}/${(_e = listener2 == null ? void 0 : listener2.notify) == null ? void 0 : _e.topic}`,
6628
- timeout: 15e3,
6629
- method: "POST"
6630
- }, auth && { auth }), {
6631
- headers: __spreadProps(__spreadValues({
6632
- "Title": `${metadata.name} (${metadata.status})`,
6633
- "Tags": (_g = (_f = properties2.parameters.tags) == null ? void 0 : _f.join(",")) != null ? _g : "N/A"
6634
- }, attachment && { "Attach": attachment }), {
6635
- "Priority": "max",
6636
- "Sound": "siren"
6637
- }),
6638
- body: getRaw(event)
6639
- }));
6626
+ if (((_a = settings == null ? void 0 : settings.NotifyServer) == null ? void 0 : _a.Enabled) && (notify == null ? void 0 : notify.Enabled) && (notify == null ? void 0 : notify.Topic)) {
6627
+ const server = settings == null ? void 0 : settings.NotifyServer;
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;
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;
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
+ }
6640
6646
  }
6641
- if ((webhook == null ? void 0 : webhook.enabled) && (webhook == null ? void 0 : webhook.destination)) {
6642
- const isRatelimited = setTimeoutAction({ identifier: webhook.destination, interval: ((_h = webhook.ratelimit) != null ? _h : 2) * 2, max: (_i = webhook.ratelimit) != null ? _i : 2, addTime: true });
6647
+ if ((webhook == null ? void 0 : webhook.Enabled) && (webhook == null ? void 0 : webhook.Destination)) {
6648
+ const isRatelimited = setTimeoutAction({ identifier: webhook.Destination, interval: ((_k = webhook.Ratelimit) != null ? _k : 2) * 2, max: (_l = webhook.Ratelimit) != null ? _l : 2, addTime: true });
6643
6649
  const form = new FormData();
6644
6650
  const embed = {
6645
6651
  title: `${metadata.name} (${metadata.status})`,
6646
- description: getEmebed(event),
6652
+ description: getEmebedText(event),
6647
6653
  fields: [],
6648
6654
  color: 16711680,
6649
6655
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6650
- footer: { text: (_j = webhook.title) != null ? _j : `AtmosphericX` }
6656
+ footer: { text: (_m = webhook.Title) != null ? _m : `AtmosphericX` }
6651
6657
  };
6652
6658
  if (isRatelimited.limited) {
6653
6659
  return;
@@ -6661,32 +6667,32 @@ var updateListener = (event) => __async(null, null, function* () {
6661
6667
  value: metadata.description ? "```\n" + metadata.description.split("\n").map((l) => l.trim()).filter(Boolean).join("\n") + "\n```" : ""
6662
6668
  });
6663
6669
  }
6664
- if (((_k = metadata.attachments) == null ? void 0 : _k.length) > 0) {
6670
+ if (((_n = metadata.attachments) == null ? void 0 : _n.length) > 0) {
6665
6671
  metadata.attachments = metadata.attachments.slice(0, 5);
6666
6672
  embed.fields.push({
6667
6673
  name: "Attachments",
6668
6674
  value: metadata.attachments.map((attachment) => `- [${attachment.name.length > 45 ? attachment.name.substring(0, 45) + "..." : attachment.name}](${attachment.link})`).join("\n")
6669
6675
  });
6670
6676
  }
6671
- if (uploads == null ? void 0 : uploads.file) {
6677
+ if (uploads == null ? void 0 : uploads.File) {
6672
6678
  form.append("fUpload", new Blob([Buffer.from(metadata.file)], { type: "application/text" }), `${properties2.event}_${properties2.status}_${properties2.metadata.tracking}.txt`);
6673
6679
  }
6674
- if (uploads == null ? void 0 : uploads.event) {
6680
+ if (uploads == null ? void 0 : uploads.JSON) {
6675
6681
  form.append("fUpload2", new Blob([Buffer.from(metadata.json)], { type: "application/json" }), `${properties2.event}_${properties2.status}_${properties2.metadata.tracking}.json`);
6676
6682
  }
6677
- if (uploads == null ? void 0 : uploads.eas) {
6683
+ if (uploads == null ? void 0 : uploads.EAS) {
6678
6684
  if (metadata.eas) {
6679
6685
  const file = (0, import_fs3.readFileSync)(metadata.eas);
6680
6686
  form.append("fEas", new Blob([Buffer.from(file)], { type: "audio/mpeg" }), `${properties2.event}_${properties2.status}_${properties2.metadata.tracking}_eas.mp3`);
6681
6687
  }
6682
6688
  }
6683
6689
  form.append("payload_json", JSON.stringify({
6684
- username: (_l = webhook.title) != null ? _l : "AtmosphericX",
6685
- content: (_m = webhook.message) != null ? _m : "",
6690
+ username: (_o = webhook.Title) != null ? _o : "AtmosphericX",
6691
+ content: (_p = webhook.Message) != null ? _p : "",
6686
6692
  embeds: [embed]
6687
6693
  }));
6688
6694
  yield createHttp({
6689
- url: webhook.destination,
6695
+ url: webhook.Destination,
6690
6696
  timeout: 15e3,
6691
6697
  method: `POST`,
6692
6698
  body: form
@@ -6923,32 +6929,42 @@ var mkEvent = (event) => __async(null, null, function* () {
6923
6929
  }
6924
6930
  });
6925
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
+
6926
6937
  // src/@manager/manager.rmEvent.ts
6927
- var rmEvent = (event) => __async(null, null, function* () {
6928
- const getEvent = bootstrap.cache.events.features.find((f) => {
6929
- var _a, _b, _c, _d;
6930
- 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;
6931
6943
  });
6932
- const cachedStatus = event.properties.status;
6933
- event.properties.expires = (/* @__PURE__ */ new Date()).toISOString();
6934
- event.properties.status = `Expired`;
6935
- event.properties.status_metadata.is_expired = true;
6936
- if (getEvent) {
6937
- if (!event.properties.status_metadata.is_statement) {
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) {
6938
6959
  setEventEmit({
6939
6960
  event: `onEventStatus`,
6940
- metadata: {
6941
- type: `Removed`,
6942
- event
6943
- },
6944
- 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})`
6945
6963
  });
6946
- setEventEmit({ event: `onExpiredProduct`, metadata: event });
6964
+ yield updateListener(event);
6947
6965
  }
6948
- if (cachedStatus != `Statement`) yield updateListener(event);
6949
- bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(getEvent), 1);
6950
- bootstrap.cache.hashes = bootstrap.cache.hashes.filter((hash) => hash.tracking !== event.properties.metadata.tracking);
6951
- setTimeoutAction({ identifier: event.properties.metadata.tracking, expire: true });
6966
+ setTimeoutAction({ identifier: gTracking, expire: true });
6967
+ setTimeoutAction({ identifier: gTracking + `notify.server`, expire: true });
6952
6968
  }
6953
6969
  setEventEmit({
6954
6970
  event: `onEventCache`,
@@ -7101,7 +7117,7 @@ var validateEvents = (events) => __async(null, null, function* () {
7101
7117
  }
7102
7118
  if (properties2.status_metadata.is_expired) {
7103
7119
  setEventEmit({ event: `onExpiredProduct`, metadata: define2 });
7104
- rmEvent(define2);
7120
+ rmEvent(define2, false);
7105
7121
  return true;
7106
7122
  }
7107
7123
  if (((_b = (_a = properties2.metadata) == null ? void 0 : _a.vtec) == null ? void 0 : _b.is_watch) && properties2.metadata.source != `events.api`) {
@@ -7163,18 +7179,19 @@ var validateEvents = (events) => __async(null, null, function* () {
7163
7179
  return false;
7164
7180
  };
7165
7181
  const filtering = events.filter((event) => {
7166
- var _a;
7167
7182
  bootstrap.cache.processed = bootstrap.cache.processed.filter((e) => e !== event);
7168
7183
  const define2 = getEventSignature(event);
7184
+ const pre = __spreadProps(__spreadValues({}, define2), { properties: __spreadProps(__spreadValues({}, define2.properties), { metadata: __spreadValues({}, define2.properties.metadata) }) });
7169
7185
  const properties2 = define2.properties;
7170
- (_a = properties2 == null ? void 0 : properties2.metadata) == null ? true : delete _a.ms;
7186
+ delete pre.properties.metadata.ms;
7187
+ delete pre.properties.metadata.header;
7171
7188
  const enhanced = properties2.event = getEventEnhancedName(event);
7172
7189
  const filtered = isFiltered(define2);
7173
7190
  if (!filtered) {
7174
7191
  event.geometry = !(bools == null ? void 0 : bools.DisableGeometryParsing) ? getEventGeometry(event) : null;
7175
7192
  properties2.metadata.attachments = getEventAttachments(event);
7176
7193
  }
7177
- 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");
7178
7195
  setEventEmit({ event: `onProductType${enhanced.replace(/\s+/g, "")}`, metadata: define2 });
7179
7196
  return !filtered;
7180
7197
  });
@@ -7610,16 +7627,17 @@ var setCronSchedule = () => __async(null, null, function* () {
7610
7627
  // src/@manager/manager.updateEvents.ts
7611
7628
  var updateEvents = (selectedEvent) => __async(null, null, function* () {
7612
7629
  const events = bootstrap.cache.events.features;
7613
- function update(evt) {
7630
+ function update(event) {
7614
7631
  return __async(this, null, function* () {
7615
- if (new Date(evt.properties.expires) < /* @__PURE__ */ new Date()) {
7616
- yield rmEvent(evt);
7632
+ if (new Date(event.properties.expires) < /* @__PURE__ */ new Date()) {
7633
+ setEventEmit({ event: `onExpiredProduct`, metadata: event });
7634
+ yield rmEvent(event, true);
7617
7635
  }
7618
7636
  });
7619
7637
  }
7620
7638
  if (!selectedEvent) {
7621
- yield Promise.all(events.map((evt) => __async(null, null, function* () {
7622
- yield update(evt);
7639
+ yield Promise.all(events.map((event) => __async(null, null, function* () {
7640
+ yield update(event);
7623
7641
  })));
7624
7642
  }
7625
7643
  if (selectedEvent) {