@atmosx/event-product-parser 3.0.42 → 3.0.44

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +13 -0
  2. package/dist/cjs/index.cjs +1795 -1666
  3. package/dist/esm/index.mjs +1770 -1641
  4. package/dist/index.d.mts +6 -0
  5. package/dist/index.d.ts +6 -0
  6. package/package.json +1 -1
  7. package/src/@building/building.create.ts +2 -2
  8. package/src/@building/building.enhance.ts +1 -1
  9. package/src/@building/building.geometry.ts +1 -1
  10. package/src/@building/building.headers.ts +1 -1
  11. package/src/@building/building.office.ts +2 -2
  12. package/src/@building/building.outlooks.ts +36 -0
  13. package/src/@building/building.properties.ts +6 -4
  14. package/src/@building/building.tracking.ts +3 -3
  15. package/src/@building/building.validate.ts +4 -2
  16. package/src/@core/core.query.ts +1 -1
  17. package/src/@core/core.start.ts +1 -1
  18. package/src/@events/events.api.ts +4 -1
  19. package/src/@events/events.text.ts +3 -2
  20. package/src/@events/events.ugc.ts +3 -2
  21. package/src/@events/events.vtec.ts +5 -4
  22. package/src/@manager/manager.createWebhook.ts +93 -81
  23. package/src/@manager/manager.mkEvent.ts +1 -1
  24. package/src/@manager/manager.setHash.ts +1 -1
  25. package/src/@manager/manager.updateWebhooks.ts +1 -1
  26. package/src/@modules/@database/database.cache.ts +1 -1
  27. package/src/@modules/@database/database.init.ts +1 -1
  28. package/src/@modules/@database/database.shapefiles.ts +1 -1
  29. package/src/@modules/@database/database.stanza.ts +2 -2
  30. package/src/@modules/@eas/eas.getCleanDescription.ts +89 -0
  31. package/src/@modules/@eas/eas.getTTS.ts +43 -0
  32. package/src/@modules/@eas/eas.setEasTone.ts +29 -24
  33. package/src/@modules/@stanza/stanza.getAwipsType.ts +1 -1
  34. package/src/@modules/@stanza/stanza.validate.ts +2 -2
  35. package/src/@modules/@utilities/utilities.getLatestIssuance.ts +32 -0
  36. package/src/@modules/@utilities/utilities.getSettings.ts +1 -1
  37. package/src/@modules/@utilities/utilities.isImageReady.ts +27 -0
  38. package/src/@modules/@utilities/utilities.setCronSchedule.ts +28 -2
  39. package/src/@modules/@utilities/utilities.setSettings.ts +1 -1
  40. package/src/@modules/@utilities/utilities.setWarning.ts +1 -1
  41. package/src/@modules/@xmpp/xmpp.xDeploy.ts +1 -1
  42. package/src/@modules/@xmpp/xmpp.xReconnect.ts +1 -1
  43. package/src/@modules/@xmpp/xmpp.xStanza.ts +1 -1
  44. package/src/@parsers/@hvtec/hvtec.extract.ts +1 -1
  45. package/src/@parsers/@pvtec/pvtec.extract.ts +1 -1
  46. package/src/@parsers/@ugc/ugc.extract.ts +1 -1
  47. package/src/@types/{types.compiled.ts → type.compiled.ts} +1 -1
  48. package/src/@types/type.event.ts +4 -2
  49. package/src/@types/type.properties.ts +3 -1
  50. package/src/@types/{types.settings.ts → type.settings.ts} +3 -2
  51. package/src/@types/{types.webhook.ts → type.webhook.ts} +1 -0
  52. package/src/bootstrap.ts +2 -1
  53. package/src/index.ts +1 -1
  54. package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +0 -68
  55. /package/src/@types/{types.attributes.ts → type.attributes.ts} +0 -0
  56. /package/src/@types/{types.hash.ts → type.hash.ts} +0 -0
  57. /package/src/@types/{types.hvtec.ts → type.hvtec.ts} +0 -0
  58. /package/src/@types/{types.pvtec.ts → type.pvtec.ts} +0 -0
  59. /package/src/@types/{types.stanza.ts → type.stanza.ts} +0 -0
  60. /package/src/@types/{types.ugc.ts → type.ugc.ts} +0 -0
@@ -10510,7 +10510,7 @@ module.exports = __toCommonJS(index_exports);
10510
10510
  var import_path = __toESM(require("path"));
10511
10511
  var import_node_events = require("events");
10512
10512
  var bootstrap = {
10513
- version: `3.0.42`,
10513
+ version: `3.0.44`,
10514
10514
  isReady: true,
10515
10515
  ratelimits: {},
10516
10516
  session_xmpp: null,
@@ -10587,6 +10587,7 @@ var bootstrap = {
10587
10587
  IgnoreTestProducts: true
10588
10588
  },
10589
10589
  EASSettings: {
10590
+ ArchiveTTL: 60,
10590
10591
  ArchiveDirectory: null,
10591
10592
  IntroWavFile: null
10592
10593
  }
@@ -14411,7 +14412,7 @@ var getEventTags = (message) => {
14411
14412
 
14412
14413
  // src/@building/building.properties.ts
14413
14414
  var properties = (options) => {
14414
- 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;
14415
+ 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;
14415
14416
  const organization = (_b = (_a = options.message.match(regExp.wmo)) == null ? void 0 : _a[0]) != null ? _b : null;
14416
14417
  const polygons = getPolygonFromProduct(options.message);
14417
14418
  const properties2 = {
@@ -14440,23 +14441,25 @@ var properties = (options) => {
14440
14441
  hail_threat: (_t = getTextFromProduct({ message: options.message, find: [`HAIL THREAT...`], removal: [] })) != null ? _t : null
14441
14442
  },
14442
14443
  spc_parameters: {
14443
- spc_max_tornado: (_u = getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] })) != null ? _u : null,
14444
- spc_max_hail: (_v = getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK HAIL SIZE...`] })) != null ? _v : null,
14445
- spc_max_wind: (_w = getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK WIND GUST...`] })) != null ? _w : null,
14446
- spc_watch_issuance: (_x = getTextFromProduct({ message: options.message, find: [`Probability of Watch Issuance...`], removal: [`percent`] })) != null ? _x : null
14444
+ spc_number: (_u = getTextFromProduct({ message: options.message, find: [`Mesoscale Discussion `], removal: [`Mesoscale Discussion`, `Number`, `...`] })) != null ? _u : null,
14445
+ spc_concerning: (_v = getTextFromProduct({ message: options.message, find: [`Concerning...`] })) != null ? _v : null,
14446
+ spc_max_tornado: (_w = getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] })) != null ? _w : null,
14447
+ spc_max_hail: (_x = getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK HAIL SIZE...`] })) != null ? _x : null,
14448
+ spc_max_wind: (_y = getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK WIND GUST...`] })) != null ? _y : null,
14449
+ spc_watch_issuance: (_z = getTextFromProduct({ message: options.message, find: [`Probability of Watch Issuance...`], removal: [`percent`] })) != null ? _z : null
14447
14450
  },
14448
14451
  watch_parameters: {
14449
- watch_number: (_A = (_z = (_y = getTextFromProduct({ message: options.message, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })) == null ? void 0 : _y.replace(/(WT|WS|)/g, "")) == null ? void 0 : _z.trim()) != null ? _A : null,
14452
+ watch_number: (_C = (_B = (_A = getTextFromProduct({ message: options.message, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })) == null ? void 0 : _A.replace(/(WT|WS|)/g, "")) == null ? void 0 : _B.trim()) != null ? _C : null,
14450
14453
  watch_type: options.message.includes(`TORNADO WATCH`) ? `Tornado` : (options == null ? void 0 : options.message.includes(`SEVERE`)) ? `Severe` : null,
14451
- additional_tornadoes_probability: (_B = getTextFromProduct({ message: options.message, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _B : null,
14452
- strong_tornadoes_probability: (_C = getTextFromProduct({ message: options.message, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _C : null,
14453
- severe_wind_probability: (_D = getTextFromProduct({ message: options.message, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _D : null,
14454
- severe_hail_probability: (_E = getTextFromProduct({ message: options.message, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _E : null,
14455
- hail_2in_probability: (_F = getTextFromProduct({ message: options.message, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] })) != null ? _F : null,
14456
- combined_hail_wind_probability: (_G = getTextFromProduct({ message: options.message, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _G : null,
14457
- max_hail_in: (_H = getTextFromProduct({ message: options.message, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] })) != null ? _H : null,
14458
- max_wind_surface: (_I = getTextFromProduct({ message: options.message, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] })) != null ? _I : null,
14459
- max_tops_x100feet: (_J = getTextFromProduct({ message: options.message, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] })) != null ? _J : null,
14454
+ additional_tornadoes_probability: (_D = getTextFromProduct({ message: options.message, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _D : null,
14455
+ strong_tornadoes_probability: (_E = getTextFromProduct({ message: options.message, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _E : null,
14456
+ severe_wind_probability: (_F = getTextFromProduct({ message: options.message, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _F : null,
14457
+ severe_hail_probability: (_G = getTextFromProduct({ message: options.message, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _G : null,
14458
+ hail_2in_probability: (_H = getTextFromProduct({ message: options.message, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] })) != null ? _H : null,
14459
+ combined_hail_wind_probability: (_I = getTextFromProduct({ message: options.message, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _I : null,
14460
+ max_hail_in: (_J = getTextFromProduct({ message: options.message, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] })) != null ? _J : null,
14461
+ max_wind_surface: (_K = getTextFromProduct({ message: options.message, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] })) != null ? _K : null,
14462
+ max_tops_x100feet: (_L = getTextFromProduct({ message: options.message, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] })) != null ? _L : null,
14460
14463
  pds_watch: getTextFromProduct({ message: options.message, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`
14461
14464
  }
14462
14465
  };
@@ -14804,1791 +14807,1917 @@ var createHttp = (options) => __async(null, null, function* () {
14804
14807
  });
14805
14808
  });
14806
14809
 
14807
- // src/@manager/manager.createWebhook.ts
14808
- var import_form_data = __toESM(require_form_data());
14809
- var createWebhook = (options) => __async(null, null, function* () {
14810
- var _a, _b, _c, _d, _e, _f;
14811
- const event = options.event.properties;
14812
- const settings = options.webhook;
14813
- let body = [
14814
- event.locations ? `**Locations**: ${event.locations.slice(0, 100)}` : null,
14815
- event.issued && event.status != `Expired` ? `**Issued**: <t:${Math.floor(new Date(event.issued).getTime() / 1e3)}:R>` : null,
14816
- event.expires && event.status != `Statement` ? `**Expires**: <t:${Math.floor(new Date(event.expires).getTime() / 1e3)}:R>` : null,
14817
- (() => {
14818
- var _a2, _b2;
14819
- const val = (_a2 = event.parameters.estimated_wind_gusts) != null ? _a2 : null;
14820
- const th = (_b2 = event.parameters.wind_threat) != null ? _b2 : null;
14821
- const combined = [val, th].filter(Boolean).join(" ");
14822
- return combined ? `**Wind Gusts**: ${val} ${th ? `(${th})` : ""}` : null;
14823
- })(),
14824
- (() => {
14825
- var _a2, _b2;
14826
- const val = (_a2 = event.parameters.estimated_hail_size) != null ? _a2 : null;
14827
- const th = (_b2 = event.parameters.hail_threat) != null ? _b2 : null;
14828
- return (val != null ? val : th) ? `**Hail Threat**: ${val} ${th ? `(${th})` : ""}` : null;
14829
- })(),
14830
- event.parameters.damage_threat ? `**Damage Threat**: ${event.parameters.damage_threat}` : null,
14831
- event.parameters.flood_threat ? `**Flood Threat**: ${event.parameters.flood_threat}` : null,
14832
- event.parameters.tornado_threat ? `**Tornado Threat**: ${event.parameters.tornado_threat}` : null,
14833
- event.spc_parameters.spc_max_tornado ? `**Max Tornado Threat**: ${event.spc_parameters.spc_max_tornado}` : null,
14834
- event.spc_parameters.spc_max_hail ? `**Max Hail Threat**: ${event.spc_parameters.spc_max_hail}` : null,
14835
- event.spc_parameters.spc_max_wind ? `**Max Wind Threat**: ${event.spc_parameters.spc_max_wind}` : null,
14836
- event.spc_parameters.spc_watch_issuance ? `**Watch Issuance**: ${event.spc_parameters.spc_watch_issuance}%` : null,
14837
- event.watch_parameters.watch_number ? `**Watch Number**: ${event.watch_parameters.watch_number}` : null,
14838
- event.watch_parameters.strong_tornadoes_probability ? `**Strong Tornadoes Probability**: ${event.watch_parameters.strong_tornadoes_probability}%` : null,
14839
- event.watch_parameters.additional_tornadoes_probability ? `**Additional Tornadoes Probability**: ${event.watch_parameters.additional_tornadoes_probability}%` : null,
14840
- event.watch_parameters.combined_hail_wind_probability ? `**Combined Hail/Wind Probability**: ${event.watch_parameters.combined_hail_wind_probability}%` : null,
14841
- event.watch_parameters.severe_hail_probability ? `**Severe Hail Probability**: ${event.watch_parameters.severe_hail_probability}%` : null,
14842
- event.watch_parameters.hail_2in_probability ? `**Hail \u22652in Probability**: ${event.watch_parameters.hail_2in_probability}%` : null,
14843
- event.watch_parameters.max_hail_in ? `**Max Hail Inches**: ${event.watch_parameters.max_hail_in}` : null,
14844
- event.watch_parameters.severe_wind_probability ? `**Severe Wind Probability**: ${event.watch_parameters.severe_wind_probability}%` : null,
14845
- event.watch_parameters.max_wind_surface ? `**Max Surface Wind**: ${event.watch_parameters.max_wind_surface}` : null,
14846
- event.watch_parameters.max_tops_x100feet ? `**Max Tops (x100 feet)**: ${event.watch_parameters.max_tops_x100feet}` : null,
14847
- ((_a = event.parameters.tags) == null ? void 0 : _a.length) > 0 ? `**Tags**: ${event.parameters.tags.join(", ")}` : null,
14848
- (() => {
14849
- var _a2, _b2, _c2, _d2, _e2, _f2;
14850
- const val = (_c2 = (_b2 = (_a2 = event.geocode) == null ? void 0 : _a2.office) == null ? void 0 : _b2.name) != null ? _c2 : `N/A`;
14851
- const th = (_f2 = (_e2 = (_d2 = event.geocode) == null ? void 0 : _d2.office) == null ? void 0 : _e2.office) != null ? _f2 : null;
14852
- return (val != null ? val : th) ? `**Sender**: ${val} ${th ? `(${th})` : ""}` : null;
14853
- })(),
14854
- ((_b = event.metadata) == null ? void 0 : _b.tracking) ? `**Tracking**: ${event.metadata.tracking}` : null,
14855
- ((_c = event.metadata.history) == null ? void 0 : _c.length) > 0 ? `**Logs**: ${event.metadata.history.length}` : null,
14856
- (() => {
14857
- var _a2;
14858
- if (event.status == `Expired`) {
14859
- return null;
14860
- }
14861
- const desc = ((_a2 = event.description) != null ? _a2 : "").split("\n").map((l) => l.trim()).filter(Boolean).join("\n");
14862
- return desc ? "```\n" + desc + "\n```" : null;
14863
- })()
14864
- ].filter(Boolean).join("\n");
14865
- const isLimited = setTimeoutAction({ identifier: options.webhook.webhook, interval: options.webhook.rate, max: options.webhook.rate, addTime: true });
14866
- if (isLimited.limited) {
14867
- return;
14868
- }
14869
- if (body.length > 1900) {
14870
- body = body.substring(0, 1900) + "\n\n[Message truncated due to length]";
14871
- const blocks = ((_d = body.match(/```/g)) != null ? _d : []).length;
14872
- if (blocks % 2 !== 0) body += "```";
14873
- }
14874
- const form = new import_form_data.default();
14875
- const embed = {
14876
- title: `${event.event} (${event.status})`,
14877
- description: body,
14878
- color: 16711680,
14879
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
14880
- footer: { text: settings.title }
14881
- };
14882
- form.append("payload_json", JSON.stringify({
14883
- username: (_e = settings.title) != null ? _e : "AtmosphericX",
14884
- content: (_f = settings.message) != null ? _f : "",
14885
- embeds: [embed]
14886
- }));
14887
- if (settings.upload) {
14888
- form.append("file", Buffer.from(JSON.stringify(getCleanedEvent(event), null, 2)), {
14889
- filename: `${event.event}_${event.status}_${event.metadata.tracking}.json`,
14890
- contentType: "application/json"
14891
- });
14892
- }
14893
- yield createHttp({
14894
- url: settings.webhook,
14895
- timeout: 2e3,
14896
- method: `POST`,
14897
- headers: form.getHeaders(),
14898
- body: form
14899
- });
14900
- });
14901
-
14902
- // src/@manager/manager.updateWebhooks.ts
14903
- var updateWebhooks = (event) => __async(null, null, function* () {
14904
- const settings = bootstrap.settings;
14905
- const webhooks = settings.WebhookSettings;
14906
- const eventName = event.properties.event;
14907
- for (const socket of webhooks) {
14908
- const events = socket.events;
14909
- if (!events || events.length === 0) {
14910
- yield createWebhook({ webhook: socket, event });
14911
- continue;
14912
- }
14913
- const matched = events.some((pattern) => {
14914
- if (!pattern) return false;
14915
- if (pattern === "*" || pattern === eventName) return true;
14916
- if (pattern.includes("*")) {
14917
- const regex = "^" + pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$";
14918
- return new RegExp(regex).test(eventName);
14919
- }
14920
- return false;
14921
- });
14922
- if (matched) {
14923
- yield createWebhook({ webhook: socket, event });
14924
- }
14810
+ // src/@modules/@utilities/utilities.isImageReady.ts
14811
+ var isImageReady = (url) => __async(null, null, function* () {
14812
+ try {
14813
+ const res = yield fetch(url, { method: "HEAD" });
14814
+ return res.ok;
14815
+ } catch (e) {
14816
+ return false;
14925
14817
  }
14926
14818
  });
14927
14819
 
14928
- // src/@modules/@utilities/utilities.getShapeNearestPoint.ts
14929
- var getShapeNearestPoint = (coordinates, point) => {
14930
- if (!coordinates || !point) {
14931
- return { proximity: false, point: [0, 0], distance: null };
14820
+ // src/@modules/@eas/eas.getWavPCM16.ts
14821
+ var getWavPCM16 = (buffer) => {
14822
+ if (buffer.toString("ascii", 0, 4) !== "RIFF" || buffer.toString("ascii", 8, 12) !== "WAVE") {
14823
+ return null;
14932
14824
  }
14933
- const normalize = (coords) => {
14934
- if (!Array.isArray(coords)) return [];
14935
- if (typeof coords[0] === "number" && typeof coords[1] === "number") return [];
14936
- if (Array.isArray(coords[0]) && typeof coords[0][0] === "number") {
14937
- return [[coords]];
14938
- }
14939
- if (Array.isArray(coords[0]) && Array.isArray(coords[0][0]) && typeof coords[0][0][0] === "number") {
14940
- return [coords];
14941
- }
14942
- if (Array.isArray(coords[0]) && Array.isArray(coords[0][0]) && Array.isArray(coords[0][0][0]) && typeof coords[0][0][0][0] === "number") {
14943
- return coords;
14944
- }
14945
- return [];
14946
- };
14947
- const polys = normalize(coordinates);
14948
- if (polys.length === 0) return { proximity: false, point: [0, 0], distance: null };
14949
- const lon = point[0];
14950
- const lat = point[1];
14951
- const pointInRing = (pt, ring) => {
14952
- let x = pt[0], y = pt[1];
14953
- let inside = false;
14954
- for (let i = 0, j2 = ring.length - 1; i < ring.length; j2 = i++) {
14955
- const xi = ring[i][0], yi = ring[i][1];
14956
- const xj = ring[j2][0], yj = ring[j2][1];
14957
- const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi + 0) + xi;
14958
- if (intersect) inside = !inside;
14959
- }
14960
- return inside;
14961
- };
14962
- const toRadians = (deg) => deg * Math.PI / 180;
14963
- const haversineMiles = (a, b) => {
14964
- const R = 3958.8;
14965
- const dLat = toRadians(b[1] - a[1]);
14966
- const dLon = toRadians(b[0] - a[0]);
14967
- const lat1 = toRadians(a[1]);
14968
- const lat2 = toRadians(b[1]);
14969
- const sinDLat = Math.sin(dLat / 2);
14970
- const sinDLon = Math.sin(dLon / 2);
14971
- const c = 2 * Math.asin(Math.sqrt(sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon));
14972
- return R * c;
14973
- };
14974
- let minDistance = Infinity;
14975
- let closestPoint = null;
14976
- for (const poly of polys) {
14977
- const outer = poly[0];
14978
- const holes = poly.slice(1);
14979
- if (pointInRing(point, outer)) {
14980
- let inHole = false;
14981
- for (const hole of holes) {
14982
- if (pointInRing(point, hole)) {
14983
- inHole = true;
14984
- break;
14985
- }
14986
- }
14987
- if (!inHole) {
14988
- return { proximity: true, point, distance: 0 };
14989
- }
14990
- }
14991
- for (const ring of poly) {
14992
- for (let i = 0; i < ring.length - 1; i++) {
14993
- const start = [ring[i][0], ring[i][1]];
14994
- const end = [ring[i + 1][0], ring[i + 1][1]];
14995
- const A = lon - start[0];
14996
- const B = lat - start[1];
14997
- const C = end[0] - start[0];
14998
- const D = end[1] - start[1];
14999
- const lenSq = C * C + D * D;
15000
- const t = lenSq === 0 ? 0 : Math.max(0, Math.min(1, (A * C + B * D) / lenSq));
15001
- const candidate = [start[0] + t * C, start[1] + t * D];
15002
- const dist = haversineMiles([lon, lat], candidate);
15003
- if (!isNaN(dist) && dist < minDistance) {
15004
- minDistance = Number(dist.toFixed(3));
15005
- closestPoint = candidate;
15006
- }
15007
- }
15008
- }
14825
+ let fmt = null;
14826
+ let data = null;
14827
+ let i = 12;
14828
+ while (i + 8 <= buffer.length) {
14829
+ const id2 = buffer.toString("ascii", i, i + 4);
14830
+ const size = buffer.readUInt32LE(i + 4);
14831
+ const start = i + 8;
14832
+ const end = start + size;
14833
+ if (id2 === "fmt ") fmt = buffer.slice(start, end);
14834
+ if (id2 === "data") data = buffer.slice(start, end);
14835
+ i = end + size % 2;
15009
14836
  }
15010
- if (!isFinite(minDistance) || closestPoint == null) {
15011
- return { proximity: false, point: [0, 0], distance: null };
14837
+ if (!fmt || !data) return null;
14838
+ const audioFormat = fmt.readUInt16LE(0);
14839
+ const channels = fmt.readUInt16LE(2);
14840
+ const sampleRate = fmt.readUInt32LE(4);
14841
+ const bitsPerSample = fmt.readUInt16LE(14);
14842
+ if (audioFormat !== 1 || bitsPerSample !== 16 || channels !== 1) {
14843
+ return null;
15012
14844
  }
15013
- const distanceMiles = minDistance;
15014
- const distanceKm = Number((distanceMiles * 1.609344).toFixed(3));
15015
- const distanceMeters = Math.round(distanceKm * 1e3);
15016
- return { proximity: distanceMiles === 0, point: closestPoint, distance: distanceMiles, distanceKm, distanceMeters };
14845
+ const samples = new Int16Array(data.buffer, data.byteOffset, data.length / 2);
14846
+ return { samples: new Int16Array(samples), sampleRate, channels, bitsPerSample };
15017
14847
  };
15018
14848
 
15019
- // src/@building/building.polygon.ts
15020
- var getEventNodes = (event) => __async(null, null, function* () {
15021
- var _a, _b;
15022
- const metadata = { nodes: [], proximity: false, filtered: false };
15023
- const geometry = yield getEventGeometry(event);
15024
- if (!geometry || !geometry.coordinates) {
15025
- return { nodes: [], filtered: false, updated: Date.now() };
15026
- }
15027
- const nodes = bootstrap.cache.nodes.features;
15028
- for (const node of nodes) {
15029
- const [longitude, latitude] = node.geometry.coordinates;
15030
- const getPoint = getShapeNearestPoint(geometry.coordinates, [longitude, latitude]);
15031
- const miles = (_a = getPoint.distance) != null ? _a : null;
15032
- const kilometers = Number((miles * 1.609344).toFixed(3));
15033
- const info = {
15034
- id: (_b = node.properties) == null ? void 0 : _b.identifier,
15035
- coordinates: [longitude, latitude],
15036
- nearest: getPoint.point,
15037
- miles,
15038
- kilometers,
15039
- proximity: getPoint.proximity
15040
- };
15041
- metadata.nodes.push(info);
15042
- if (bootstrap.settings.GlobalSettings.EventFiltering.NodeLocationFiltering && miles < bootstrap.settings.GlobalSettings.NodeMinDistance) {
15043
- metadata.proximity = true;
15044
- info.proximity = true;
15045
- }
14849
+ // src/@modules/@eas/eas.getSampledPCM16.ts
14850
+ var getSampledPCM16 = (int16, originalRate, targetRate) => {
14851
+ if (originalRate === targetRate) return int16;
14852
+ const ratio = targetRate / originalRate;
14853
+ const outLen = Math.max(1, Math.round(int16.length * ratio));
14854
+ const out = new Int16Array(outLen);
14855
+ for (let i = 0; i < outLen; i++) {
14856
+ const pos = i / ratio;
14857
+ const i0 = Math.floor(pos);
14858
+ const i1 = Math.min(i0 + 1, int16.length - 1);
14859
+ const frac = pos - i0;
14860
+ const v = int16[i0] * (1 - frac) + int16[i1] * frac;
14861
+ out[i] = Math.round(v);
15046
14862
  }
15047
- return {
15048
- nodes: metadata.nodes,
15049
- filtered: metadata.proximity,
15050
- updated: Date.now()
15051
- };
15052
- });
14863
+ return out;
14864
+ };
15053
14865
 
15054
- // src/@manager/manager.updateNodes.ts
15055
- var updateNode = (selectedEvent) => __async(null, null, function* () {
15056
- const events = bootstrap.cache.events.features;
15057
- const ttl = bootstrap.settings.GlobalSettings.NodeTTL * 1e3;
15058
- let total = 0;
15059
- function update(evt) {
15060
- return __async(this, null, function* () {
15061
- var _a, _b, _c;
15062
- const lastUpdate = (_c = (_b = (_a = evt == null ? void 0 : evt.properties) == null ? void 0 : _a.metadata) == null ? void 0 : _b.updated) != null ? _c : null;
15063
- if (lastUpdate != null && Date.now() - lastUpdate < ttl) {
15064
- return evt;
15065
- }
15066
- const node = yield getEventNodes(evt);
15067
- if (node.nodes.length > 0) {
15068
- total++;
15069
- }
15070
- evt.properties.metadata.nodes = node.nodes;
15071
- evt.properties.metadata.filtered_proximity = node.filtered;
15072
- evt.properties.metadata.updated = node.updated;
15073
- });
15074
- }
15075
- if (!selectedEvent) {
15076
- yield Promise.all(events.map((evt) => __async(null, null, function* () {
15077
- yield update(evt);
15078
- })));
15079
- }
15080
- if (selectedEvent) {
15081
- yield update(selectedEvent);
15082
- }
15083
- if (total > 0) {
15084
- setEventEmit({
15085
- event: `onNodeUpdate`,
15086
- metadata: {
15087
- type: `global-update`,
15088
- updated: total
15089
- }
15090
- });
14866
+ // src/@modules/@eas/eas.getPCMToFloat.ts
14867
+ var getPCMToFloat = (int16) => {
14868
+ const out = new Float32Array(int16.length);
14869
+ for (let i = 0; i < int16.length; i++) out[i] = int16[i] / 32768;
14870
+ return out;
14871
+ };
14872
+
14873
+ // src/@modules/@eas/eas.getFloatPCM16.ts
14874
+ var getFloatPCM16 = (float32) => {
14875
+ const out = new Int16Array(float32.length);
14876
+ for (let i = 0; i < float32.length; i++) {
14877
+ let v = Math.max(-1, Math.min(1, float32[i]));
14878
+ out[i] = Math.round(v * 32767);
15091
14879
  }
15092
- });
14880
+ return out;
14881
+ };
15093
14882
 
15094
- // src/@manager/manager.mkEvent.ts
15095
- var mkEvent = (event) => __async(null, null, function* () {
15096
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
15097
- const settings = bootstrap.settings;
15098
- const features = bootstrap.cache.events.features;
15099
- const getHash = event.properties.metadata.hash;
15100
- const getTracking = event.properties.metadata.tracking;
15101
- const isEntry = (_a = bootstrap.cache.hashes) == null ? void 0 : _a.find((hash) => hash.tracking === getTracking);
15102
- const isHashed = (_c = (_b = isEntry == null ? void 0 : isEntry.hashes) == null ? void 0 : _b.includes(getHash)) != null ? _c : false;
15103
- const getFeature = features.find((feature) => feature.properties.metadata.tracking === getTracking);
15104
- if (isHashed || event.properties.status_metadata.is_expired) return;
15105
- setHash(event, isEntry);
15106
- const isFilteredLocation = yield updateNode(event).then(() => event.properties.metadata.filtered_proximity);
15107
- if (!isFilteredLocation && settings.GlobalSettings.EventFiltering.NodeLocationFiltering) {
15108
- return;
15109
- }
15110
- setEventEmit({
15111
- event: `onEventStatus`,
15112
- metadata: {
15113
- type: getFeature ? `Updated` : `New`,
15114
- event
15115
- },
15116
- message: `[${getFeature ? "Updated" : "New"}] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
15117
- });
15118
- if (settings.GlobalSettings.EventManagement) {
15119
- if (event.properties.status_metadata.is_issued || event.properties.status_metadata.is_updated) {
15120
- if (getFeature) {
15121
- const getIndex = features.indexOf(getFeature);
15122
- const cHistory = (_f = (_e = (_d = getFeature == null ? void 0 : getFeature.properties) == null ? void 0 : _d.metadata) == null ? void 0 : _e.history) != null ? _f : [];
15123
- 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 : [];
15124
- const cUgc = (_l = (_k = (_j = getFeature == null ? void 0 : getFeature.properties) == null ? void 0 : _j.geocode) == null ? void 0 : _k.ugc) != null ? _l : [];
15125
- const iHistory = (_o = (_n = (_m = event.properties) == null ? void 0 : _m.metadata) == null ? void 0 : _n.history) != null ? _o : [];
15126
- const iLocations = (_r = (_q = (_p = event.properties) == null ? void 0 : _p.locations) == null ? void 0 : _q.split(";").map((l) => l.trim())) != null ? _r : [];
15127
- const iUgc = (_u = (_t = (_s = event.properties) == null ? void 0 : _s.geocode) == null ? void 0 : _t.ugc) != null ? _u : [];
15128
- 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);
15129
- const mLocations = [...cLocations, ...iLocations].filter((v, i, a) => a.indexOf(v) === i).join("; ");
15130
- const mUgc = [...cUgc, ...iUgc].filter((v, i, a) => a.indexOf(v) === i);
15131
- bootstrap.cache.events.features[getIndex] = __spreadProps(__spreadValues({}, event), {
15132
- properties: __spreadProps(__spreadValues({}, event.properties), {
15133
- metadata: __spreadProps(__spreadValues({}, (_v = event == null ? void 0 : event.properties) == null ? void 0 : _v.metadata), {
15134
- history: mHistory
15135
- }),
15136
- locations: mLocations,
15137
- geocode: __spreadProps(__spreadValues({}, (_w = event == null ? void 0 : event.properties) == null ? void 0 : _w.geocode), {
15138
- ugc: mUgc
15139
- })
15140
- })
15141
- });
15142
- updateWebhooks(bootstrap.cache.events.features[getIndex]);
15143
- } else {
15144
- features.push(event);
15145
- updateWebhooks(event);
15146
- }
15147
- }
15148
- }
15149
- });
15150
-
15151
- // src/@manager/manager.rmEvent.ts
15152
- var rmEvent = (event) => {
15153
- const getEvent = bootstrap.cache.events.features.find((f) => {
15154
- var _a, _b, _c, _d;
15155
- 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);
15156
- });
15157
- const cachedStatus = event.properties.status;
15158
- event.properties.expires = (/* @__PURE__ */ new Date()).toISOString();
15159
- event.properties.status = `Expired`;
15160
- if (getEvent) {
15161
- setEventEmit({
15162
- event: `onEventStatus`,
15163
- metadata: {
15164
- type: `Removed`,
15165
- event
15166
- },
15167
- message: `[Removed] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
15168
- });
15169
- setEventEmit({ event: `onExpiredProduct`, metadata: event });
15170
- if (cachedStatus != `Statement`) updateWebhooks(event);
15171
- bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(getEvent), 1);
15172
- bootstrap.cache.hashes = bootstrap.cache.hashes.filter((hash) => hash.tracking !== event.properties.metadata.tracking);
15173
- }
15174
- setEventEmit({
15175
- event: `onEventCache`,
15176
- metadata: bootstrap.cache.events,
15177
- limited: true
15178
- });
15179
- };
15180
-
15181
- // src/@building/building.validate.ts
15182
- var validateEvents = (events) => __async(null, null, function* () {
15183
- var _a;
15184
- if (events.length === 0) return;
15185
- const configurations = bootstrap.settings;
15186
- const sets = {};
15187
- const bools = {};
15188
- const megered = __spreadValues(__spreadValues({}, configurations.GlobalSettings), configurations.GlobalSettings.EventFiltering);
15189
- for (const key in megered) {
15190
- const setting = megered[key];
15191
- if (Array.isArray(setting)) {
15192
- sets[key] = new Set(setting.map((item) => item.toLowerCase()));
15193
- }
15194
- if (typeof setting === "boolean") {
15195
- bools[key] = setting;
15196
- }
15197
- }
15198
- const filterd = events.filter((event) => {
15199
- var _a2, _b, _c, _d, _e;
15200
- const define2 = getEventSignature(event);
15201
- const properties2 = define2.properties;
15202
- const zones = properties2.geocode.ugc;
15203
- const icao = properties2.geocode.office.office;
15204
- const enhancedEventName = properties2.event = getEventEnhancedName(event);
15205
- const filteredProperties = JSON.parse(JSON.stringify(properties2));
15206
- if ((filteredProperties == null ? void 0 : filteredProperties.metadata) && "ms" in filteredProperties.metadata) {
15207
- delete filteredProperties.metadata.ms;
15208
- }
15209
- filteredProperties.metadata = (_a2 = filteredProperties.metadata) != null ? _a2 : {};
15210
- properties2.metadata.hash = (0, import_crypto.createHash)("sha256").update(JSON.stringify(filteredProperties)).digest("hex");
15211
- setEventEmit({ event: `onProductType${enhancedEventName.replace(/\s+/g, "")}`, metadata: define2 });
15212
- if (properties2.status_metadata.is_test) {
15213
- setEventEmit({ event: `onTestProduct`, metadata: define2 });
15214
- if (bools == null ? void 0 : bools.IgnoreTestProducts) return false;
15215
- }
15216
- if (properties2.status_metadata.is_expired) {
15217
- setEventEmit({ event: `onExpiredProduct`, metadata: define2 });
15218
- rmEvent(define2);
15219
- return false;
15220
- }
15221
- if ((_c = (_b = properties2.metadata) == null ? void 0 : _b.vtec) == null ? void 0 : _c.is_watch) {
15222
- const isSPC = (_e = (_d = properties2.metadata) == null ? void 0 : _d.vtec) == null ? void 0 : _e.prediction_center;
15223
- setEventEmit({ event: isSPC ? `onStormPredictionWatch` : `onNonStormPredictionWatch`, metadata: define2 });
15224
- if ((bools == null ? void 0 : bools.SPCWatchesOnly) && !isSPC) {
15225
- return false;
15226
- }
15227
- if (!(bools == null ? void 0 : bools.SPCWatchesOnly) && isSPC) {
15228
- return false;
15229
- }
15230
- }
15231
- for (const key in sets) {
15232
- const setting = sets[key];
15233
- if (key === "ListeningEvents" && setting.size > 0 && !setting.has(define2.properties.event.toLowerCase())) {
15234
- setEventEmit({
15235
- event: `onFilteredEvent`,
15236
- metadata: define2
15237
- });
15238
- return false;
15239
- }
15240
- if (key === "IgnoredEvents" && setting.size > 0 && setting.has(define2.properties.event.toLowerCase())) {
15241
- setEventEmit({
15242
- event: `onIgnoredEvent`,
15243
- metadata: define2
15244
- });
15245
- return false;
15246
- }
15247
- if (key === "ListeningICAO" && setting.size > 0 && icao != null && !setting.has(icao.toLowerCase())) {
15248
- setEventEmit({
15249
- event: `onFilteredICAO`,
15250
- metadata: define2
15251
- });
15252
- return false;
15253
- }
15254
- if (key === "IgnoredICAO" && setting.size > 0 && icao != null && setting.has(icao.toLowerCase())) {
15255
- setEventEmit({
15256
- event: `onIgnoredICAO`,
15257
- metadata: define2
15258
- });
15259
- return false;
15260
- }
15261
- if (key === "ListeningUGC" && setting.size > 0 && zones.length > 0 && !zones.some((ugc2) => setting.has(ugc2.toLowerCase()))) {
15262
- setEventEmit({
15263
- event: `onFilteredUGC`,
15264
- metadata: define2
15265
- });
15266
- return false;
15267
- }
15268
- if (key === "ListeningStates" && setting.size > 0 && zones.length > 0 && !zones.some((ugc2) => setting.has(ugc2.substring(0, 2).toLowerCase()))) {
15269
- setEventEmit({
15270
- event: `onFilteredState`,
15271
- metadata: define2
15272
- });
15273
- return false;
15274
- }
15275
- }
15276
- return true;
15277
- });
15278
- if (!((_a = configurations == null ? void 0 : configurations.GlobalSettings) == null ? void 0 : _a.DisableGeometryParsing)) {
15279
- for (const event of filterd) {
15280
- event.geometry = yield getEventGeometry(event);
15281
- }
15282
- }
15283
- if (filterd.length > 0) {
15284
- for (const event of filterd) {
15285
- yield mkEvent(event);
15286
- }
15287
- }
15288
- yield updateNode();
15289
- setEventEmit({
15290
- event: `onEventCache`,
15291
- metadata: bootstrap.cache.events,
15292
- limited: true
15293
- });
15294
- });
15295
-
15296
- // src/@events/events.text.ts
15297
- var text = (stanza) => __async(null, null, function* () {
15298
- var _a, _b, _c;
15299
- let processed = [];
15300
- const getMessages = (_c = (_b = (_a = stanza == null ? void 0 : stanza.message) == null ? void 0 : _a.split(/(?=\$\$)/g)) == null ? void 0 : _b.map((message) => message.trim())) == null ? void 0 : _c.filter((message) => message && message !== "$$");
15301
- if (!getMessages || (getMessages == null ? void 0 : getMessages.length) == 0) return;
15302
- for (const message of getMessages) {
15303
- const tick = performance.now();
15304
- const attributes = stanza == null ? void 0 : stanza.attributes;
15305
- const props = properties({ message, attributes });
15306
- const header = getEventHeader({ properties: props, getType: stanza.getType });
15307
- const issued = new Date(attributes.issue);
15308
- const expires = new Date(issued.getTime() + 12 * 60 * 60 * 1e3);
15309
- let event = Object.keys(eventsMatchText).find((event2) => message.toLowerCase().includes(event2.toLowerCase()));
15310
- let isStatement = false;
15311
- if (!event) {
15312
- event = stanza.getType.type.split(`-`).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(` `);
15313
- isStatement = true;
15314
- }
15315
- processed.push({
15316
- type: `Feature`,
15317
- geometry: {
15318
- type: `Point`,
15319
- coordinates: []
15320
- },
15321
- properties: __spreadProps(__spreadValues({
15322
- event,
15323
- parent: event,
15324
- status: isStatement ? `Statement` : `Issued`,
15325
- issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15326
- expires: isStatement ? new Date(issued.getTime() + 120 * 1e3).toISOString() : !isNaN(expires.getTime()) ? expires.toISOString() : new Date(Date.now() + 60 * 60 * 1e3).toISOString()
15327
- }, props), {
15328
- metadata: {
15329
- ms: performance.now() - tick,
15330
- source: `events.text`,
15331
- tracking: getEventTracking({ type: `RAW`, stanza, attributes, properties: props }),
15332
- header,
15333
- vtec: null,
15334
- hvtec: null,
15335
- history: [
15336
- {
15337
- description: props.description,
15338
- issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15339
- status: `Issued`
15340
- }
15341
- ]
15342
- }
15343
- })
15344
- });
15345
- }
15346
- validateEvents(processed);
15347
- });
15348
-
15349
- // src/@parsers/@ugc/ugc.header.ts
15350
- var getUGCHeader = (message) => {
15351
- const start = message.search(regExp.ugc1);
15352
- const sub = message.substring(start);
15353
- const end = sub.search(regExp.ugc2);
15354
- const fin = sub.substring(0, end).replace(/\s+/g, "").slice(0, -1);
15355
- return fin != null ? fin : null;
15356
- };
15357
-
15358
- // src/@parsers/@ugc/ugc.zones.ts
15359
- var getZones = (header) => {
15360
- const splits = header.split("-");
15361
- const zones = [];
15362
- let state = splits[0].substring(0, 2);
15363
- const format = splits[0].substring(2, 3);
15364
- for (const part of splits) {
15365
- if (/^[A-Z]/.test(part)) {
15366
- state = part.substring(0, 2);
15367
- if (part.includes(">")) {
15368
- const [start, end] = part.split(">");
15369
- const startNum = parseInt(start.substring(3), 10);
15370
- const endNum = parseInt(end, 10);
15371
- for (let j2 = startNum; j2 <= endNum; j2++) {
15372
- zones.push(`${state}${format}${j2.toString().padStart(3, "0")}`);
15373
- }
15374
- } else {
15375
- zones.push(part);
15376
- }
15377
- continue;
15378
- }
15379
- if (part.includes(">")) {
15380
- const [start, end] = part.split(">");
15381
- const startNum = parseInt(start, 10);
15382
- const endNum = parseInt(end, 10);
15383
- for (let j2 = startNum; j2 <= endNum; j2++) {
15384
- zones.push(`${state}${format}${j2.toString().padStart(3, "0")}`);
15385
- }
15386
- } else {
15387
- zones.push(`${state}${format}${part}`);
15388
- }
14883
+ // src/@modules/@eas/eas.setRadioEffect.ts
14884
+ var setRadioEffect = (int16, sampleRate) => {
14885
+ const hpCut = 3555;
14886
+ const lpCut = 1600;
14887
+ const x = getPCMToFloat(int16);
14888
+ const dt = 1 / sampleRate;
14889
+ const rcHP = 1 / (2 * Math.PI * hpCut);
14890
+ const aHP = rcHP / (rcHP + dt);
14891
+ let yHP = 0, xPrev = 0;
14892
+ for (let i = 0; i < x.length; i++) {
14893
+ const xi = x[i];
14894
+ yHP = aHP * (yHP + xi - xPrev);
14895
+ xPrev = xi;
14896
+ x[i] = yHP;
15389
14897
  }
15390
- return zones.filter((item) => item !== "");
15391
- };
15392
-
15393
- // src/@parsers/@ugc/ugc.expiry.ts
15394
- var getExpiry = (message) => {
15395
- const match = message.match(/\b(\d{6})-/);
15396
- if (!match) {
15397
- return null;
14898
+ const rcLP = 1 / (2 * Math.PI * lpCut);
14899
+ const aLP = dt / (rcLP + dt);
14900
+ let yLP = 0;
14901
+ for (let i = 0; i < x.length; i++) {
14902
+ yLP = yLP + aLP * (x[i] - yLP);
14903
+ x[i] = yLP;
15398
14904
  }
15399
- const date = match == null ? void 0 : match[1];
15400
- const day = parseInt(date == null ? void 0 : date.slice(0, 2), 10);
15401
- const hour = parseInt(date == null ? void 0 : date.slice(2, 4), 10);
15402
- const minute = parseInt(date == null ? void 0 : date.slice(4, 6), 10);
15403
- const now = /* @__PURE__ */ new Date();
15404
- const expires = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), day, hour, minute));
15405
- return expires.toISOString();
14905
+ const compGain = 2;
14906
+ const norm = Math.tanh(compGain);
14907
+ for (let i = 0; i < x.length; i++) x[i] = Math.tanh(x[i] * compGain) / norm;
14908
+ return getFloatPCM16(x);
15406
14909
  };
15407
14910
 
15408
- // src/@parsers/@ugc/ugc.locations.ts
15409
- var getLocations = (zones) => __async(null, null, function* () {
15410
- const sites = Array.from(new Set(zones));
15411
- const placeholders = sites.map(() => "?").join(",");
15412
- const rows = yield bootstrap.database.prepare(`SELECT id, location FROM shapefiles WHERE id IN (${placeholders})`).all(...sites);
15413
- return rows.map((row) => row.location).sort();
15414
- });
15415
-
15416
- // src/@parsers/@ugc/ugc.extract.ts
15417
- var ugcExtract = (message) => __async(null, null, function* () {
15418
- const head = getUGCHeader(message);
15419
- const ugcs = getZones(head);
15420
- const expires = getExpiry(message);
15421
- const areas = yield getLocations(ugcs);
15422
- if (!head || (ugcs == null ? void 0 : ugcs.length) == 0) return;
15423
- return {
15424
- zones: ugcs,
15425
- locations: areas,
15426
- expires
15427
- };
15428
- });
15429
-
15430
- // src/@events/events.ugc.ts
15431
- var ugc = (stanza) => __async(null, null, function* () {
15432
- var _a, _b, _c;
15433
- let processed = [];
15434
- const getMessages = (_c = (_b = (_a = stanza == null ? void 0 : stanza.message) == null ? void 0 : _a.split(/(?=\$\$)/g)) == null ? void 0 : _b.map((message) => message.trim())) == null ? void 0 : _c.filter((message) => message && message !== "$$");
15435
- if (!getMessages || (getMessages == null ? void 0 : getMessages.length) == 0) return;
15436
- for (const message of getMessages) {
15437
- const tick = performance.now();
15438
- const attributes = stanza == null ? void 0 : stanza.attributes;
15439
- const ugc2 = yield ugcExtract(message);
15440
- if (ugc2 != null) {
15441
- const props = properties({ message, attributes, ugc: ugc2 });
15442
- const issued = new Date(attributes.issue);
15443
- const expires = new Date(ugc2.expires);
15444
- const header = getEventHeader({ properties: props, getType: stanza.getType });
15445
- let event = Object.keys(eventsMatchText).find((event2) => message.toLowerCase().includes(event2.toLowerCase()));
15446
- let isStatement = false;
15447
- if (!event) {
15448
- event = stanza.getType.type.split(`-`).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(` `);
15449
- isStatement = true;
15450
- }
15451
- processed.push({
15452
- type: `Feature`,
15453
- geometry: {
15454
- type: `Point`,
15455
- coordinates: []
15456
- },
15457
- properties: __spreadProps(__spreadValues({
15458
- event,
15459
- parent: event,
15460
- status: isStatement ? `Statement` : `Issued`,
15461
- issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15462
- expires: isStatement ? new Date(issued.getTime() + 120 * 1e3).toISOString() : !isNaN(expires.getTime()) ? expires.toISOString() : new Date(Date.now() + 60 * 60 * 1e3).toISOString()
15463
- }, props), {
15464
- metadata: {
15465
- ms: performance.now() - tick,
15466
- source: `events.ugc`,
15467
- tracking: getEventTracking({ type: `RAW`, stanza, attributes, properties: props }),
15468
- header,
15469
- vtec: null,
15470
- hvtec: null,
15471
- history: [
15472
- {
15473
- description: props.description,
15474
- issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15475
- status: `Issued`
15476
- }
15477
- ]
15478
- }
15479
- })
15480
- });
14911
+ // src/@modules/@eas/eas.setAFSK.ts
14912
+ var setAFSK = (bits, sampleRate) => {
14913
+ const baud = 520.83;
14914
+ const markFreq = 2083.3;
14915
+ const spaceFreq = 1562.5;
14916
+ const amplitude = 0.6;
14917
+ const twoPi = Math.PI * 2;
14918
+ const result = [];
14919
+ let phase = 0;
14920
+ let frac = 0;
14921
+ for (let b = 0; b < bits.length; b++) {
14922
+ const bit = bits[b];
14923
+ const freq = bit ? markFreq : spaceFreq;
14924
+ const samplesPerBit = sampleRate / baud + frac;
14925
+ const n = Math.round(samplesPerBit);
14926
+ frac = samplesPerBit - n;
14927
+ const inc = twoPi * freq / sampleRate;
14928
+ for (let i = 0; i < n; i++) {
14929
+ result.push(Math.round(Math.sin(phase) * amplitude * 32767));
14930
+ phase += inc;
14931
+ if (phase > twoPi) phase -= twoPi;
15481
14932
  }
15482
14933
  }
15483
- validateEvents(processed);
15484
- });
14934
+ const fadeSamples = Math.floor(sampleRate * 2e-3);
14935
+ for (let i = 0; i < fadeSamples; i++) {
14936
+ const gain = i / fadeSamples;
14937
+ result[i] = Math.round(result[i] * gain);
14938
+ result[result.length - 1 - i] = Math.round(result[result.length - 1 - i] * gain);
14939
+ }
14940
+ return Int16Array.from(result);
14941
+ };
15485
14942
 
15486
- // src/@dictionaries/dictionaries.eventTypes.ts
15487
- var eventTypes = {
15488
- "AF": "Ashfall",
15489
- "AS": "Air Stagnation",
15490
- "BH": "Beach Hazard",
15491
- "BW": "Brisk Wind",
15492
- "BZ": "Blizzard",
15493
- "CF": "Coastal Flood",
15494
- "DF": "Debris Flow",
15495
- "DS": "Dust Storm",
15496
- "EC": "Extreme Cold",
15497
- "EH": "Excessive Heat",
15498
- "XH": "Extreme Heat",
15499
- "EW": "Extreme Wind",
15500
- "FA": "Areal Flood",
15501
- "FF": "Flash Flood",
15502
- "FG": "Dense Fog",
15503
- "FL": "Flood",
15504
- "FR": "Frost",
15505
- "FW": "Fire Weather",
15506
- "FZ": "Freeze",
15507
- "GL": "Gale",
15508
- "HF": "Hurricane Force Wind",
15509
- "HT": "Heat",
15510
- "HU": "Hurricane",
15511
- "HW": "High Wind",
15512
- "HY": "Hydrologic",
15513
- "HZ": "Hard Freeze",
15514
- "IS": "Ice Storm",
15515
- "LE": "Lake Effect Snow",
15516
- "LO": "Low Water",
15517
- "LS": "Lakeshore Flood",
15518
- "LW": "Lake Wind",
15519
- "MA": "Special Marine",
15520
- "EQ": "Earthquake",
15521
- "MF": "Dense Fog",
15522
- "MH": "Ashfall",
15523
- "MS": "Dense Smoke",
15524
- "RB": "Small Craft for Rough Bar",
15525
- "RP": "Rip Current Risk",
15526
- "SC": "Small Craft",
15527
- "SE": "Hazardous Seas",
15528
- "SI": "Small Craft for Winds",
15529
- "SM": "Dense Smoke",
15530
- "SQ": "Snow Squall",
15531
- "SR": "Storm",
15532
- "SS": "Storm Surge",
15533
- "SU": "High Surf",
15534
- "SV": "Severe Thunderstorm",
15535
- "SW": "Small Craft for Hazardous Seas",
15536
- "TO": "Tornado",
15537
- "TR": "Tropical Storm",
15538
- "TS": "Tsunami",
15539
- "TY": "Typhoon",
15540
- "SP": "Special Weather",
15541
- "UP": "Heavy Freezing Spray",
15542
- "WC": "Wind Chill",
15543
- "WI": "Wind",
15544
- "WS": "Winter Storm",
15545
- "WW": "Winter Weather",
15546
- "ZF": "Freezing Fog",
15547
- "ZR": "Freezing Rain",
15548
- "ZY": "Freezing Spray"
14943
+ // src/@modules/@eas/eas.setAsciiToBits.ts
14944
+ var setAsciiToBits = (str) => {
14945
+ const bits = [];
14946
+ for (let i = 0; i < str.length; i++) {
14947
+ const c = str.charCodeAt(i) & 255;
14948
+ bits.push(0);
14949
+ for (let b = 0; b < 8; b++) bits.push(c >> b & 1);
14950
+ bits.push(1, 1);
14951
+ }
14952
+ return bits;
15549
14953
  };
15550
14954
 
15551
- // src/@dictionaries/dictionaries.eventActions.ts
15552
- var eventActions = {
15553
- "W": "Warning",
15554
- "F": "Forecast",
15555
- "A": "Watch",
15556
- "O": "Outlook",
15557
- "Y": "Advisory",
15558
- "N": "Synopsis",
15559
- "S": "Statement"
14955
+ // src/@modules/@eas/eas.getMergedPCM16.ts
14956
+ var getMergedPCM16 = (arrays) => {
14957
+ let total = 0;
14958
+ for (const a of arrays) total += a.length;
14959
+ const out = new Int16Array(total);
14960
+ let o = 0;
14961
+ for (const a of arrays) {
14962
+ out.set(a, o);
14963
+ o += a.length;
14964
+ }
14965
+ return out;
15560
14966
  };
15561
14967
 
15562
- // src/@dictionaries/dictionaries.eventStatus.ts
15563
- var eventStatus = {
15564
- "NEW": "Issued",
15565
- "CON": "Updated",
15566
- "EXT": "Extended",
15567
- "EXA": "Extended",
15568
- "EXB": "Extended",
15569
- "UPG": "Upgraded",
15570
- "COR": "Correction",
15571
- "ROU": "Routine",
15572
- "CAN": "Cancelled",
15573
- "EXP": "Expired"
14968
+ // src/@modules/@eas/eas.setSameHeader.ts
14969
+ var setSameHeader = (vtec2, repeats, sampleRate = 8e3, options = {}) => {
14970
+ var _a, _b;
14971
+ const preMarkSec = (_a = options.preMarkSec) != null ? _a : 0.3;
14972
+ const gapSec = (_b = options.gapSec) != null ? _b : 0.1;
14973
+ const bursts = [];
14974
+ const gap = new Int16Array(Math.floor(gapSec * sampleRate));
14975
+ for (let i = 0; i < repeats; i++) {
14976
+ const bodyBits = setAsciiToBits(vtec2);
14977
+ const body = setAFSK(bodyBits, sampleRate);
14978
+ const extendedBodyDuration = Math.round(preMarkSec * sampleRate);
14979
+ const extendedBody = new Int16Array(extendedBodyDuration + gap.length);
14980
+ for (let j2 = 0; j2 < extendedBodyDuration; j2++) {
14981
+ extendedBody[j2] = Math.round(body[j2 % body.length] * 0.2);
14982
+ }
14983
+ extendedBody.set(gap, extendedBodyDuration);
14984
+ bursts.push(extendedBody);
14985
+ if (i !== repeats - 1) bursts.push(gap);
14986
+ }
14987
+ return getMergedPCM16(bursts);
15574
14988
  };
15575
14989
 
15576
- // src/@parsers/@pvtec/pvtec.expires.ts
15577
- var getExpiry2 = (dates) => {
15578
- if ((dates == null ? void 0 : dates[1]) == `000000T0000Z`) return "Invalid Date Format";
15579
- const expires = `${(/* @__PURE__ */ new Date()).getFullYear().toString().substring(0, 2)}${dates[1].substring(0, 2)}-${dates[1].substring(2, 4)}-${dates[1].substring(4, 6)}T${dates[1].substring(7, 9)}:${dates[1].substring(9, 11)}:00`;
15580
- const local = new Date(new Date(expires).getTime() - 4 * 60 * 6e4);
15581
- const pad = (n) => n.toString().padStart(2, "0");
15582
- return `${local.getFullYear()}-${pad(local.getMonth() + 1)}-${pad(local.getDate())}T${pad(local.getHours())}:${pad(local.getMinutes())}:00.000-04:00`;
14990
+ // src/@modules/@eas/eas.setAttentionTone.ts
14991
+ var setAttentionTone = (ms, sampleRate) => {
14992
+ const len = Math.floor(ms * sampleRate);
14993
+ const out = new Int16Array(len);
14994
+ const f1 = 853;
14995
+ const f2 = 960;
14996
+ const twoPi = Math.PI * 2;
14997
+ const amp = 0.1;
14998
+ const fadeLen = Math.floor(sampleRate * 0);
14999
+ for (let i = 0; i < len; i++) {
15000
+ const t = i / sampleRate;
15001
+ const s = Math.sin(twoPi * f1 * t) + Math.sin(twoPi * f2 * t);
15002
+ let gain = 1;
15003
+ if (i < fadeLen) gain = i / fadeLen;
15004
+ else if (i > len - fadeLen) gain = (len - i) / fadeLen;
15005
+ const v = Math.max(-1, Math.min(1, s / 2 * amp * gain));
15006
+ out[i] = Math.round(v * 32767);
15007
+ }
15008
+ return out;
15583
15009
  };
15584
15010
 
15585
- // src/@parsers/@pvtec/pvtec.extract.ts
15586
- var pvExtract = (message) => {
15587
- var _a, _b, _c, _d;
15588
- const getVTECs = (_a = message.match(regExp.pvtec)) != null ? _a : [];
15589
- const vtecs = [];
15590
- for (const vtec2 of getVTECs) {
15591
- const sub = vtec2.split(`.`);
15592
- if ((sub == null ? void 0 : sub.length) < 7) continue;
15593
- const dates = (_b = sub[6]) == null ? void 0 : _b.split(`-`);
15594
- vtecs.push({
15595
- vtec: vtec2,
15596
- product: eventProducts[sub[0]],
15597
- tracking: `${sub[2]}.${sub[3]}.${sub[4]}.${sub[5]}`,
15598
- event: `${eventTypes[sub[3]]} ${eventActions[sub[4]]}`,
15599
- status: eventStatus[sub[1]],
15600
- organization: (_d = (_c = message.match(regExp.wmo)) == null ? void 0 : _c[0]) != null ? _d : null,
15601
- expires: getExpiry2(dates),
15602
- is_watch: (sub[4] == `A` || sub[4] == `Y`) && (sub[3] == `TO` || sub[3] == `SV`),
15603
- prediction_center: sub[2] == `KWNS` ? true : false
15604
- });
15011
+ // src/@modules/@eas/eas.setNoise.ts
15012
+ var setNoise = (int16, noiseLevel = 0.02) => {
15013
+ const x = getPCMToFloat(int16);
15014
+ for (let i = 0; i < x.length; i++) x[i] += (Math.random() * 2 - 1) * noiseLevel;
15015
+ let peak = 0;
15016
+ for (let i = 0; i < x.length; i++) peak = Math.max(peak, Math.abs(x[i]));
15017
+ if (peak > 1) for (let i = 0; i < x.length; i++) x[i] *= 0.98 / peak;
15018
+ return getFloatPCM16(x);
15019
+ };
15020
+
15021
+ // src/@modules/@eas/eas.getPCM16.ts
15022
+ var getPCM16 = (samples, sampleRate) => {
15023
+ let o = 0;
15024
+ const bytesPerSample = 2;
15025
+ const blockAlign = 1 * bytesPerSample;
15026
+ const byteRate = sampleRate * blockAlign;
15027
+ const subchunk2Size = samples.length * bytesPerSample;
15028
+ const chunkSize = 36 + subchunk2Size;
15029
+ const buffer = Buffer.alloc(44 + subchunk2Size);
15030
+ buffer.write("RIFF", o);
15031
+ o += 4;
15032
+ buffer.writeUInt32LE(chunkSize, o);
15033
+ o += 4;
15034
+ buffer.write("WAVE", o);
15035
+ o += 4;
15036
+ buffer.write("fmt ", o);
15037
+ o += 4;
15038
+ buffer.writeUInt32LE(16, o);
15039
+ o += 4;
15040
+ buffer.writeUInt16LE(1, o);
15041
+ o += 2;
15042
+ buffer.writeUInt16LE(1, o);
15043
+ o += 2;
15044
+ buffer.writeUInt32LE(sampleRate, o);
15045
+ o += 4;
15046
+ buffer.writeUInt32LE(byteRate, o);
15047
+ o += 4;
15048
+ buffer.writeUInt16LE(blockAlign, o);
15049
+ o += 2;
15050
+ buffer.writeUInt16LE(16, o);
15051
+ o += 2;
15052
+ buffer.write("data", o);
15053
+ o += 4;
15054
+ buffer.writeUInt32LE(subchunk2Size, o);
15055
+ o += 4;
15056
+ for (let i = 0; i < samples.length; i++, o += 2) {
15057
+ buffer.writeInt16LE(samples[i].value, o);
15058
+ }
15059
+ return buffer;
15060
+ };
15061
+
15062
+ // src/@modules/@eas/eas.getTTS.ts
15063
+ var import_os = require("os");
15064
+ var import_child_process = require("child_process");
15065
+ var getTTS = (text2, outputPath) => __async(null, null, function* () {
15066
+ const vPlatform = (0, import_os.platform)();
15067
+ switch (vPlatform) {
15068
+ case "win32": {
15069
+ const command = `Add-Type -AssemblyName System.Speech;$speak = New-Object System.Speech.Synthesis.SpeechSynthesizer;$speak.SetOutputToWaveFile('${outputPath}');$speak.Speak('${text2}');$speak.Dispose();`;
15070
+ (0, import_child_process.execSync)(`powershell -Command "${command}"`, { stdio: "ignore" });
15071
+ break;
15072
+ }
15073
+ case "linux":
15074
+ (0, import_child_process.execSync)(`espeak -w "${outputPath}" "${text2.replace(/"/g, '\\"')}"`);
15075
+ break;
15076
+ default:
15077
+ break;
15078
+ }
15079
+ });
15080
+
15081
+ // src/@modules/@eas/eas.getCleanDescription.ts
15082
+ var getCleanDescription = (message) => {
15083
+ const patches = [
15084
+ { regex: /\.{3,}/g, replacement: ". " },
15085
+ { regex: /\bUTC\b/g, replacement: "Coordinated Universal Time" },
15086
+ { regex: /\bGMT\b/g, replacement: "Greenwich Mean Time" },
15087
+ { regex: /\bEST\b(?!\w)/g, replacement: "Eastern Standard Time" },
15088
+ { regex: /\bEDT\b(?!\w)/g, replacement: "Eastern Daylight Time" },
15089
+ { regex: /\bCST\b(?!\w)/g, replacement: "Central Standard Time" },
15090
+ { regex: /\bCDT\b(?!\w)/g, replacement: "Central Daylight Time" },
15091
+ { regex: /\bMST\b(?!\w)/g, replacement: "Mountain Standard Time" },
15092
+ { regex: /\bMDT\b(?!\w)/g, replacement: "Mountain Daylight Time" },
15093
+ { regex: /\bPST\b(?!\w)/g, replacement: "Pacific Standard Time" },
15094
+ { regex: /\bPDT\b(?!\w)/g, replacement: "Pacific Daylight Time" },
15095
+ { regex: /\bAKST\b(?!\w)/g, replacement: "Alaska Standard Time" },
15096
+ { regex: /\bAKDT\b(?!\w)/g, replacement: "Alaska Daylight Time" },
15097
+ { regex: /\bHST\b(?!\w)/g, replacement: "Hawaii Standard Time" },
15098
+ { regex: /\bHDT\b(?!\w)/g, replacement: "Hawaii Daylight Time" },
15099
+ { regex: /\bmph\b(?!\w)/g, replacement: "miles per hour" },
15100
+ { regex: /\bkm\/h\b(?!\w)/g, replacement: "kilometers per hour" },
15101
+ { regex: /\bkmh\b(?!\w)/g, replacement: "kilometers per hour" },
15102
+ { regex: /\bkt\b(?!\w)/g, replacement: "knots" },
15103
+ { regex: /\bNE\b(?!\w)/g, replacement: "northeast" },
15104
+ { regex: /\bNW\b(?!\w)/g, replacement: "northwest" },
15105
+ { regex: /\bSE\b(?!\w)/g, replacement: "southeast" },
15106
+ { regex: /\bSW\b(?!\w)/g, replacement: "southwest" },
15107
+ { regex: /\bNM\b(?!\w)/g, replacement: "nautical miles" },
15108
+ { regex: /\bdeg\b(?!\w)/g, replacement: "degrees" },
15109
+ { regex: /\btstm\b(?!\w)/g, replacement: "thunderstorm" },
15110
+ { regex: /\bmm\b(?!\w)/g, replacement: "millimeters" },
15111
+ { regex: /\bcm\b(?!\w)/g, replacement: "centimeters" },
15112
+ { regex: /\bin.\b(?!\w)/g, replacement: "inches" },
15113
+ { regex: /\bft\b(?!\w)/g, replacement: "feet" },
15114
+ { regex: /\bmi\b(?!\w)/g, replacement: "miles" },
15115
+ { regex: /\bhr\b(?!\w)/g, replacement: "hour" },
15116
+ { regex: /\bhourly\b(?!\w)/g, replacement: "per hour" },
15117
+ { regex: /\bkg\b(?!\w)/g, replacement: "kilograms" },
15118
+ { regex: /\bg\/kg\b(?!\w)/g, replacement: "grams per kilogram" },
15119
+ { regex: /\bmb\b(?!\w)/g, replacement: "millibars" },
15120
+ { regex: /\bhPa\b(?!\w)/g, replacement: "hectopascals" },
15121
+ { regex: /\bPa\b(?!\w)/g, replacement: "pascals" },
15122
+ { regex: /\bKPa\b(?!\w)/g, replacement: "kilopascals" },
15123
+ { regex: /\bC\/hr\b(?!\w)/g, replacement: "degrees Celsius per hour" },
15124
+ { regex: /\bF\/hr\b(?!\w)/g, replacement: "degrees Fahrenheit per hour" },
15125
+ { regex: /\bC\/min\b(?!\w)/g, replacement: "degrees Celsius per minute" },
15126
+ { regex: /\bF\/min\b(?!\w)/g, replacement: "degrees Fahrenheit per minute" },
15127
+ { regex: /\bC\b(?!\w)/g, replacement: "degrees Celsius" },
15128
+ { regex: /\bF\b(?!\w)/g, replacement: "degrees Fahrenheit" }
15129
+ ];
15130
+ const hours = {
15131
+ 0: "twelve",
15132
+ 1: "one",
15133
+ 2: "two",
15134
+ 3: "three",
15135
+ 4: "four",
15136
+ 5: "five",
15137
+ 6: "six",
15138
+ 7: "seven",
15139
+ 8: "eight",
15140
+ 9: "nine",
15141
+ 10: "ten",
15142
+ 11: "eleven",
15143
+ 12: "twelve"
15144
+ };
15145
+ const minWord = (m) => m === 0 ? "o'clock" : m < 10 ? `oh ${m}` : `${m}`;
15146
+ const fmt = (h, m, ap) => `${hours[h % 12]} ${minWord(m)} ${ap}`;
15147
+ for (const { regex, replacement } of patches) {
15148
+ message = message.replace(regex, replacement);
15605
15149
  }
15606
- return vtecs.length > 0 ? vtecs : null;
15150
+ return message.replace(/\b(\d{1,2}):(\d{2})\s*(AM|PM)\b/gi, (_, h, m, ap) => fmt(+h, +m, ap.toUpperCase())).replace(/\b(\d{1,2})\s+(\d{2})\s+(AM|PM)\b/gi, (_, h, m, ap) => fmt(+h, +m, ap.toUpperCase())).replace(/\b(\d{2})(\d{2})\s+(AM|PM)\b/gi, (_, hh, mm, ap) => fmt(+hh, +mm, ap.toUpperCase())).replace(/\*+/g, " ").replace(/-/g, " ").replace(/\n/g, " ").trim();
15607
15151
  };
15608
15152
 
15609
- // src/@dictionaries/dictionaries.eventCauses.ts
15610
- var eventCauses = {
15611
- "SM": "Snow Melt",
15612
- "RS": "Rain/Snow Melt",
15613
- "ER": "Excessive Rain",
15614
- "DM": "Dam/Levee Failure",
15615
- "IJ": "Ice Jam",
15616
- "GO": "Glacier Lake Outburst",
15617
- "IC": "Ice",
15618
- "FS": "Flash Flood / Storm Surge",
15619
- "FT": "Tidal Effects",
15620
- "ET": "Elevated Upstream Flow",
15621
- "MC": "Other Multiple Causes",
15622
- "WT": "Wind and/or Tidal Effects",
15623
- "DR": "Reservoir Release",
15624
- "UU": "Unknown",
15625
- "OT": "Other Effects"
15626
- };
15153
+ // src/@modules/@eas/eas.setEasTone.ts
15154
+ var import_path2 = require("path");
15155
+ var import_fs = require("fs");
15156
+ var import_child_process2 = require("child_process");
15157
+ var import_os2 = require("os");
15158
+ var setEasTone = (options) => __async(null, null, function* () {
15159
+ const settings = bootstrap.settings;
15160
+ const directory = settings.GlobalSettings.EASSettings.ArchiveDirectory;
15161
+ const prefix = settings.GlobalSettings.EASSettings.IntroWavFile;
15162
+ let message = options.message;
15163
+ let header = options.header;
15164
+ if (!message || !header) {
15165
+ setWarning({
15166
+ title: `EAS`,
15167
+ message: `Message and header are required to generate an EAS tone.`
15168
+ });
15169
+ return null;
15170
+ }
15171
+ let buffTTS;
15172
+ let buffRadio;
15173
+ let buffFull = [];
15174
+ if (!(0, import_fs.existsSync)(directory)) {
15175
+ (0, import_fs.mkdirSync)(directory, { recursive: true });
15176
+ }
15177
+ if (!(0, import_fs.existsSync)((0, import_path2.join)(directory, `/temp`))) {
15178
+ (0, import_fs.mkdirSync)((0, import_path2.join)(directory, `/temp`), { recursive: true });
15179
+ }
15180
+ if (!(0, import_fs.existsSync)((0, import_path2.join)(directory, `/output`))) {
15181
+ (0, import_fs.mkdirSync)((0, import_path2.join)(directory, `/output`), { recursive: true });
15182
+ }
15183
+ const tmpTTS = (0, import_path2.join)(directory, `/temp/${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, "")}.wav`);
15184
+ const outTTS = (0, import_path2.join)(directory, `/output/${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, "")}.wav`);
15185
+ const vPlatform = (0, import_os2.platform)();
15186
+ if (vPlatform === "darwin") {
15187
+ setWarning({
15188
+ title: `EAS`,
15189
+ message: `EAS tone generation is not supported on macOS.`
15190
+ });
15191
+ return null;
15192
+ }
15193
+ yield new Promise((resolve6, reject) => {
15194
+ const tMsg = getCleanDescription(message);
15195
+ getTTS(tMsg, tmpTTS).then(() => {
15196
+ buffTTS = (0, import_fs.readFileSync)(tmpTTS);
15197
+ resolve6();
15198
+ });
15199
+ });
15200
+ const vWav = getWavPCM16(buffTTS);
15201
+ const vSamples = getSampledPCM16(vWav.samples, vWav.sampleRate, 8e3);
15202
+ const vRadio = setRadioEffect(vSamples, 8e3);
15203
+ if ((0, import_fs.existsSync)(prefix)) {
15204
+ let tBuffer = (0, import_fs.readFileSync)(prefix);
15205
+ let tWav = getWavPCM16(tBuffer);
15206
+ if (tWav == null) {
15207
+ try {
15208
+ const converted = (0, import_path2.join)(directory, `/temp/${Math.random().toString(36).substring(2, 15)}.converted.wav`);
15209
+ (0, import_child_process2.execSync)(`ffmpeg -y -i "${prefix}" -ar 8000 -ac 1 -sample_fmt s16 "${converted}"`, { stdio: "ignore" });
15210
+ if ((0, import_fs.existsSync)(converted)) {
15211
+ tBuffer = (0, import_fs.readFileSync)(converted);
15212
+ tWav = getWavPCM16(tBuffer);
15213
+ try {
15214
+ (0, import_fs.unlinkSync)(converted);
15215
+ } catch (e) {
15216
+ }
15217
+ }
15218
+ } catch (e) {
15219
+ }
15220
+ }
15221
+ if (tWav == null) {
15222
+ setWarning({ title: `EAS`, message: `Intro tone isn't a valid .WAV file or isn't in PCM 16-bit format. Converted attempt failed; please convert it then try again.` });
15223
+ return null;
15224
+ }
15225
+ const tSamples = tWav.sampleRate != 8e3 ? getSampledPCM16(tWav.samples, tWav.sampleRate, 8e3) : tWav.samples;
15226
+ buffRadio = setRadioEffect(tSamples, 8e3);
15227
+ }
15228
+ buffFull = buffRadio != null ? [buffRadio, new Int16Array(Math.floor(0.5 * 8e3))] : [];
15229
+ buffFull.push(
15230
+ setSameHeader(header, 3, 8e3, {
15231
+ preMarkSec: 1.1,
15232
+ gapSec: 0.5
15233
+ }),
15234
+ new Int16Array(Math.floor(0.5 * 8e3)),
15235
+ setAttentionTone(8, 8e3),
15236
+ new Int16Array(Math.floor(0.5 * 8e3)),
15237
+ vRadio
15238
+ );
15239
+ for (let i = 0; i < 3; i++) {
15240
+ buffFull.push(setSameHeader(header, 1, 8e3, { preMarkSec: 0.5, gapSec: 0.1 }));
15241
+ buffFull.push(new Int16Array(Math.floor(0.5 * 8e3)));
15242
+ }
15243
+ const aSamples = getMergedPCM16(buffFull);
15244
+ const aFinal = setNoise(aSamples, 2e-3);
15245
+ const aBuffer = getPCM16(Array.from(aFinal).map((v) => ({ value: v })), 8e3);
15246
+ (0, import_fs.writeFileSync)(outTTS, aBuffer);
15247
+ try {
15248
+ (0, import_fs.unlinkSync)(tmpTTS);
15249
+ } catch (e) {
15250
+ }
15251
+ return outTTS;
15252
+ });
15627
15253
 
15628
- // src/@dictionaries/dictionaries.eventRecords.ts
15629
- var eventRecords = {
15630
- "NO": "No Record Expected",
15631
- "NR": "Near Record or possible record",
15632
- "UU": "Unknown history of records",
15633
- "OO": "Other"
15634
- };
15254
+ // src/@manager/manager.createWebhook.ts
15255
+ var import_fs2 = require("fs");
15256
+ var import_form_data = __toESM(require_form_data());
15257
+ var createWebhook = (options) => __async(null, null, function* () {
15258
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
15259
+ const event = options.event.properties;
15260
+ const settings = options.webhook;
15261
+ const line = (label, value, condition = true) => condition && value ? `${label} ${value}` : null;
15262
+ const isLimited = setTimeoutAction({ identifier: options.webhook.webhook, interval: options.webhook.rate, max: options.webhook.rate, addTime: true });
15263
+ if (!isLimited.limited) {
15264
+ const isStatement = event.status_metadata.is_statement;
15265
+ const isExpired = event.status_metadata.is_expired;
15266
+ let body = [
15267
+ line(`**Locations:**`, (_a = event == null ? void 0 : event.locations) == null ? void 0 : _a.slice(0, 100)),
15268
+ line(`**Issued:**`, `<t:${Math.floor(new Date(event.issued).getTime() / 1e3)}:R>`),
15269
+ line(`**Expires:**`, `<t:${Math.floor(new Date(event.expires).getTime() / 1e3)}:R>`, !isExpired && !isStatement),
15270
+ line(`**Damage Threat:**`, event.parameters.damage_threat, !isExpired),
15271
+ line(`**Flood Threat:**`, event.parameters.flood_threat, !isExpired),
15272
+ line(`**Tornado Threat:**`, event.parameters.tornado_threat, !isExpired),
15273
+ line(`**Estimated Wind Gusts:**`, `${event.parameters.estimated_wind_gusts} ${event.parameters.wind_threat ? ` (${event.parameters.wind_threat})` : ""}`, !isExpired && event.parameters.estimated_wind_gusts != null),
15274
+ line(`**Estimated Hail Size:**`, `${event.parameters.estimated_hail_size} ${event.parameters.hail_threat ? ` (${event.parameters.hail_threat})` : ""}`, !isExpired && event.parameters.estimated_hail_size != null),
15275
+ line(`**Discussion:**`, event.spc_parameters.spc_number, !isExpired),
15276
+ line(`**Concern:**`, event.spc_parameters.spc_concerning, !isExpired),
15277
+ line(`**SPC Max Tornado Threat:**`, event.spc_parameters.spc_max_tornado, !isExpired),
15278
+ line(`**SPC Max Hail Threat:**`, event.spc_parameters.spc_max_hail, !isExpired),
15279
+ line(`**SPC Max Wind Threat:**`, event.spc_parameters.spc_max_wind, !isExpired),
15280
+ line(`**SPC Watch Issuance Probability:**`, event.spc_parameters.spc_watch_issuance ? `${event.spc_parameters.spc_watch_issuance}%` : null, !isExpired),
15281
+ line(`**Watch Number:**`, event.watch_parameters.watch_number, !isExpired),
15282
+ line(`**Strong Tornadoes Probability:**`, event.watch_parameters.strong_tornadoes_probability ? `${event.watch_parameters.strong_tornadoes_probability}%` : null, !isExpired),
15283
+ line(`**Additional Tornadoes Probability:**`, event.watch_parameters.additional_tornadoes_probability ? `${event.watch_parameters.additional_tornadoes_probability}%` : null, !isExpired),
15284
+ line(`**Combined Hail/Wind Probability:**`, event.watch_parameters.combined_hail_wind_probability ? `${event.watch_parameters.combined_hail_wind_probability}%` : null, !isExpired),
15285
+ line(`**Severe Hail Probability:**`, event.watch_parameters.severe_hail_probability ? `${event.watch_parameters.severe_hail_probability}%` : null, !isExpired),
15286
+ line(`**Hail >2in Probability:**`, event.watch_parameters.hail_2in_probability ? `${event.watch_parameters.hail_2in_probability}%` : null, !isExpired),
15287
+ line(`**Max Hail Inches:**`, event.watch_parameters.max_hail_in, !isExpired),
15288
+ line(`**Severe Wind Probability:**`, event.watch_parameters.severe_wind_probability ? `${event.watch_parameters.severe_wind_probability}%` : null, !isExpired),
15289
+ line(`**Max Surface Wind:**`, event.watch_parameters.max_wind_surface, !isExpired),
15290
+ line(`**Max Tops (x100 feet):**`, event.watch_parameters.max_tops_x100feet, !isExpired),
15291
+ line(`**Tags:**`, ((_b = event.parameters.tags) == null ? void 0 : _b.length) > 0 ? event.parameters.tags.join(", ") : null, !isExpired),
15292
+ line(`**Sender:**`, ((_d = (_c = event.geocode) == null ? void 0 : _c.office) == null ? void 0 : _d.name) ? `${event.geocode.office.name} (${event.geocode.office.office})` : (_f = (_e = event.geocode) == null ? void 0 : _e.office) == null ? void 0 : _f.office),
15293
+ line(`**Tracking:**`, (_g = event.metadata) == null ? void 0 : _g.tracking),
15294
+ line(`**Logs:**`, ((_h = event.metadata.history) == null ? void 0 : _h.length) > 0 ? event.metadata.history.length : null),
15295
+ line(``, event.description ? "```\n" + event.description.split("\n").map((l) => l.trim()).filter(Boolean).join("\n") + "\n```" : null, !isExpired)
15296
+ ].filter(Boolean).join("\n");
15297
+ if (body.length > 1900) {
15298
+ body = body.substring(0, 1900) + "\n\n[Message truncated due to length]";
15299
+ const blocks = ((_i = body.match(/```/g)) != null ? _i : []).length;
15300
+ if (blocks % 2 !== 0) body += "```";
15301
+ }
15302
+ if (event.description.length < 25) {
15303
+ return;
15304
+ }
15305
+ const form = new import_form_data.default();
15306
+ const img = (_j = event.metadata.attachments) == null ? void 0 : _j[0];
15307
+ const embed = {
15308
+ title: `${event.event} (${event.status})`,
15309
+ description: body,
15310
+ color: 16711680,
15311
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
15312
+ image: {},
15313
+ footer: { text: settings.title }
15314
+ };
15315
+ if (img) {
15316
+ for (let i = 0; i < 5; i++) {
15317
+ const ok = yield isImageReady(img);
15318
+ if (ok) break;
15319
+ yield new Promise((r) => setTimeout(r, 5e3));
15320
+ }
15321
+ const finalCheck = yield isImageReady(img);
15322
+ if (finalCheck) {
15323
+ embed.image = { url: img };
15324
+ }
15325
+ }
15326
+ form.append("payload_json", JSON.stringify({
15327
+ username: (_k = settings.title) != null ? _k : "AtmosphericX",
15328
+ content: (_l = settings.message) != null ? _l : "",
15329
+ embeds: [embed]
15330
+ }));
15331
+ if (settings.upload) {
15332
+ form.append("fUpload", Buffer.from(`${event.metadata.raw}
15635
15333
 
15636
- // src/@dictionaries/dictionaries.eventSeverity.ts
15637
- var eventSeverity = {
15638
- N: "Not Expected",
15639
- 0: "Areal Flood or FF Product",
15640
- 1: "Minor",
15641
- 2: "Moderate",
15642
- 3: "Major",
15643
- U: "Unknown"
15644
- };
15334
+ ${JSON.stringify(getCleanedEvent(event), null, 2)}`), { filename: `${event.event}_${event.status}_${event.metadata.tracking}.txt`, contentType: "application/text" });
15335
+ }
15336
+ if (settings.eas) {
15337
+ const audio = yield setEasTone({
15338
+ message: event.description,
15339
+ header: event.metadata.header
15340
+ });
15341
+ const file = (0, import_fs2.readFileSync)(audio);
15342
+ if (audio) {
15343
+ form.append("fEas", Buffer.from(file), { filename: `${event.event}_${event.status}_${event.metadata.tracking}_eas.mp3`, contentType: "audio/mpeg" });
15344
+ }
15345
+ }
15346
+ yield createHttp({
15347
+ url: settings.webhook,
15348
+ timeout: 2e3,
15349
+ method: `POST`,
15350
+ headers: form.getHeaders(),
15351
+ body: form
15352
+ });
15353
+ }
15354
+ });
15645
15355
 
15646
- // src/@parsers/@hvtec/hvtec.extract.ts
15647
- var hvExtract = (message) => {
15648
- var _a;
15649
- const getHVTECs = (_a = message.match(regExp.hvtec)) != null ? _a : [];
15650
- const vtecs = [];
15651
- for (const vtec2 of getHVTECs) {
15652
- const sub = vtec2.split(`.`);
15653
- if (sub.length < 7) continue;
15654
- vtecs.push({
15655
- hvtec: vtec2,
15656
- severity: eventSeverity[sub[1]],
15657
- cause: eventCauses[sub[2]],
15658
- record: eventRecords[sub[6]]
15356
+ // src/@manager/manager.updateWebhooks.ts
15357
+ var updateWebhooks = (event) => __async(null, null, function* () {
15358
+ const settings = bootstrap.settings;
15359
+ const webhooks = settings.WebhookSettings;
15360
+ const eventName = event.properties.event;
15361
+ for (const socket of webhooks) {
15362
+ const events = socket.events;
15363
+ if (!events || events.length === 0) {
15364
+ yield createWebhook({ webhook: socket, event });
15365
+ continue;
15366
+ }
15367
+ const matched = events.some((pattern) => {
15368
+ if (!pattern) return false;
15369
+ if (pattern === "*" || pattern === eventName) return true;
15370
+ if (pattern.includes("*")) {
15371
+ const regex = "^" + pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$";
15372
+ return new RegExp(regex).test(eventName);
15373
+ }
15374
+ return false;
15659
15375
  });
15376
+ if (matched) {
15377
+ yield createWebhook({ webhook: socket, event });
15378
+ }
15660
15379
  }
15661
- return vtecs.length > 0 ? vtecs : null;
15662
- };
15380
+ });
15663
15381
 
15664
- // src/@events/events.vtec.ts
15665
- var vtec = (stanza) => __async(null, null, function* () {
15666
- var _a, _b, _c, _d, _e;
15667
- let processed = [];
15668
- const getMessages = (_c = (_b = (_a = stanza == null ? void 0 : stanza.message) == null ? void 0 : _a.split(/(?=\$\$)/g)) == null ? void 0 : _b.map((message) => message.trim())) == null ? void 0 : _c.filter((message) => message && message !== "$$");
15669
- if (!getMessages || (getMessages == null ? void 0 : getMessages.length) == 0) return;
15670
- for (const message of getMessages) {
15671
- const tick = performance.now();
15672
- const attributes = stanza == null ? void 0 : stanza.attributes;
15673
- const pVtec = pvExtract(message);
15674
- const hVtec = hvExtract(message);
15675
- const ugc2 = yield ugcExtract(message);
15676
- if (pVtec != null && ugc2 != null) {
15677
- for (const pv of pVtec) {
15678
- const vtec2 = pv;
15679
- const props = properties({ message, attributes, ugc: ugc2, pVtec: vtec2 });
15680
- const header = getEventHeader({ properties: props, getType: stanza.getType, vtec: vtec2 });
15681
- const issued = (_d = new Date(attributes.issue)) != null ? _d : /* @__PURE__ */ new Date();
15682
- const expires = new Date(vtec2.expires);
15683
- processed.push({
15684
- type: `Feature`,
15685
- geometry: {
15686
- type: `Point`,
15687
- coordinates: []
15688
- },
15689
- properties: __spreadProps(__spreadValues({
15690
- event: pv.event,
15691
- parent: pv.event,
15692
- status: pv.status,
15693
- issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15694
- expires: !isNaN(expires.getTime()) ? expires.toISOString() : (_e = ugc2.expires) != null ? _e : new Date(issued.getTime() + 60 * 60 * 1e3).toISOString()
15695
- }, props), {
15696
- metadata: {
15697
- ms: performance.now() - tick,
15698
- source: `events.vtec`,
15699
- tracking: getEventTracking({ type: `VTEC`, stanza, attributes, properties: props, vtec: vtec2 }),
15700
- header,
15701
- vtec: pv,
15702
- hvtec: hVtec,
15703
- history: [
15704
- {
15705
- description: props.description,
15706
- issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15707
- status: pv.status
15708
- }
15709
- ]
15710
- }
15711
- })
15712
- });
15382
+ // src/@modules/@utilities/utilities.getShapeNearestPoint.ts
15383
+ var getShapeNearestPoint = (coordinates, point) => {
15384
+ if (!coordinates || !point) {
15385
+ return { proximity: false, point: [0, 0], distance: null };
15386
+ }
15387
+ const normalize = (coords) => {
15388
+ if (!Array.isArray(coords)) return [];
15389
+ if (typeof coords[0] === "number" && typeof coords[1] === "number") return [];
15390
+ if (Array.isArray(coords[0]) && typeof coords[0][0] === "number") {
15391
+ return [[coords]];
15392
+ }
15393
+ if (Array.isArray(coords[0]) && Array.isArray(coords[0][0]) && typeof coords[0][0][0] === "number") {
15394
+ return [coords];
15395
+ }
15396
+ if (Array.isArray(coords[0]) && Array.isArray(coords[0][0]) && Array.isArray(coords[0][0][0]) && typeof coords[0][0][0][0] === "number") {
15397
+ return coords;
15398
+ }
15399
+ return [];
15400
+ };
15401
+ const polys = normalize(coordinates);
15402
+ if (polys.length === 0) return { proximity: false, point: [0, 0], distance: null };
15403
+ const lon = point[0];
15404
+ const lat = point[1];
15405
+ const pointInRing = (pt, ring) => {
15406
+ let x = pt[0], y = pt[1];
15407
+ let inside = false;
15408
+ for (let i = 0, j2 = ring.length - 1; i < ring.length; j2 = i++) {
15409
+ const xi = ring[i][0], yi = ring[i][1];
15410
+ const xj = ring[j2][0], yj = ring[j2][1];
15411
+ const intersect = yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi + 0) + xi;
15412
+ if (intersect) inside = !inside;
15413
+ }
15414
+ return inside;
15415
+ };
15416
+ const toRadians = (deg) => deg * Math.PI / 180;
15417
+ const haversineMiles = (a, b) => {
15418
+ const R = 3958.8;
15419
+ const dLat = toRadians(b[1] - a[1]);
15420
+ const dLon = toRadians(b[0] - a[0]);
15421
+ const lat1 = toRadians(a[1]);
15422
+ const lat2 = toRadians(b[1]);
15423
+ const sinDLat = Math.sin(dLat / 2);
15424
+ const sinDLon = Math.sin(dLon / 2);
15425
+ const c = 2 * Math.asin(Math.sqrt(sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon));
15426
+ return R * c;
15427
+ };
15428
+ let minDistance = Infinity;
15429
+ let closestPoint = null;
15430
+ for (const poly of polys) {
15431
+ const outer = poly[0];
15432
+ const holes = poly.slice(1);
15433
+ if (pointInRing(point, outer)) {
15434
+ let inHole = false;
15435
+ for (const hole of holes) {
15436
+ if (pointInRing(point, hole)) {
15437
+ inHole = true;
15438
+ break;
15439
+ }
15440
+ }
15441
+ if (!inHole) {
15442
+ return { proximity: true, point, distance: 0 };
15443
+ }
15444
+ }
15445
+ for (const ring of poly) {
15446
+ for (let i = 0; i < ring.length - 1; i++) {
15447
+ const start = [ring[i][0], ring[i][1]];
15448
+ const end = [ring[i + 1][0], ring[i + 1][1]];
15449
+ const A = lon - start[0];
15450
+ const B = lat - start[1];
15451
+ const C = end[0] - start[0];
15452
+ const D = end[1] - start[1];
15453
+ const lenSq = C * C + D * D;
15454
+ const t = lenSq === 0 ? 0 : Math.max(0, Math.min(1, (A * C + B * D) / lenSq));
15455
+ const candidate = [start[0] + t * C, start[1] + t * D];
15456
+ const dist = haversineMiles([lon, lat], candidate);
15457
+ if (!isNaN(dist) && dist < minDistance) {
15458
+ minDistance = Number(dist.toFixed(3));
15459
+ closestPoint = candidate;
15460
+ }
15713
15461
  }
15714
15462
  }
15715
15463
  }
15716
- validateEvents(processed);
15464
+ if (!isFinite(minDistance) || closestPoint == null) {
15465
+ return { proximity: false, point: [0, 0], distance: null };
15466
+ }
15467
+ const distanceMiles = minDistance;
15468
+ const distanceKm = Number((distanceMiles * 1.609344).toFixed(3));
15469
+ const distanceMeters = Math.round(distanceKm * 1e3);
15470
+ return { proximity: distanceMiles === 0, point: closestPoint, distance: distanceMiles, distanceKm, distanceMeters };
15471
+ };
15472
+
15473
+ // src/@building/building.polygon.ts
15474
+ var getEventNodes = (event) => __async(null, null, function* () {
15475
+ var _a, _b;
15476
+ const metadata = { nodes: [], proximity: false, filtered: false };
15477
+ const geometry = yield getEventGeometry(event);
15478
+ if (!geometry || !geometry.coordinates) {
15479
+ return { nodes: [], filtered: false, updated: Date.now() };
15480
+ }
15481
+ const nodes = bootstrap.cache.nodes.features;
15482
+ for (const node of nodes) {
15483
+ const [longitude, latitude] = node.geometry.coordinates;
15484
+ const getPoint = getShapeNearestPoint(geometry.coordinates, [longitude, latitude]);
15485
+ const miles = (_a = getPoint.distance) != null ? _a : null;
15486
+ const kilometers = Number((miles * 1.609344).toFixed(3));
15487
+ const info = {
15488
+ id: (_b = node.properties) == null ? void 0 : _b.identifier,
15489
+ coordinates: [longitude, latitude],
15490
+ nearest: getPoint.point,
15491
+ miles,
15492
+ kilometers,
15493
+ proximity: getPoint.proximity
15494
+ };
15495
+ metadata.nodes.push(info);
15496
+ if (bootstrap.settings.GlobalSettings.EventFiltering.NodeLocationFiltering && miles < bootstrap.settings.GlobalSettings.NodeMinDistance) {
15497
+ metadata.proximity = true;
15498
+ info.proximity = true;
15499
+ }
15500
+ }
15501
+ return {
15502
+ nodes: metadata.nodes,
15503
+ filtered: metadata.proximity,
15504
+ updated: Date.now()
15505
+ };
15717
15506
  });
15718
15507
 
15719
- // src/@events/events.api.ts
15720
- var api = (stanza) => __async(null, null, function* () {
15721
- 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, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab, _bb;
15722
- let processed = [];
15723
- const messages = Object.values(JSON.parse(stanza.message).features);
15724
- for (const feature of messages) {
15725
- const tick = performance.now();
15726
- const pVtec = (_d = (_c = (_b = (_a = feature == null ? void 0 : feature.properties) == null ? void 0 : _a.parameters) == null ? void 0 : _b.VTEC) == null ? void 0 : _c[0]) != null ? _d : null;
15727
- processed.push({
15728
- type: `Feature`,
15729
- geometry: {
15730
- type: `Point`,
15731
- coordinates: []
15732
- },
15733
- properties: {
15734
- event: (_f = (_e = feature == null ? void 0 : feature.properties) == null ? void 0 : _e.event) != null ? _f : null,
15735
- parent: (_h = (_g = feature == null ? void 0 : feature.properties) == null ? void 0 : _g.event) != null ? _h : null,
15736
- status: (_j = (_i = feature == null ? void 0 : feature.properties) == null ? void 0 : _i.messageType) != null ? _j : null,
15737
- issued: ((_k = feature == null ? void 0 : feature.properties) == null ? void 0 : _k.sent) ? new Date((_l = feature == null ? void 0 : feature.properties) == null ? void 0 : _l.sent).toISOString() : null,
15738
- expires: ((_m = feature == null ? void 0 : feature.properties) == null ? void 0 : _m.expires) ? new Date((_n = feature == null ? void 0 : feature.properties) == null ? void 0 : _n.expires).toISOString() : null,
15739
- locations: (_p = (_o = feature == null ? void 0 : feature.properties) == null ? void 0 : _o.areaDesc) != null ? _p : null,
15740
- description: (_r = (_q = feature == null ? void 0 : feature.properties) == null ? void 0 : _q.description) != null ? _r : null,
15741
- attributes: (_t = (_s = feature == null ? void 0 : feature.properties) == null ? void 0 : _s.attributes) != null ? _t : {},
15742
- geocode: {
15743
- office: {
15744
- office: pVtec ? pVtec.split(`.`)[2] : null,
15745
- name: (_u = officeICAOs[pVtec ? pVtec.split(`.`)[2] : null]) != null ? _u : null
15746
- },
15747
- organization: (_x = (_w = (_v = feature == null ? void 0 : feature.properties) == null ? void 0 : _v.parameters) == null ? void 0 : _w.WMOidentifier) == null ? void 0 : _x[0],
15748
- ugc: (_A = (_z = (_y = feature == null ? void 0 : feature.properties) == null ? void 0 : _y.geocode) == null ? void 0 : _z.UGC) != null ? _A : [],
15749
- polygon: ((_B = feature == null ? void 0 : feature.geometry) == null ? void 0 : _B.coordinates.length) > 0 ? Buffer.from(JSON.stringify([(_C = feature == null ? void 0 : feature.geometry) == null ? void 0 : _C.coordinates[0]])).toString("base64") : null,
15750
- polygon_generated: ((_D = feature == null ? void 0 : feature.geometry) == null ? void 0 : _D.coordinates.length) > 0 ? true : false
15751
- },
15752
- parameters: {
15753
- tags: getEventTags((_E = feature == null ? void 0 : feature.properties) == null ? void 0 : _E.description),
15754
- instructions: (_G = (_F = feature == null ? void 0 : feature.properties) == null ? void 0 : _F.instruction) != null ? _G : null,
15755
- source: (_I = getTextFromProduct({ message: (_H = feature == null ? void 0 : feature.properties) == null ? void 0 : _H.description, find: [`SOURCE...`], removal: [`.`] })) != null ? _I : null,
15756
- hazards: (_K = getTextFromProduct({ message: (_J = feature == null ? void 0 : feature.properties) == null ? void 0 : _J.description, find: [`HAZARD...`], removal: [`.`] })) != null ? _K : null,
15757
- impacts: (_M = getTextFromProduct({ message: (_L = feature == null ? void 0 : feature.properties) == null ? void 0 : _L.description, find: [`IMPACT...`], removal: [`.`] })) != null ? _M : null,
15758
- estimated_hail_size: (_Q = (_P = (_O = (_N = feature == null ? void 0 : feature.properties) == null ? void 0 : _N.parameters) == null ? void 0 : _O.maxHailSize) == null ? void 0 : _P[0]) != null ? _Q : null,
15759
- estimated_wind_gusts: (_U = (_T = (_S = (_R = feature == null ? void 0 : feature.properties) == null ? void 0 : _R.parameters) == null ? void 0 : _S.maxWindGust) == null ? void 0 : _T[0]) != null ? _U : null,
15760
- damage_threat: (_Y = (_X = (_W = (_V = feature == null ? void 0 : feature.properties) == null ? void 0 : _V.parameters) == null ? void 0 : _W.thunderstormDamageThreat) == null ? void 0 : _X[0]) != null ? _Y : null,
15761
- tornado_threat: (_aa = (_$ = (__ = (_Z = feature == null ? void 0 : feature.properties) == null ? void 0 : _Z.parameters) == null ? void 0 : __.tornadoDetection) == null ? void 0 : _$[0]) != null ? _aa : null,
15762
- flood_threat: (_ea = (_da = (_ca = (_ba = feature == null ? void 0 : feature.properties) == null ? void 0 : _ba.parameters) == null ? void 0 : _ca.floodDetection) == null ? void 0 : _da[0]) != null ? _ea : null,
15763
- wind_threat: (_ia = (_ha = (_ga = (_fa = feature == null ? void 0 : feature.properties) == null ? void 0 : _fa.parameters) == null ? void 0 : _ga.windThreat) == null ? void 0 : _ha[0]) != null ? _ia : null,
15764
- hail_threat: (_ma = (_la = (_ka = (_ja = feature == null ? void 0 : feature.properties) == null ? void 0 : _ja.parameters) == null ? void 0 : _ka.hailThreat) == null ? void 0 : _la[0]) != null ? _ma : null
15765
- },
15766
- spc_parameters: {
15767
- spc_max_tornado: (_oa = getTextFromProduct({ message: (_na = feature == null ? void 0 : feature.properties) == null ? void 0 : _na.description, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] })) != null ? _oa : null,
15768
- spc_max_hail: (_qa = getTextFromProduct({ message: (_pa = feature == null ? void 0 : feature.properties) == null ? void 0 : _pa.description, find: [`MOST PROBABLE PEAK HAIL SIZE...`] })) != null ? _qa : null,
15769
- spc_max_wind: (_sa = getTextFromProduct({ message: (_ra = feature == null ? void 0 : feature.properties) == null ? void 0 : _ra.description, find: [`MOST PROBABLE PEAK WIND GUST...`] })) != null ? _sa : null,
15770
- spc_watch_issuance: (_ua = getTextFromProduct({ message: (_ta = feature == null ? void 0 : feature.properties) == null ? void 0 : _ta.description, find: [`Probability of Watch Issuance...`], removal: [`percent`] })) != null ? _ua : null
15771
- },
15772
- watch_parameters: {
15773
- watch_number: (_ya = (_xa = (_wa = getTextFromProduct({ message: (_va = feature == null ? void 0 : feature.properties) == null ? void 0 : _va.description, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })) == null ? void 0 : _wa.replace(/(WT|WS|)/g, "")) == null ? void 0 : _xa.trim()) != null ? _ya : null,
15774
- watch_type: ((_za = feature == null ? void 0 : feature.properties) == null ? void 0 : _za.description.includes(`TORNADO WATCH`)) ? `Tornado` : ((_Aa = feature == null ? void 0 : feature.properties) == null ? void 0 : _Aa.description.includes(`SEVERE`)) ? `Severe` : null,
15775
- additional_tornadoes_probability: (_Ca = getTextFromProduct({ message: (_Ba = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ba.description, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _Ca : null,
15776
- strong_tornadoes_probability: (_Ea = getTextFromProduct({ message: (_Da = feature == null ? void 0 : feature.properties) == null ? void 0 : _Da.description, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _Ea : null,
15777
- severe_wind_probability: (_Ga = getTextFromProduct({ message: (_Fa = feature == null ? void 0 : feature.properties) == null ? void 0 : _Fa.description, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _Ga : null,
15778
- severe_hail_probability: (_Ia = getTextFromProduct({ message: (_Ha = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ha.description, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _Ia : null,
15779
- hail_2in_probability: (_Ka = getTextFromProduct({ message: (_Ja = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ja.description, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] })) != null ? _Ka : null,
15780
- combined_hail_wind_probability: (_Ma = getTextFromProduct({ message: (_La = feature == null ? void 0 : feature.properties) == null ? void 0 : _La.description, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _Ma : null,
15781
- max_hail_in: (_Oa = getTextFromProduct({ message: (_Na = feature == null ? void 0 : feature.properties) == null ? void 0 : _Na.description, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] })) != null ? _Oa : null,
15782
- max_wind_surface: (_Qa = getTextFromProduct({ message: (_Pa = feature == null ? void 0 : feature.properties) == null ? void 0 : _Pa.description, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] })) != null ? _Qa : null,
15783
- max_tops_x100feet: (_Sa = getTextFromProduct({ message: (_Ra = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ra.description, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] })) != null ? _Sa : null,
15784
- pds_watch: getTextFromProduct({ message: (_Ta = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ta.description, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`
15785
- },
15786
- metadata: {
15787
- ms: performance.now() - tick,
15788
- source: `events.api`,
15789
- tracking: getEventTracking({ type: `API`, organization: { wmoidentifier: (_Wa = (_Va = (_Ua = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ua.parameters) == null ? void 0 : _Va.WMOidentifier) == null ? void 0 : _Wa[0], featureId: feature == null ? void 0 : feature.id }, vtec: pVtec }),
15790
- header: `ZCZC-ATMOSX-${(_Ya = (_Xa = feature == null ? void 0 : feature.properties) == null ? void 0 : _Xa.parameters) == null ? void 0 : _Ya.WMOidentifier}`,
15791
- vtec: pVtec,
15792
- hvtec: null,
15793
- history: [
15794
- {
15795
- description: (_Za = feature == null ? void 0 : feature.properties) == null ? void 0 : _Za.description,
15796
- issued: ((__a = feature == null ? void 0 : feature.properties) == null ? void 0 : __a.sent) ? new Date((_$a = feature == null ? void 0 : feature.properties) == null ? void 0 : _$a.sent).toISOString() : null,
15797
- status: (_bb = (_ab = feature == null ? void 0 : feature.properties) == null ? void 0 : _ab.messageType) != null ? _bb : null
15798
- }
15799
- ]
15800
- }
15508
+ // src/@manager/manager.updateNodes.ts
15509
+ var updateNode = (selectedEvent) => __async(null, null, function* () {
15510
+ const events = bootstrap.cache.events.features;
15511
+ const ttl = bootstrap.settings.GlobalSettings.NodeTTL * 1e3;
15512
+ let total = 0;
15513
+ function update(evt) {
15514
+ return __async(this, null, function* () {
15515
+ var _a, _b, _c;
15516
+ const lastUpdate = (_c = (_b = (_a = evt == null ? void 0 : evt.properties) == null ? void 0 : _a.metadata) == null ? void 0 : _b.updated) != null ? _c : null;
15517
+ if (lastUpdate != null && Date.now() - lastUpdate < ttl) {
15518
+ return evt;
15519
+ }
15520
+ const node = yield getEventNodes(evt);
15521
+ if (node.nodes.length > 0) {
15522
+ total++;
15523
+ }
15524
+ evt.properties.metadata.nodes = node.nodes;
15525
+ evt.properties.metadata.filtered_proximity = node.filtered;
15526
+ evt.properties.metadata.updated = node.updated;
15527
+ });
15528
+ }
15529
+ if (!selectedEvent) {
15530
+ yield Promise.all(events.map((evt) => __async(null, null, function* () {
15531
+ yield update(evt);
15532
+ })));
15533
+ }
15534
+ if (selectedEvent) {
15535
+ yield update(selectedEvent);
15536
+ }
15537
+ if (total > 0) {
15538
+ setEventEmit({
15539
+ event: `onNodeUpdate`,
15540
+ metadata: {
15541
+ type: `global-update`,
15542
+ updated: total
15801
15543
  }
15802
15544
  });
15803
15545
  }
15804
- validateEvents(processed);
15805
- });
15806
-
15807
- // src/@building/building.create.ts
15808
- var createEvent = (stanza) => __async(null, null, function* () {
15809
- const settings = bootstrap.settings;
15810
- const StanzaSettings = settings.NOAAWeatherWireServiceSettings.StanzaSettings;
15811
- const isVtecEvent = stanza.isVTEC && stanza.isUGC;
15812
- const isUgcEvent = !stanza.isVTEC && stanza.isUGC;
15813
- const isTextEvent = !stanza.isVTEC && !stanza.isUGC;
15814
- const isNWWS = stanza.isNWWS;
15815
- if (!isNWWS) return yield api(stanza);
15816
- if (!StanzaSettings.DisableVTEC && isVtecEvent) return yield vtec(stanza);
15817
- if (!StanzaSettings.DisableUGC && isUgcEvent) return yield ugc(stanza);
15818
- if (!StanzaSettings.DisableText && isTextEvent) return yield text(stanza);
15819
- return "nothing picked";
15820
15546
  });
15821
15547
 
15822
- // src/@modules/@database/database.stanza.ts
15823
- var importStanza = (stanza) => __async(null, null, function* () {
15548
+ // src/@manager/manager.mkEvent.ts
15549
+ var mkEvent = (event) => __async(null, null, function* () {
15550
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w;
15824
15551
  const settings = bootstrap.settings;
15825
- try {
15826
- if (!settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
15827
- return;
15828
- }
15829
- bootstrap.database.prepare(`INSERT OR IGNORE INTO stanzas (type, stanza, issued) VALUES (?, ?, ?)`).run(stanza.getType.type, JSON.stringify(stanza), stanza.attributes.issue);
15830
- const count = bootstrap.database.prepare(`SELECT COUNT(*) as total FROM stanzas`).get();
15831
- const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxDatabaseHistory;
15832
- if (count.total > max) {
15833
- const toDelete = count.total - max;
15834
- if (toDelete > 0) {
15835
- bootstrap.database.prepare(`DELETE FROM stanzas WHERE id IN (SELECT id FROM stanzas ORDER BY issued ASC LIMIT ?)`).run(toDelete);
15552
+ const features = bootstrap.cache.events.features;
15553
+ const getHash = event.properties.metadata.hash;
15554
+ const getTracking = event.properties.metadata.tracking;
15555
+ const isEntry = (_a = bootstrap.cache.hashes) == null ? void 0 : _a.find((hash) => hash.tracking === getTracking);
15556
+ const isHashed = (_c = (_b = isEntry == null ? void 0 : isEntry.hashes) == null ? void 0 : _b.includes(getHash)) != null ? _c : false;
15557
+ const getFeature = features.find((feature) => feature.properties.metadata.tracking === getTracking);
15558
+ if (isHashed || event.properties.status_metadata.is_expired) return;
15559
+ setHash(event, isEntry);
15560
+ const isFilteredLocation = yield updateNode(event).then(() => event.properties.metadata.filtered_proximity);
15561
+ if (!isFilteredLocation && settings.GlobalSettings.EventFiltering.NodeLocationFiltering) {
15562
+ return;
15563
+ }
15564
+ setEventEmit({
15565
+ event: `onEventStatus`,
15566
+ metadata: {
15567
+ type: getFeature ? `Updated` : `New`,
15568
+ event
15569
+ },
15570
+ message: `[${getFeature ? "Updated" : "New"}] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
15571
+ });
15572
+ if (settings.GlobalSettings.EventManagement) {
15573
+ if (event.properties.status_metadata.is_issued || event.properties.status_metadata.is_updated) {
15574
+ if (getFeature) {
15575
+ const getIndex = features.indexOf(getFeature);
15576
+ const cHistory = (_f = (_e = (_d = getFeature == null ? void 0 : getFeature.properties) == null ? void 0 : _d.metadata) == null ? void 0 : _e.history) != null ? _f : [];
15577
+ 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 : [];
15578
+ const cUgc = (_l = (_k = (_j = getFeature == null ? void 0 : getFeature.properties) == null ? void 0 : _j.geocode) == null ? void 0 : _k.ugc) != null ? _l : [];
15579
+ const iHistory = (_o = (_n = (_m = event.properties) == null ? void 0 : _m.metadata) == null ? void 0 : _n.history) != null ? _o : [];
15580
+ const iLocations = (_r = (_q = (_p = event.properties) == null ? void 0 : _p.locations) == null ? void 0 : _q.split(";").map((l) => l.trim())) != null ? _r : [];
15581
+ const iUgc = (_u = (_t = (_s = event.properties) == null ? void 0 : _s.geocode) == null ? void 0 : _t.ugc) != null ? _u : [];
15582
+ 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);
15583
+ const mLocations = [...cLocations, ...iLocations].filter((v, i, a) => a.indexOf(v) === i).join("; ");
15584
+ const mUgc = [...cUgc, ...iUgc].filter((v, i, a) => a.indexOf(v) === i);
15585
+ bootstrap.cache.events.features[getIndex] = __spreadProps(__spreadValues({}, event), {
15586
+ properties: __spreadProps(__spreadValues({}, event.properties), {
15587
+ metadata: __spreadProps(__spreadValues({}, (_v = event == null ? void 0 : event.properties) == null ? void 0 : _v.metadata), {
15588
+ history: mHistory
15589
+ }),
15590
+ locations: mLocations,
15591
+ geocode: __spreadProps(__spreadValues({}, (_w = event == null ? void 0 : event.properties) == null ? void 0 : _w.geocode), {
15592
+ ugc: mUgc
15593
+ })
15594
+ })
15595
+ });
15596
+ updateWebhooks(bootstrap.cache.events.features[getIndex]);
15597
+ } else {
15598
+ features.push(event);
15599
+ updateWebhooks(event);
15836
15600
  }
15837
15601
  }
15838
- } catch (error) {
15839
- setWarning({ message: `An error occurred while importing stanza: ${error.message}` });
15840
15602
  }
15841
15603
  });
15842
15604
 
15843
- // src/@modules/@xmpp/xmpp.xStanza.ts
15844
- var xStanza = () => {
15845
- bootstrap.session_xmpp.on(`stanza`, (stanza) => __async(null, null, function* () {
15605
+ // src/@manager/manager.rmEvent.ts
15606
+ var rmEvent = (event) => {
15607
+ const getEvent = bootstrap.cache.events.features.find((f) => {
15846
15608
  var _a, _b, _c, _d;
15847
- const msgFrom = (_b = (_a = stanza == null ? void 0 : stanza.attrs) == null ? void 0 : _a.from) != null ? _b : ``;
15848
- const msgType = (_d = (_c = stanza == null ? void 0 : stanza.attrs) == null ? void 0 : _c.type) != null ? _d : ``;
15849
- setEventEmit({
15850
- event: `onServiceStatus`,
15851
- metadata: {
15852
- message: stanza,
15853
- from: msgFrom,
15854
- type: `stanza`
15855
- }
15856
- });
15857
- bootstrap.cache.lastStanza = Date.now();
15858
- if (stanza.is(`message`)) {
15859
- const result = validate({ stanza });
15860
- const isSkippable = result.isIgnored || result.isCapEvent || result.isCapEvent && !result.isCapAreaDescription;
15861
- if (isSkippable) {
15862
- return;
15863
- }
15864
- yield createEvent(result);
15865
- yield importStanza(result);
15866
- }
15867
- if (stanza.is(`presence`) && msgFrom.startsWith("nwws@conference.nwws-oi.weather.gov/")) {
15868
- const getOccupant = msgFrom.split(`/`).slice(1).join(`/`);
15869
- const getAvailability = msgType === `unavailable`;
15870
- setEventEmit({
15871
- event: `onServiceStatus`,
15872
- metadata: {
15873
- message: `Occupant ${getOccupant} has ${getAvailability ? `left` : `joined`} the room`,
15874
- data: {},
15875
- type: `occupant`,
15876
- error: false
15877
- }
15878
- });
15879
- }
15880
- }));
15881
- };
15882
-
15883
- // src/@modules/@xmpp/xmpp.xDeploy.ts
15884
- var xDeploy = () => __async(null, null, function* () {
15885
- var _a, _b;
15886
- let session;
15887
- const settings = bootstrap.settings;
15888
- (_b = (_a = settings.NOAAWeatherWireServiceSettings.CredentialSettings).Nickname) != null ? _b : _a.Nickname = settings.NOAAWeatherWireServiceSettings.CredentialSettings.Username;
15889
- session = bootstrap.session_xmpp = client({
15890
- service: "xmpp://nwws-oi.weather.gov",
15891
- domain: "nwws-oi.weather.gov",
15892
- username: settings.NOAAWeatherWireServiceSettings.CredentialSettings.Username,
15893
- password: settings.NOAAWeatherWireServiceSettings.CredentialSettings.Password
15609
+ 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);
15894
15610
  });
15895
- try {
15896
- yield xOffline();
15897
- yield xError();
15898
- yield xStanza();
15899
- yield xOnline();
15900
- yield session.start();
15901
- } catch (error) {
15611
+ const cachedStatus = event.properties.status;
15612
+ event.properties.expires = (/* @__PURE__ */ new Date()).toISOString();
15613
+ event.properties.status = `Expired`;
15614
+ if (getEvent) {
15902
15615
  setEventEmit({
15903
- event: `onServiceStatus`,
15616
+ event: `onEventStatus`,
15904
15617
  metadata: {
15905
- message: `Error occured while starting XMPP Session: ${error}`,
15906
- data: {},
15907
- type: `error`,
15908
- error: true
15909
- }
15618
+ type: `Removed`,
15619
+ event
15620
+ },
15621
+ message: `[Removed] ${event.properties.event} (${event.properties.status}) (${event.properties.metadata.tracking})`
15910
15622
  });
15623
+ setEventEmit({ event: `onExpiredProduct`, metadata: event });
15624
+ if (cachedStatus != `Statement`) updateWebhooks(event);
15625
+ bootstrap.cache.events.features.splice(bootstrap.cache.events.features.indexOf(getEvent), 1);
15626
+ bootstrap.cache.hashes = bootstrap.cache.hashes.filter((hash) => hash.tracking !== event.properties.metadata.tracking);
15911
15627
  }
15912
- });
15913
-
15914
- // src/@modules/@database/database.init.ts
15915
- var import_fs2 = __toESM(require("fs"));
15916
- var import_better_sqlite3 = __toESM(require("better-sqlite3"));
15917
-
15918
- // src/@modules/@database/database.shapefiles.ts
15919
- var import_fs = __toESM(require("fs"));
15920
- var import_path2 = require("path");
15921
- var import_jszip = require("jszip");
15922
- var import_shapefile = require("shapefile");
15923
-
15924
- // src/@modules/@utilities/utilities.setSleep.ts
15925
- var setSleep = (options) => __async(null, null, function* () {
15926
- return new Promise((resolve6) => {
15927
- setTimeout(() => {
15928
- resolve6();
15929
- }, options.timeout);
15628
+ setEventEmit({
15629
+ event: `onEventCache`,
15630
+ metadata: bootstrap.cache.events,
15631
+ limited: true
15930
15632
  });
15931
- });
15932
-
15933
- // src/@dictionaries/dictionaries.shapefileLinks.ts
15934
- var shapefileLinks = [
15935
- { name: "us_counties", id: "C", link: "https://www.weather.gov/source/gis/Shapefiles/County/c_16ap26.zip" },
15936
- { name: "us_states_territories", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/County/s_16ap26.zip" },
15937
- { name: "fire_weather_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/fz16ap26.zip" },
15938
- { name: "costal_marine_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/mz16ap26.zip" },
15939
- { name: "offshore_marine_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/oz16ap26.zip" },
15940
- { name: "public_forecast_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/z_16ap26.zip" },
15941
- { name: "county_warning_areas", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/w_16ap26.zip" },
15942
- { name: "river_forecast_boundaries", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/Misc/rf05mr24.zip" },
15943
- { name: "high_seas_marine_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/hz17fe26.zip" }
15944
- ];
15633
+ };
15945
15634
 
15946
- // src/@modules/@database/database.shapefiles.ts
15947
- var importShapefiles = () => __async(null, null, function* () {
15948
- var _a, _b;
15949
- const settings = bootstrap.settings;
15950
- try {
15951
- const tShapefiles = bootstrap.database.prepare(`SELECT COUNT(*) AS count FROM shapefiles`).get().count;
15952
- if (tShapefiles === 0) {
15953
- yield setSleep({ timeout: 1e3 });
15954
- setWarning({ message: `Shapefiles are currently building, please DO NOT close your terminal. The shapefiles will not finish and will remain incomplete. If you do mess up, you will need to delete ${settings.Database} and restart the application.` });
15955
- for (const shapefile of shapefileLinks) {
15956
- const response2 = yield fetch(shapefile.link);
15957
- const arrayBuff = yield response2.arrayBuffer();
15958
- const content = yield (0, import_jszip.loadAsync)(arrayBuff);
15959
- const directory = (0, import_path2.resolve)(__dirname, `../../shapefiles`);
15960
- if (!import_fs.default.existsSync(directory)) {
15961
- import_fs.default.mkdirSync(directory, { recursive: true });
15962
- }
15963
- for (const file of Object.keys(content.files)) {
15964
- if (file.endsWith(".shp") || file.endsWith(".dbf")) {
15965
- const data = yield content.files[file].async(`nodebuffer`);
15966
- const output = (0, import_path2.resolve)(directory, `${(_a = shapefile == null ? void 0 : shapefile.name) != null ? _a : ``}_${(_b = shapefile == null ? void 0 : shapefile.id) != null ? _b : ``}${(0, import_path2.extname)(file)}`);
15967
- import_fs.default.writeFileSync(output, data);
15968
- }
15969
- }
15970
- const filepath = (0, import_path2.resolve)(__dirname, "../../shapefiles", shapefile.name + "_" + shapefile.id);
15971
- const { features } = yield (0, import_shapefile.read)(
15972
- filepath,
15973
- filepath
15974
- );
15975
- setWarning({ message: `Importing ${features.length} features from ${shapefile.name}_${shapefile.id}` });
15976
- const insert = bootstrap.database.prepare(`INSERT OR REPLACE INTO shapefiles (id, location, geometry) VALUES (?, ?, ?)`);
15977
- const transaction = bootstrap.database.transaction((entries) => {
15978
- var _a2, _b2, _c;
15979
- for (const entry of entries) {
15980
- const { properties: properties2, geometry } = entry;
15981
- let final2, location;
15982
- if (properties2.FIPS) {
15983
- final2 = `${properties2.STATE}${shapefile.id}${properties2.FIPS.substring(2)}`;
15984
- location = `${properties2.COUNTYNAME}, ${properties2.STATE}`;
15985
- } else if (properties2.FULLSTAID) {
15986
- final2 = `${properties2.ST}${shapefile.id}${properties2.WFO}`;
15987
- location = `${properties2.CITY}, ${properties2.STATE}`;
15988
- } else if (properties2.STATE) {
15989
- final2 = `${properties2.STATE}${shapefile.id}${(_a2 = properties2.ZONE) != null ? _a2 : properties2.SITE_ID}`;
15990
- location = `${(_b2 = properties2.NAME) != null ? _b2 : `${properties2.RFC_NAME} ${properties2.RFC_CITY}`}, ${properties2.STATE}`;
15991
- } else {
15992
- final2 = (_c = properties2.ID) != null ? _c : properties2.WFO;
15993
- location = properties2.NAME;
15994
- }
15995
- insert.run(final2, location, JSON.stringify(geometry));
15996
- }
15997
- });
15998
- import_fs.default.unlinkSync(`${filepath}.shp`);
15999
- import_fs.default.unlinkSync(`${filepath}.dbf`);
16000
- setWarning({ message: `Cleaned up temporary files for ${shapefile.name}_${shapefile.id}` });
16001
- transaction(features);
16002
- }
16003
- setWarning({ message: `Shapefiles have finished compiling, you can now continue and close this terminal` });
16004
- import_fs.default.rm((0, import_path2.resolve)(__dirname, "../../shapefiles"), { recursive: true, force: true }, () => {
16005
- });
15635
+ // src/@modules/@utilities/utilities.getLatestIssuance.ts
15636
+ var getLatestIssuance = () => {
15637
+ const now = /* @__PURE__ */ new Date();
15638
+ const current = now.getUTCHours() * 100 + now.getUTCMinutes();
15639
+ const issuances = [100, 600, 1300, 1630, 2e3];
15640
+ let latest = issuances[0];
15641
+ for (const issuance of issuances) {
15642
+ if (current >= issuance) {
15643
+ latest = issuance;
16006
15644
  }
16007
- } catch (error) {
16008
- setWarning({ message: `An error occurred while compiling shapefiles: ${error.message}` });
16009
15645
  }
16010
- });
15646
+ return latest.toString().padStart(4, "0");
15647
+ };
16011
15648
 
16012
- // src/@modules/@database/database.init.ts
16013
- var initializeDatabase = () => __async(null, null, function* () {
16014
- const settings = bootstrap.settings;
16015
- try {
16016
- if (!import_fs2.default.existsSync(settings.Database)) {
16017
- import_fs2.default.writeFileSync(settings.Database, "");
16018
- setWarning({ message: `Creating new database at ${settings.Database}` });
16019
- }
16020
- bootstrap.database = new import_better_sqlite3.default(settings.Database);
16021
- bootstrap.database.prepare(`CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )`).run();
16022
- bootstrap.database.prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`).run();
16023
- yield importShapefiles();
16024
- } catch (error) {
16025
- setWarning({ message: `An error occurred while initializing the database: ${error.message}` });
15649
+ // src/@building/building.outlooks.ts
15650
+ var getEventAttachments = (event) => {
15651
+ var _a, _b;
15652
+ const latestTime = getLatestIssuance();
15653
+ const validEvents = [
15654
+ { target: "Day 1", attachment: `https://www.spc.noaa.gov/products/outlook/day1otlk_${latestTime}.png` },
15655
+ { target: "Day 2", attachment: `https://www.spc.noaa.gov/products/outlook/day2otlk.png` },
15656
+ { target: "Day 3", attachment: `https://www.spc.noaa.gov/products/outlook/day3otlk.png` },
15657
+ { target: "Mesoscale Discussion", attachment: `https://www.spc.noaa.gov/products/md/mcd${(_b = (_a = event == null ? void 0 : event.properties) == null ? void 0 : _a.spc_parameters) == null ? void 0 : _b.spc_number}.png` }
15658
+ ];
15659
+ const isValid = validEvents.find((outlook) => outlook.target == event.properties.event);
15660
+ if (isValid) {
15661
+ return (isValid == null ? void 0 : isValid.attachment) ? [isValid.attachment] : [];
16026
15662
  }
16027
- });
15663
+ return null;
15664
+ };
16028
15665
 
16029
- // src/@modules/@database/database.cache.ts
16030
- var getCachedEvents = () => __async(null, null, function* () {
15666
+ // src/@building/building.validate.ts
15667
+ var validateEvents = (events) => __async(null, null, function* () {
16031
15668
  var _a;
16032
- try {
16033
- const settings = bootstrap.settings;
16034
- const tick = performance.now();
16035
- if (settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
16036
- const max = (_a = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxRetentionHistory) != null ? _a : 500;
16037
- const get = yield bootstrap.database.prepare(`SELECT * FROM stanzas ORDER BY rowid DESC LIMIT ?`).all(max);
16038
- setWarning({ message: `Fetched ${get.length} cached events from the database in ${Math.floor(performance.now() - tick)} ms` });
16039
- let events = get.map((row) => JSON.parse(row.stanza)).filter((stanza) => {
16040
- if (!stanza) {
16041
- return;
16042
- }
16043
- const isSkippable = stanza.isIgnored || stanza.isCapEvent || stanza.isCapEvent && !stanza.isCapAreaDescription;
16044
- return !isSkippable;
16045
- });
16046
- events = events.sort((a, b) => b.issued - a.issued);
16047
- yield Promise.all(events.map((event) => createEvent(event)));
16048
- setWarning({ message: `Processed ${events.length} cached events in ${Math.floor(performance.now() - tick)} ms` });
15669
+ if (events.length === 0) return;
15670
+ const configurations = bootstrap.settings;
15671
+ const sets = {};
15672
+ const bools = {};
15673
+ const megered = __spreadValues(__spreadValues({}, configurations.GlobalSettings), configurations.GlobalSettings.EventFiltering);
15674
+ for (const key in megered) {
15675
+ const setting = megered[key];
15676
+ if (Array.isArray(setting)) {
15677
+ sets[key] = new Set(setting.map((item) => item.toLowerCase()));
15678
+ }
15679
+ if (typeof setting === "boolean") {
15680
+ bools[key] = setting;
15681
+ }
15682
+ }
15683
+ const filterd = events.filter((event) => {
15684
+ var _a2, _b, _c, _d, _e;
15685
+ const define2 = getEventSignature(event);
15686
+ const properties2 = define2.properties;
15687
+ const zones = properties2.geocode.ugc;
15688
+ const icao = properties2.geocode.office.office;
15689
+ const enhancedEventName = properties2.event = getEventEnhancedName(event);
15690
+ const filteredProperties = JSON.parse(JSON.stringify(properties2));
15691
+ if ((filteredProperties == null ? void 0 : filteredProperties.metadata) && "ms" in filteredProperties.metadata) {
15692
+ delete filteredProperties.metadata.ms;
15693
+ }
15694
+ filteredProperties.metadata = (_a2 = filteredProperties.metadata) != null ? _a2 : {};
15695
+ properties2.metadata.hash = (0, import_crypto.createHash)("sha256").update(JSON.stringify(filteredProperties)).digest("hex");
15696
+ properties2.metadata.attachments = getEventAttachments(event);
15697
+ setEventEmit({ event: `onProductType${enhancedEventName.replace(/\s+/g, "")}`, metadata: define2 });
15698
+ if (properties2.status_metadata.is_test) {
15699
+ setEventEmit({ event: `onTestProduct`, metadata: define2 });
15700
+ if (bools == null ? void 0 : bools.IgnoreTestProducts) return false;
15701
+ }
15702
+ if (properties2.status_metadata.is_expired) {
15703
+ setEventEmit({ event: `onExpiredProduct`, metadata: define2 });
15704
+ rmEvent(define2);
15705
+ return false;
15706
+ }
15707
+ if ((_c = (_b = properties2.metadata) == null ? void 0 : _b.vtec) == null ? void 0 : _c.is_watch) {
15708
+ const isSPC = (_e = (_d = properties2.metadata) == null ? void 0 : _d.vtec) == null ? void 0 : _e.prediction_center;
15709
+ setEventEmit({ event: isSPC ? `onStormPredictionWatch` : `onNonStormPredictionWatch`, metadata: define2 });
15710
+ if ((bools == null ? void 0 : bools.SPCWatchesOnly) && !isSPC) {
15711
+ return false;
15712
+ }
15713
+ if (!(bools == null ? void 0 : bools.SPCWatchesOnly) && isSPC) {
15714
+ return false;
15715
+ }
16049
15716
  }
16050
- } catch (error) {
16051
- setWarning({ message: `An error occurred while fetching cached events: ${error.message} -> ${error.stack}` });
16052
- }
16053
- });
16054
-
16055
- // src/@modules/@xmpp/xmpp.xReconnect.ts
16056
- var xReconnect = (interval) => __async(null, null, function* () {
16057
- const settings = bootstrap.settings;
16058
- const lastStanza = Date.now() - bootstrap.cache.lastStanza;
16059
- if (interval < 15) {
16060
- setWarning({ message: `Reconnection interval of ${interval} seconds is too low, setting to 15 seconds` });
16061
- interval = 15;
16062
- bootstrap.settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.ReconnectionInterval = 15;
16063
- }
16064
- const reconnectThreshold = interval * 1e3;
16065
- if (!bootstrap.cache.isConnected && !bootstrap.cache.sigHault || !bootstrap.session_xmpp) {
16066
- return;
16067
- }
16068
- if (lastStanza > reconnectThreshold) {
16069
- if (!bootstrap.cache.isReconnecting) {
16070
- bootstrap.cache.isReconnecting = true;
16071
- bootstrap.cache.isConnected = false;
16072
- bootstrap.cache.tReconnects += 1;
16073
- try {
15717
+ for (const key in sets) {
15718
+ const setting = sets[key];
15719
+ if (key === "ListeningEvents" && setting.size > 0 && !setting.has(define2.properties.event.toLowerCase())) {
16074
15720
  setEventEmit({
16075
- event: `onServiceStatus`,
16076
- metadata: {
16077
- message: `Attempting to reconnect to XMPP Service (Reconnect Attempt ${bootstrap.cache.tReconnects})`,
16078
- data: {
16079
- last_stanza: lastStanza,
16080
- nickname: settings.NOAAWeatherWireServiceSettings.CredentialSettings.Nickname
16081
- },
16082
- type: `reconnect`,
16083
- error: true
16084
- }
15721
+ event: `onFilteredEvent`,
15722
+ metadata: define2
16085
15723
  });
16086
- yield bootstrap.session_xmpp.stop().catch(() => {
15724
+ return false;
15725
+ }
15726
+ if (key === "IgnoredEvents" && setting.size > 0 && setting.has(define2.properties.event.toLowerCase())) {
15727
+ setEventEmit({
15728
+ event: `onIgnoredEvent`,
15729
+ metadata: define2
16087
15730
  });
16088
- yield bootstrap.session_xmpp.start().catch(() => {
15731
+ return false;
15732
+ }
15733
+ if (key === "ListeningICAO" && setting.size > 0 && icao != null && !setting.has(icao.toLowerCase())) {
15734
+ setEventEmit({
15735
+ event: `onFilteredICAO`,
15736
+ metadata: define2
16089
15737
  });
16090
- } catch (error) {
16091
- setWarning({ message: `XMPP Reconnect Failed - ${error.message}` });
16092
- } finally {
16093
- bootstrap.cache.isReconnecting = false;
15738
+ return false;
15739
+ }
15740
+ if (key === "IgnoredICAO" && setting.size > 0 && icao != null && setting.has(icao.toLowerCase())) {
15741
+ setEventEmit({
15742
+ event: `onIgnoredICAO`,
15743
+ metadata: define2
15744
+ });
15745
+ return false;
15746
+ }
15747
+ if (key === "ListeningUGC" && setting.size > 0 && zones.length > 0 && !zones.some((ugc2) => setting.has(ugc2.toLowerCase()))) {
15748
+ setEventEmit({
15749
+ event: `onFilteredUGC`,
15750
+ metadata: define2
15751
+ });
15752
+ return false;
15753
+ }
15754
+ if (key === "ListeningStates" && setting.size > 0 && zones.length > 0 && !zones.some((ugc2) => setting.has(ugc2.substring(0, 2).toLowerCase()))) {
15755
+ setEventEmit({
15756
+ event: `onFilteredState`,
15757
+ metadata: define2
15758
+ });
15759
+ return false;
16094
15760
  }
16095
15761
  }
15762
+ return true;
15763
+ });
15764
+ if (!((_a = configurations == null ? void 0 : configurations.GlobalSettings) == null ? void 0 : _a.DisableGeometryParsing)) {
15765
+ for (const event of filterd) {
15766
+ event.geometry = yield getEventGeometry(event);
15767
+ }
15768
+ }
15769
+ if (filterd.length > 0) {
15770
+ for (const event of filterd) {
15771
+ yield mkEvent(event);
15772
+ }
16096
15773
  }
15774
+ yield updateNode();
15775
+ setEventEmit({
15776
+ event: `onEventCache`,
15777
+ metadata: bootstrap.cache.events,
15778
+ limited: true
15779
+ });
16097
15780
  });
16098
15781
 
16099
- // src/@modules/@utilities/utilities.setCronSchedule.ts
16100
- var setCronSchedule = () => __async(null, null, function* () {
16101
- const settings = bootstrap.settings;
16102
- if (settings.EnableWireService) {
16103
- if (settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.Enabled) {
16104
- void xReconnect(settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.ReconnectionInterval);
15782
+ // src/@events/events.text.ts
15783
+ var text = (stanza) => __async(null, null, function* () {
15784
+ var _a, _b, _c;
15785
+ let processed = [];
15786
+ const getMessages = (_c = (_b = (_a = stanza == null ? void 0 : stanza.message) == null ? void 0 : _a.split(/(?=\$\$)/g)) == null ? void 0 : _b.map((message) => message.trim())) == null ? void 0 : _c.filter((message) => message && message !== "$$");
15787
+ if (!getMessages || (getMessages == null ? void 0 : getMessages.length) == 0) return;
15788
+ for (const message of getMessages) {
15789
+ const tick = performance.now();
15790
+ const attributes = stanza == null ? void 0 : stanza.attributes;
15791
+ const props = properties({ message, attributes });
15792
+ const header = getEventHeader({ properties: props, getType: stanza.getType });
15793
+ const issued = new Date(attributes.issue);
15794
+ const expires = new Date(issued.getTime() + 12 * 60 * 60 * 1e3);
15795
+ let event = Object.keys(eventsMatchText).find((event2) => message.toLowerCase().includes(event2.toLowerCase()));
15796
+ let isStatement = false;
15797
+ if (!event) {
15798
+ event = stanza.getType.type.split(`-`).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(` `);
15799
+ isStatement = true;
16105
15800
  }
16106
- } else {
16107
- const response2 = yield createHttp({
16108
- url: settings.NationalWeatherServiceSettings.EventsEndpoint,
16109
- headers: {
16110
- "User-Agent": "@atmosx/event-product-parser"
16111
- }
16112
- });
16113
- if (response2.error) {
16114
- return setEventEmit({
16115
- event: `onServiceStatus`,
15801
+ processed.push({
15802
+ type: `Feature`,
15803
+ geometry: {
15804
+ type: `Point`,
15805
+ coordinates: []
15806
+ },
15807
+ properties: __spreadProps(__spreadValues({
15808
+ event,
15809
+ parent: event,
15810
+ status: isStatement ? `Statement` : `Issued`,
15811
+ issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15812
+ expires: isStatement ? new Date(issued.getTime() + 120 * 1e3).toISOString() : !isNaN(expires.getTime()) ? expires.toISOString() : new Date(Date.now() + 60 * 60 * 1e3).toISOString()
15813
+ }, props), {
16116
15814
  metadata: {
16117
- type: "fetch-api",
16118
- message: `Failed to fetch latest events from National Weather Service API - ${response2.message}`,
16119
- data: {},
16120
- error: true
15815
+ ms: performance.now() - tick,
15816
+ source: `events.text`,
15817
+ tracking: getEventTracking({ type: `RAW`, stanza, attributes, properties: props }),
15818
+ header,
15819
+ vtec: null,
15820
+ hvtec: null,
15821
+ raw: message,
15822
+ history: [
15823
+ {
15824
+ description: props.description,
15825
+ issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15826
+ status: `Issued`
15827
+ }
15828
+ ]
16121
15829
  }
16122
- });
16123
- }
16124
- setEventEmit({
16125
- event: `onServiceStatus`,
16126
- metadata: {
16127
- message: `Fetched latest events from National Weather Service API`,
16128
- data: {},
16129
- type: "fetch-api",
16130
- error: false
16131
- }
15830
+ })
16132
15831
  });
16133
- createEvent({ message: response2.message, isNWWS: false });
16134
15832
  }
15833
+ validateEvents(processed);
16135
15834
  });
16136
15835
 
16137
- // src/@manager/manager.updateEvents.ts
16138
- var updateEvents = (selectedEvent) => __async(null, null, function* () {
16139
- const events = bootstrap.cache.events.features;
16140
- function update(evt) {
16141
- return __async(this, null, function* () {
16142
- if (new Date(evt.properties.expires) < /* @__PURE__ */ new Date()) {
16143
- rmEvent(evt);
15836
+ // src/@parsers/@ugc/ugc.header.ts
15837
+ var getUGCHeader = (message) => {
15838
+ const start = message.search(regExp.ugc1);
15839
+ const sub = message.substring(start);
15840
+ const end = sub.search(regExp.ugc2);
15841
+ const fin = sub.substring(0, end).replace(/\s+/g, "").slice(0, -1);
15842
+ return fin != null ? fin : null;
15843
+ };
15844
+
15845
+ // src/@parsers/@ugc/ugc.zones.ts
15846
+ var getZones = (header) => {
15847
+ const splits = header.split("-");
15848
+ const zones = [];
15849
+ let state = splits[0].substring(0, 2);
15850
+ const format = splits[0].substring(2, 3);
15851
+ for (const part of splits) {
15852
+ if (/^[A-Z]/.test(part)) {
15853
+ state = part.substring(0, 2);
15854
+ if (part.includes(">")) {
15855
+ const [start, end] = part.split(">");
15856
+ const startNum = parseInt(start.substring(3), 10);
15857
+ const endNum = parseInt(end, 10);
15858
+ for (let j2 = startNum; j2 <= endNum; j2++) {
15859
+ zones.push(`${state}${format}${j2.toString().padStart(3, "0")}`);
15860
+ }
15861
+ } else {
15862
+ zones.push(part);
16144
15863
  }
16145
- });
16146
- }
16147
- if (!selectedEvent) {
16148
- yield Promise.all(events.map((evt) => __async(null, null, function* () {
16149
- yield update(evt);
16150
- })));
16151
- }
16152
- if (selectedEvent) {
16153
- yield update(selectedEvent);
15864
+ continue;
15865
+ }
15866
+ if (part.includes(">")) {
15867
+ const [start, end] = part.split(">");
15868
+ const startNum = parseInt(start, 10);
15869
+ const endNum = parseInt(end, 10);
15870
+ for (let j2 = startNum; j2 <= endNum; j2++) {
15871
+ zones.push(`${state}${format}${j2.toString().padStart(3, "0")}`);
15872
+ }
15873
+ } else {
15874
+ zones.push(`${state}${format}${part}`);
15875
+ }
16154
15876
  }
16155
- });
15877
+ return zones.filter((item) => item !== "");
15878
+ };
16156
15879
 
16157
- // src/@core/core.start.ts
16158
- var import_croner = require("croner");
16159
- var startService = (configurations) => __async(null, null, function* () {
16160
- if (!bootstrap.isReady) {
16161
- return setWarning({
16162
- message: `You can not create another instance without shutting down the current one first, please make sure to call the stop() method first!`
16163
- });
16164
- }
16165
- const settings = setSettings(configurations);
16166
- bootstrap.isReady = true;
16167
- yield initializeDatabase();
16168
- if (settings.EnableWireService) {
16169
- (() => __async(null, null, function* () {
16170
- yield getCachedEvents();
16171
- yield xDeploy();
16172
- }))();
16173
- }
16174
- yield setCronSchedule();
16175
- let scheduleInterval = !settings.EnableWireService ? settings.NationalWeatherServiceSettings.CallbackInterval : 1;
16176
- if (!settings.EnableWireService && scheduleInterval < 15) {
16177
- setWarning({ message: `Schedule interval of ${scheduleInterval} seconds is too low, setting to 15 seconds` });
16178
- bootstrap.settings.NationalWeatherServiceSettings.CallbackInterval = 15;
16179
- scheduleInterval = 15;
15880
+ // src/@parsers/@ugc/ugc.expiry.ts
15881
+ var getExpiry = (message) => {
15882
+ const match = message.match(/\b(\d{6})-/);
15883
+ if (!match) {
15884
+ return null;
16180
15885
  }
16181
- bootstrap.cron = new import_croner.Cron(`*/${scheduleInterval} * * * * *`, () => __async(null, null, function* () {
16182
- yield setCronSchedule();
16183
- }));
16184
- bootstrap.cron = new import_croner.Cron(`* * * * * *`, () => __async(null, null, function* () {
16185
- yield updateNode();
16186
- yield updateEvents();
16187
- }));
15886
+ const date = match == null ? void 0 : match[1];
15887
+ const day = parseInt(date == null ? void 0 : date.slice(0, 2), 10);
15888
+ const hour = parseInt(date == null ? void 0 : date.slice(2, 4), 10);
15889
+ const minute = parseInt(date == null ? void 0 : date.slice(4, 6), 10);
15890
+ const now = /* @__PURE__ */ new Date();
15891
+ const expires = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), day, hour, minute));
15892
+ return expires.toISOString();
15893
+ };
15894
+
15895
+ // src/@parsers/@ugc/ugc.locations.ts
15896
+ var getLocations = (zones) => __async(null, null, function* () {
15897
+ const sites = Array.from(new Set(zones));
15898
+ const placeholders = sites.map(() => "?").join(",");
15899
+ const rows = yield bootstrap.database.prepare(`SELECT id, location FROM shapefiles WHERE id IN (${placeholders})`).all(...sites);
15900
+ return rows.map((row) => row.location).sort();
16188
15901
  });
16189
15902
 
16190
- // src/@core/core.stop.ts
16191
- var stopService = () => __async(null, null, function* () {
16192
- if (bootstrap.isReady) {
16193
- bootstrap.isReady = false;
16194
- if (bootstrap.session_xmpp) {
16195
- try {
16196
- yield bootstrap.session_xmpp.stop();
16197
- } catch (e) {
15903
+ // src/@parsers/@ugc/ugc.extract.ts
15904
+ var ugcExtract = (message) => __async(null, null, function* () {
15905
+ const head = getUGCHeader(message);
15906
+ const ugcs = getZones(head);
15907
+ const expires = getExpiry(message);
15908
+ const areas = yield getLocations(ugcs);
15909
+ if (!head || (ugcs == null ? void 0 : ugcs.length) == 0) return;
15910
+ return {
15911
+ zones: ugcs,
15912
+ locations: areas,
15913
+ expires
15914
+ };
15915
+ });
15916
+
15917
+ // src/@events/events.ugc.ts
15918
+ var ugc = (stanza) => __async(null, null, function* () {
15919
+ var _a, _b, _c;
15920
+ let processed = [];
15921
+ const getMessages = (_c = (_b = (_a = stanza == null ? void 0 : stanza.message) == null ? void 0 : _a.split(/(?=\$\$)/g)) == null ? void 0 : _b.map((message) => message.trim())) == null ? void 0 : _c.filter((message) => message && message !== "$$");
15922
+ if (!getMessages || (getMessages == null ? void 0 : getMessages.length) == 0) return;
15923
+ for (const message of getMessages) {
15924
+ const tick = performance.now();
15925
+ const attributes = stanza == null ? void 0 : stanza.attributes;
15926
+ const ugc2 = yield ugcExtract(message);
15927
+ if (ugc2 != null) {
15928
+ const props = properties({ message, attributes, ugc: ugc2 });
15929
+ const issued = new Date(attributes.issue);
15930
+ const expires = new Date(ugc2.expires);
15931
+ const header = getEventHeader({ properties: props, getType: stanza.getType });
15932
+ let event = Object.keys(eventsMatchText).find((event2) => message.toLowerCase().includes(event2.toLowerCase()));
15933
+ let isStatement = false;
15934
+ if (!event) {
15935
+ event = stanza.getType.type.split(`-`).map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(` `);
15936
+ isStatement = true;
16198
15937
  }
16199
- bootstrap.cache.isConnected = false;
16200
- bootstrap.cache.sigHault = true;
16201
- bootstrap.session_xmpp = null;
15938
+ processed.push({
15939
+ type: `Feature`,
15940
+ geometry: {
15941
+ type: `Point`,
15942
+ coordinates: []
15943
+ },
15944
+ properties: __spreadProps(__spreadValues({
15945
+ event,
15946
+ parent: event,
15947
+ status: isStatement ? `Statement` : `Issued`,
15948
+ issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15949
+ expires: isStatement ? new Date(issued.getTime() + 120 * 1e3).toISOString() : !isNaN(expires.getTime()) ? expires.toISOString() : new Date(Date.now() + 60 * 60 * 1e3).toISOString()
15950
+ }, props), {
15951
+ metadata: {
15952
+ ms: performance.now() - tick,
15953
+ source: `events.ugc`,
15954
+ tracking: getEventTracking({ type: `RAW`, stanza, attributes, properties: props }),
15955
+ header,
15956
+ vtec: null,
15957
+ hvtec: null,
15958
+ raw: message,
15959
+ history: [
15960
+ {
15961
+ description: props.description,
15962
+ issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
15963
+ status: `Issued`
15964
+ }
15965
+ ]
15966
+ }
15967
+ })
15968
+ });
16202
15969
  }
16203
15970
  }
15971
+ validateEvents(processed);
16204
15972
  });
16205
15973
 
16206
- // src/@dictionaries/dictionaries.transcribedMessageReplacements.ts
16207
- var transcribedMessageReplacements = [
16208
- { regex: /\*/g, replacement: "" },
16209
- { regex: /\.{3,}/g, replacement: "" },
16210
- { regex: /\bUTC\b/g, replacement: "Coordinated Universal Time" },
16211
- { regex: /\bGMT\b/g, replacement: "Greenwich Mean Time" },
16212
- { regex: /\bEST\b(?!\w)/g, replacement: "Eastern Standard Time" },
16213
- { regex: /\bEDT\b(?!\w)/g, replacement: "Eastern Daylight Time" },
16214
- { regex: /\bCST\b(?!\w)/g, replacement: "Central Standard Time" },
16215
- { regex: /\bCDT\b(?!\w)/g, replacement: "Central Daylight Time" },
16216
- { regex: /\bMST\b(?!\w)/g, replacement: "Mountain Standard Time" },
16217
- { regex: /\bMDT\b(?!\w)/g, replacement: "Mountain Daylight Time" },
16218
- { regex: /\bPST\b(?!\w)/g, replacement: "Pacific Standard Time" },
16219
- { regex: /\bPDT\b(?!\w)/g, replacement: "Pacific Daylight Time" },
16220
- { regex: /\bAKST\b(?!\w)/g, replacement: "Alaska Standard Time" },
16221
- { regex: /\bAKDT\b(?!\w)/g, replacement: "Alaska Daylight Time" },
16222
- { regex: /\bHST\b(?!\w)/g, replacement: "Hawaii Standard Time" },
16223
- { regex: /\bHDT\b(?!\w)/g, replacement: "Hawaii Daylight Time" },
16224
- { regex: /\bmph\b(?!\w)/g, replacement: "miles per hour" },
16225
- { regex: /\bkm\/h\b(?!\w)/g, replacement: "kilometers per hour" },
16226
- { regex: /\bkmh\b(?!\w)/g, replacement: "kilometers per hour" },
16227
- { regex: /\bkt\b(?!\w)/g, replacement: "knots" },
16228
- { regex: /\bNE\b(?!\w)/g, replacement: "northeast" },
16229
- { regex: /\bNW\b(?!\w)/g, replacement: "northwest" },
16230
- { regex: /\bSE\b(?!\w)/g, replacement: "southeast" },
16231
- { regex: /\bSW\b(?!\w)/g, replacement: "southwest" },
16232
- { regex: /\bNM\b(?!\w)/g, replacement: "nautical miles" },
16233
- { regex: /\bdeg\b(?!\w)/g, replacement: "degrees" },
16234
- { regex: /\btstm\b(?!\w)/g, replacement: "thunderstorm" },
16235
- { regex: /\bmm\b(?!\w)/g, replacement: "millimeters" },
16236
- { regex: /\bcm\b(?!\w)/g, replacement: "centimeters" },
16237
- { regex: /\bin.\b(?!\w)/g, replacement: "inches" },
16238
- { regex: /\bft\b(?!\w)/g, replacement: "feet" },
16239
- { regex: /\bmi\b(?!\w)/g, replacement: "miles" },
16240
- { regex: /\bhr\b(?!\w)/g, replacement: "hour" },
16241
- { regex: /\bhourly\b(?!\w)/g, replacement: "per hour" },
16242
- { regex: /\bkg\b(?!\w)/g, replacement: "kilograms" },
16243
- { regex: /\bg\/kg\b(?!\w)/g, replacement: "grams per kilogram" },
16244
- { regex: /\bmb\b(?!\w)/g, replacement: "millibars" },
16245
- { regex: /\bhPa\b(?!\w)/g, replacement: "hectopascals" },
16246
- { regex: /\bPa\b(?!\w)/g, replacement: "pascals" },
16247
- { regex: /\bKPa\b(?!\w)/g, replacement: "kilopascals" },
16248
- { regex: /\bC\/hr\b(?!\w)/g, replacement: "degrees Celsius per hour" },
16249
- { regex: /\bF\/hr\b(?!\w)/g, replacement: "degrees Fahrenheit per hour" },
16250
- { regex: /\bC\/min\b(?!\w)/g, replacement: "degrees Celsius per minute" },
16251
- { regex: /\bF\/min\b(?!\w)/g, replacement: "degrees Fahrenheit per minute" },
16252
- { regex: /\bC\b(?!\w)/g, replacement: "degrees Celsius" },
16253
- { regex: /\bF\b(?!\w)/g, replacement: "degrees Fahrenheit" }
16254
- ];
15974
+ // src/@dictionaries/dictionaries.eventTypes.ts
15975
+ var eventTypes = {
15976
+ "AF": "Ashfall",
15977
+ "AS": "Air Stagnation",
15978
+ "BH": "Beach Hazard",
15979
+ "BW": "Brisk Wind",
15980
+ "BZ": "Blizzard",
15981
+ "CF": "Coastal Flood",
15982
+ "DF": "Debris Flow",
15983
+ "DS": "Dust Storm",
15984
+ "EC": "Extreme Cold",
15985
+ "EH": "Excessive Heat",
15986
+ "XH": "Extreme Heat",
15987
+ "EW": "Extreme Wind",
15988
+ "FA": "Areal Flood",
15989
+ "FF": "Flash Flood",
15990
+ "FG": "Dense Fog",
15991
+ "FL": "Flood",
15992
+ "FR": "Frost",
15993
+ "FW": "Fire Weather",
15994
+ "FZ": "Freeze",
15995
+ "GL": "Gale",
15996
+ "HF": "Hurricane Force Wind",
15997
+ "HT": "Heat",
15998
+ "HU": "Hurricane",
15999
+ "HW": "High Wind",
16000
+ "HY": "Hydrologic",
16001
+ "HZ": "Hard Freeze",
16002
+ "IS": "Ice Storm",
16003
+ "LE": "Lake Effect Snow",
16004
+ "LO": "Low Water",
16005
+ "LS": "Lakeshore Flood",
16006
+ "LW": "Lake Wind",
16007
+ "MA": "Special Marine",
16008
+ "EQ": "Earthquake",
16009
+ "MF": "Dense Fog",
16010
+ "MH": "Ashfall",
16011
+ "MS": "Dense Smoke",
16012
+ "RB": "Small Craft for Rough Bar",
16013
+ "RP": "Rip Current Risk",
16014
+ "SC": "Small Craft",
16015
+ "SE": "Hazardous Seas",
16016
+ "SI": "Small Craft for Winds",
16017
+ "SM": "Dense Smoke",
16018
+ "SQ": "Snow Squall",
16019
+ "SR": "Storm",
16020
+ "SS": "Storm Surge",
16021
+ "SU": "High Surf",
16022
+ "SV": "Severe Thunderstorm",
16023
+ "SW": "Small Craft for Hazardous Seas",
16024
+ "TO": "Tornado",
16025
+ "TR": "Tropical Storm",
16026
+ "TS": "Tsunami",
16027
+ "TY": "Typhoon",
16028
+ "SP": "Special Weather",
16029
+ "UP": "Heavy Freezing Spray",
16030
+ "WC": "Wind Chill",
16031
+ "WI": "Wind",
16032
+ "WS": "Winter Storm",
16033
+ "WW": "Winter Weather",
16034
+ "ZF": "Freezing Fog",
16035
+ "ZR": "Freezing Rain",
16036
+ "ZY": "Freezing Spray"
16037
+ };
16255
16038
 
16256
- // src/@modules/@eas/eas.getWavPCM16.ts
16257
- var getWavPCM16 = (buffer) => {
16258
- if (buffer.toString("ascii", 0, 4) !== "RIFF" || buffer.toString("ascii", 8, 12) !== "WAVE") {
16259
- return null;
16260
- }
16261
- let fmt = null;
16262
- let data = null;
16263
- let i = 12;
16264
- while (i + 8 <= buffer.length) {
16265
- const id2 = buffer.toString("ascii", i, i + 4);
16266
- const size = buffer.readUInt32LE(i + 4);
16267
- const start = i + 8;
16268
- const end = start + size;
16269
- if (id2 === "fmt ") fmt = buffer.slice(start, end);
16270
- if (id2 === "data") data = buffer.slice(start, end);
16271
- i = end + size % 2;
16272
- }
16273
- if (!fmt || !data) return null;
16274
- const audioFormat = fmt.readUInt16LE(0);
16275
- const channels = fmt.readUInt16LE(2);
16276
- const sampleRate = fmt.readUInt32LE(4);
16277
- const bitsPerSample = fmt.readUInt16LE(14);
16278
- if (audioFormat !== 1 || bitsPerSample !== 16 || channels !== 1) {
16279
- return null;
16039
+ // src/@dictionaries/dictionaries.eventActions.ts
16040
+ var eventActions = {
16041
+ "W": "Warning",
16042
+ "F": "Forecast",
16043
+ "A": "Watch",
16044
+ "O": "Outlook",
16045
+ "Y": "Advisory",
16046
+ "N": "Synopsis",
16047
+ "S": "Statement"
16048
+ };
16049
+
16050
+ // src/@dictionaries/dictionaries.eventStatus.ts
16051
+ var eventStatus = {
16052
+ "NEW": "Issued",
16053
+ "CON": "Updated",
16054
+ "EXT": "Extended",
16055
+ "EXA": "Extended",
16056
+ "EXB": "Extended",
16057
+ "UPG": "Upgraded",
16058
+ "COR": "Correction",
16059
+ "ROU": "Routine",
16060
+ "CAN": "Cancelled",
16061
+ "EXP": "Expired"
16062
+ };
16063
+
16064
+ // src/@parsers/@pvtec/pvtec.expires.ts
16065
+ var getExpiry2 = (dates) => {
16066
+ if ((dates == null ? void 0 : dates[1]) == `000000T0000Z`) return "Invalid Date Format";
16067
+ const expires = `${(/* @__PURE__ */ new Date()).getFullYear().toString().substring(0, 2)}${dates[1].substring(0, 2)}-${dates[1].substring(2, 4)}-${dates[1].substring(4, 6)}T${dates[1].substring(7, 9)}:${dates[1].substring(9, 11)}:00`;
16068
+ const local = new Date(new Date(expires).getTime() - 4 * 60 * 6e4);
16069
+ const pad = (n) => n.toString().padStart(2, "0");
16070
+ return `${local.getFullYear()}-${pad(local.getMonth() + 1)}-${pad(local.getDate())}T${pad(local.getHours())}:${pad(local.getMinutes())}:00.000-04:00`;
16071
+ };
16072
+
16073
+ // src/@parsers/@pvtec/pvtec.extract.ts
16074
+ var pvExtract = (message) => {
16075
+ var _a, _b, _c, _d;
16076
+ const getVTECs = (_a = message.match(regExp.pvtec)) != null ? _a : [];
16077
+ const vtecs = [];
16078
+ for (const vtec2 of getVTECs) {
16079
+ const sub = vtec2.split(`.`);
16080
+ if ((sub == null ? void 0 : sub.length) < 7) continue;
16081
+ const dates = (_b = sub[6]) == null ? void 0 : _b.split(`-`);
16082
+ vtecs.push({
16083
+ vtec: vtec2,
16084
+ product: eventProducts[sub[0]],
16085
+ tracking: `${sub[2]}.${sub[3]}.${sub[4]}.${sub[5]}`,
16086
+ event: `${eventTypes[sub[3]]} ${eventActions[sub[4]]}`,
16087
+ status: eventStatus[sub[1]],
16088
+ organization: (_d = (_c = message.match(regExp.wmo)) == null ? void 0 : _c[0]) != null ? _d : null,
16089
+ expires: getExpiry2(dates),
16090
+ is_watch: (sub[4] == `A` || sub[4] == `Y`) && (sub[3] == `TO` || sub[3] == `SV`),
16091
+ prediction_center: sub[2] == `KWNS` ? true : false
16092
+ });
16280
16093
  }
16281
- const samples = new Int16Array(data.buffer, data.byteOffset, data.length / 2);
16282
- return { samples: new Int16Array(samples), sampleRate, channels, bitsPerSample };
16094
+ return vtecs.length > 0 ? vtecs : null;
16095
+ };
16096
+
16097
+ // src/@dictionaries/dictionaries.eventCauses.ts
16098
+ var eventCauses = {
16099
+ "SM": "Snow Melt",
16100
+ "RS": "Rain/Snow Melt",
16101
+ "ER": "Excessive Rain",
16102
+ "DM": "Dam/Levee Failure",
16103
+ "IJ": "Ice Jam",
16104
+ "GO": "Glacier Lake Outburst",
16105
+ "IC": "Ice",
16106
+ "FS": "Flash Flood / Storm Surge",
16107
+ "FT": "Tidal Effects",
16108
+ "ET": "Elevated Upstream Flow",
16109
+ "MC": "Other Multiple Causes",
16110
+ "WT": "Wind and/or Tidal Effects",
16111
+ "DR": "Reservoir Release",
16112
+ "UU": "Unknown",
16113
+ "OT": "Other Effects"
16283
16114
  };
16284
16115
 
16285
- // src/@modules/@eas/eas.getSampledPCM16.ts
16286
- var getSampledPCM16 = (int16, originalRate, targetRate) => {
16287
- if (originalRate === targetRate) return int16;
16288
- const ratio = targetRate / originalRate;
16289
- const outLen = Math.max(1, Math.round(int16.length * ratio));
16290
- const out = new Int16Array(outLen);
16291
- for (let i = 0; i < outLen; i++) {
16292
- const pos = i / ratio;
16293
- const i0 = Math.floor(pos);
16294
- const i1 = Math.min(i0 + 1, int16.length - 1);
16295
- const frac = pos - i0;
16296
- const v = int16[i0] * (1 - frac) + int16[i1] * frac;
16297
- out[i] = Math.round(v);
16298
- }
16299
- return out;
16116
+ // src/@dictionaries/dictionaries.eventRecords.ts
16117
+ var eventRecords = {
16118
+ "NO": "No Record Expected",
16119
+ "NR": "Near Record or possible record",
16120
+ "UU": "Unknown history of records",
16121
+ "OO": "Other"
16300
16122
  };
16301
16123
 
16302
- // src/@modules/@eas/eas.getPCMToFloat.ts
16303
- var getPCMToFloat = (int16) => {
16304
- const out = new Float32Array(int16.length);
16305
- for (let i = 0; i < int16.length; i++) out[i] = int16[i] / 32768;
16306
- return out;
16124
+ // src/@dictionaries/dictionaries.eventSeverity.ts
16125
+ var eventSeverity = {
16126
+ N: "Not Expected",
16127
+ 0: "Areal Flood or FF Product",
16128
+ 1: "Minor",
16129
+ 2: "Moderate",
16130
+ 3: "Major",
16131
+ U: "Unknown"
16307
16132
  };
16308
16133
 
16309
- // src/@modules/@eas/eas.getFloatPCM16.ts
16310
- var getFloatPCM16 = (float32) => {
16311
- const out = new Int16Array(float32.length);
16312
- for (let i = 0; i < float32.length; i++) {
16313
- let v = Math.max(-1, Math.min(1, float32[i]));
16314
- out[i] = Math.round(v * 32767);
16134
+ // src/@parsers/@hvtec/hvtec.extract.ts
16135
+ var hvExtract = (message) => {
16136
+ var _a;
16137
+ const getHVTECs = (_a = message.match(regExp.hvtec)) != null ? _a : [];
16138
+ const vtecs = [];
16139
+ for (const vtec2 of getHVTECs) {
16140
+ const sub = vtec2.split(`.`);
16141
+ if (sub.length < 7) continue;
16142
+ vtecs.push({
16143
+ hvtec: vtec2,
16144
+ severity: eventSeverity[sub[1]],
16145
+ cause: eventCauses[sub[2]],
16146
+ record: eventRecords[sub[6]]
16147
+ });
16315
16148
  }
16316
- return out;
16149
+ return vtecs.length > 0 ? vtecs : null;
16317
16150
  };
16318
16151
 
16319
- // src/@modules/@eas/eas.setRadioEffect.ts
16320
- var setRadioEffect = (int16, sampleRate) => {
16321
- const hpCut = 3555;
16322
- const lpCut = 1600;
16323
- const x = getPCMToFloat(int16);
16324
- const dt = 1 / sampleRate;
16325
- const rcHP = 1 / (2 * Math.PI * hpCut);
16326
- const aHP = rcHP / (rcHP + dt);
16327
- let yHP = 0, xPrev = 0;
16328
- for (let i = 0; i < x.length; i++) {
16329
- const xi = x[i];
16330
- yHP = aHP * (yHP + xi - xPrev);
16331
- xPrev = xi;
16332
- x[i] = yHP;
16152
+ // src/@events/events.vtec.ts
16153
+ var vtec = (stanza) => __async(null, null, function* () {
16154
+ var _a, _b, _c, _d, _e;
16155
+ let processed = [];
16156
+ const getMessages = (_c = (_b = (_a = stanza == null ? void 0 : stanza.message) == null ? void 0 : _a.split(/(?=\$\$)/g)) == null ? void 0 : _b.map((message) => message.trim())) == null ? void 0 : _c.filter((message) => message && message !== "$$");
16157
+ if (!getMessages || (getMessages == null ? void 0 : getMessages.length) == 0) return;
16158
+ for (const message of getMessages) {
16159
+ const tick = performance.now();
16160
+ const attributes = stanza == null ? void 0 : stanza.attributes;
16161
+ const pVtec = pvExtract(message);
16162
+ const hVtec = hvExtract(message);
16163
+ const ugc2 = yield ugcExtract(message);
16164
+ if (pVtec != null && ugc2 != null) {
16165
+ for (const pv of pVtec) {
16166
+ const vtec2 = pv;
16167
+ const props = properties({ message, attributes, ugc: ugc2, pVtec: vtec2 });
16168
+ const header = getEventHeader({ properties: props, getType: stanza.getType, vtec: vtec2 });
16169
+ const issued = (_d = new Date(attributes.issue)) != null ? _d : /* @__PURE__ */ new Date();
16170
+ const expires = new Date(vtec2.expires);
16171
+ processed.push({
16172
+ type: `Feature`,
16173
+ geometry: {
16174
+ type: `Point`,
16175
+ coordinates: []
16176
+ },
16177
+ properties: __spreadProps(__spreadValues({
16178
+ event: pv.event,
16179
+ parent: pv.event,
16180
+ status: pv.status,
16181
+ issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
16182
+ expires: !isNaN(expires.getTime()) ? expires.toISOString() : (_e = ugc2.expires) != null ? _e : new Date(issued.getTime() + 60 * 60 * 1e3).toISOString()
16183
+ }, props), {
16184
+ metadata: {
16185
+ ms: performance.now() - tick,
16186
+ source: `events.vtec`,
16187
+ tracking: getEventTracking({ type: `VTEC`, stanza, attributes, properties: props, vtec: vtec2 }),
16188
+ header,
16189
+ vtec: pv,
16190
+ hvtec: hVtec,
16191
+ raw: message,
16192
+ history: [
16193
+ {
16194
+ description: props.description,
16195
+ issued: !isNaN(issued.getTime()) ? issued.toISOString() : (/* @__PURE__ */ new Date()).toISOString(),
16196
+ status: pv.status
16197
+ }
16198
+ ]
16199
+ }
16200
+ })
16201
+ });
16202
+ }
16203
+ }
16333
16204
  }
16334
- const rcLP = 1 / (2 * Math.PI * lpCut);
16335
- const aLP = dt / (rcLP + dt);
16336
- let yLP = 0;
16337
- for (let i = 0; i < x.length; i++) {
16338
- yLP = yLP + aLP * (x[i] - yLP);
16339
- x[i] = yLP;
16205
+ validateEvents(processed);
16206
+ });
16207
+
16208
+ // src/@events/events.api.ts
16209
+ var api = (stanza) => __async(null, null, function* () {
16210
+ 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, _Oa, _Pa, _Qa, _Ra, _Sa, _Ta, _Ua, _Va, _Wa, _Xa, _Ya, _Za, __a, _$a, _ab, _bb, _cb, _db, _eb, _fb, _gb;
16211
+ let processed = [];
16212
+ const messages = Object.values(JSON.parse(stanza.message).features);
16213
+ for (const feature of messages) {
16214
+ const tick = performance.now();
16215
+ const pVtec = (_d = (_c = (_b = (_a = feature == null ? void 0 : feature.properties) == null ? void 0 : _a.parameters) == null ? void 0 : _b.VTEC) == null ? void 0 : _c[0]) != null ? _d : null;
16216
+ processed.push({
16217
+ type: `Feature`,
16218
+ geometry: {
16219
+ type: `Point`,
16220
+ coordinates: []
16221
+ },
16222
+ properties: {
16223
+ event: (_f = (_e = feature == null ? void 0 : feature.properties) == null ? void 0 : _e.event) != null ? _f : null,
16224
+ parent: (_h = (_g = feature == null ? void 0 : feature.properties) == null ? void 0 : _g.event) != null ? _h : null,
16225
+ status: (_j = (_i = feature == null ? void 0 : feature.properties) == null ? void 0 : _i.messageType) != null ? _j : null,
16226
+ issued: ((_k = feature == null ? void 0 : feature.properties) == null ? void 0 : _k.sent) ? new Date((_l = feature == null ? void 0 : feature.properties) == null ? void 0 : _l.sent).toISOString() : null,
16227
+ expires: ((_m = feature == null ? void 0 : feature.properties) == null ? void 0 : _m.expires) ? new Date((_n = feature == null ? void 0 : feature.properties) == null ? void 0 : _n.expires).toISOString() : null,
16228
+ locations: (_p = (_o = feature == null ? void 0 : feature.properties) == null ? void 0 : _o.areaDesc) != null ? _p : null,
16229
+ description: (_r = (_q = feature == null ? void 0 : feature.properties) == null ? void 0 : _q.description) != null ? _r : null,
16230
+ attributes: (_t = (_s = feature == null ? void 0 : feature.properties) == null ? void 0 : _s.attributes) != null ? _t : {},
16231
+ geocode: {
16232
+ office: {
16233
+ office: pVtec ? pVtec.split(`.`)[2] : null,
16234
+ name: (_u = officeICAOs[pVtec ? pVtec.split(`.`)[2] : null]) != null ? _u : null
16235
+ },
16236
+ organization: (_x = (_w = (_v = feature == null ? void 0 : feature.properties) == null ? void 0 : _v.parameters) == null ? void 0 : _w.WMOidentifier) == null ? void 0 : _x[0],
16237
+ ugc: (_A = (_z = (_y = feature == null ? void 0 : feature.properties) == null ? void 0 : _y.geocode) == null ? void 0 : _z.UGC) != null ? _A : [],
16238
+ polygon: ((_B = feature == null ? void 0 : feature.geometry) == null ? void 0 : _B.coordinates.length) > 0 ? Buffer.from(JSON.stringify([(_C = feature == null ? void 0 : feature.geometry) == null ? void 0 : _C.coordinates[0]])).toString("base64") : null,
16239
+ polygon_generated: ((_D = feature == null ? void 0 : feature.geometry) == null ? void 0 : _D.coordinates.length) > 0 ? true : false
16240
+ },
16241
+ parameters: {
16242
+ tags: getEventTags((_E = feature == null ? void 0 : feature.properties) == null ? void 0 : _E.description),
16243
+ instructions: (_G = (_F = feature == null ? void 0 : feature.properties) == null ? void 0 : _F.instruction) != null ? _G : null,
16244
+ source: (_I = getTextFromProduct({ message: (_H = feature == null ? void 0 : feature.properties) == null ? void 0 : _H.description, find: [`SOURCE...`], removal: [`.`] })) != null ? _I : null,
16245
+ hazards: (_K = getTextFromProduct({ message: (_J = feature == null ? void 0 : feature.properties) == null ? void 0 : _J.description, find: [`HAZARD...`], removal: [`.`] })) != null ? _K : null,
16246
+ impacts: (_M = getTextFromProduct({ message: (_L = feature == null ? void 0 : feature.properties) == null ? void 0 : _L.description, find: [`IMPACT...`], removal: [`.`] })) != null ? _M : null,
16247
+ estimated_hail_size: (_Q = (_P = (_O = (_N = feature == null ? void 0 : feature.properties) == null ? void 0 : _N.parameters) == null ? void 0 : _O.maxHailSize) == null ? void 0 : _P[0]) != null ? _Q : null,
16248
+ estimated_wind_gusts: (_U = (_T = (_S = (_R = feature == null ? void 0 : feature.properties) == null ? void 0 : _R.parameters) == null ? void 0 : _S.maxWindGust) == null ? void 0 : _T[0]) != null ? _U : null,
16249
+ damage_threat: (_Y = (_X = (_W = (_V = feature == null ? void 0 : feature.properties) == null ? void 0 : _V.parameters) == null ? void 0 : _W.thunderstormDamageThreat) == null ? void 0 : _X[0]) != null ? _Y : null,
16250
+ tornado_threat: (_aa = (_$ = (__ = (_Z = feature == null ? void 0 : feature.properties) == null ? void 0 : _Z.parameters) == null ? void 0 : __.tornadoDetection) == null ? void 0 : _$[0]) != null ? _aa : null,
16251
+ flood_threat: (_ea = (_da = (_ca = (_ba = feature == null ? void 0 : feature.properties) == null ? void 0 : _ba.parameters) == null ? void 0 : _ca.floodDetection) == null ? void 0 : _da[0]) != null ? _ea : null,
16252
+ wind_threat: (_ia = (_ha = (_ga = (_fa = feature == null ? void 0 : feature.properties) == null ? void 0 : _fa.parameters) == null ? void 0 : _ga.windThreat) == null ? void 0 : _ha[0]) != null ? _ia : null,
16253
+ hail_threat: (_ma = (_la = (_ka = (_ja = feature == null ? void 0 : feature.properties) == null ? void 0 : _ja.parameters) == null ? void 0 : _ka.hailThreat) == null ? void 0 : _la[0]) != null ? _ma : null
16254
+ },
16255
+ spc_parameters: {
16256
+ spc_number: (_oa = getTextFromProduct({ message: (_na = feature == null ? void 0 : feature.properties) == null ? void 0 : _na.description, find: [`Mesoscale Discussion `], removal: [`Mesoscale Discussion`, `Number`, `...`] })) != null ? _oa : null,
16257
+ spc_concerning: (_qa = getTextFromProduct({ message: (_pa = feature == null ? void 0 : feature.properties) == null ? void 0 : _pa.description, find: [`Concerning...`] })) != null ? _qa : null,
16258
+ spc_max_tornado: (_sa = getTextFromProduct({ message: (_ra = feature == null ? void 0 : feature.properties) == null ? void 0 : _ra.description, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] })) != null ? _sa : null,
16259
+ spc_max_hail: (_ua = getTextFromProduct({ message: (_ta = feature == null ? void 0 : feature.properties) == null ? void 0 : _ta.description, find: [`MOST PROBABLE PEAK HAIL SIZE...`] })) != null ? _ua : null,
16260
+ spc_max_wind: (_wa = getTextFromProduct({ message: (_va = feature == null ? void 0 : feature.properties) == null ? void 0 : _va.description, find: [`MOST PROBABLE PEAK WIND GUST...`] })) != null ? _wa : null,
16261
+ spc_watch_issuance: (_ya = getTextFromProduct({ message: (_xa = feature == null ? void 0 : feature.properties) == null ? void 0 : _xa.description, find: [`Probability of Watch Issuance...`], removal: [`percent`] })) != null ? _ya : null
16262
+ },
16263
+ watch_parameters: {
16264
+ watch_number: (_Ca = (_Ba = (_Aa = getTextFromProduct({ message: (_za = feature == null ? void 0 : feature.properties) == null ? void 0 : _za.description, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })) == null ? void 0 : _Aa.replace(/(WT|WS|)/g, "")) == null ? void 0 : _Ba.trim()) != null ? _Ca : null,
16265
+ watch_type: ((_Da = feature == null ? void 0 : feature.properties) == null ? void 0 : _Da.description.includes(`TORNADO WATCH`)) ? `Tornado` : ((_Ea = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ea.description.includes(`SEVERE`)) ? `Severe` : null,
16266
+ additional_tornadoes_probability: (_Ga = getTextFromProduct({ message: (_Fa = feature == null ? void 0 : feature.properties) == null ? void 0 : _Fa.description, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _Ga : null,
16267
+ strong_tornadoes_probability: (_Ia = getTextFromProduct({ message: (_Ha = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ha.description, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] })) != null ? _Ia : null,
16268
+ severe_wind_probability: (_Ka = getTextFromProduct({ message: (_Ja = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ja.description, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _Ka : null,
16269
+ severe_hail_probability: (_Ma = getTextFromProduct({ message: (_La = feature == null ? void 0 : feature.properties) == null ? void 0 : _La.description, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _Ma : null,
16270
+ hail_2in_probability: (_Oa = getTextFromProduct({ message: (_Na = feature == null ? void 0 : feature.properties) == null ? void 0 : _Na.description, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] })) != null ? _Oa : null,
16271
+ combined_hail_wind_probability: (_Qa = getTextFromProduct({ message: (_Pa = feature == null ? void 0 : feature.properties) == null ? void 0 : _Pa.description, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] })) != null ? _Qa : null,
16272
+ max_hail_in: (_Sa = getTextFromProduct({ message: (_Ra = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ra.description, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] })) != null ? _Sa : null,
16273
+ max_wind_surface: (_Ua = getTextFromProduct({ message: (_Ta = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ta.description, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] })) != null ? _Ua : null,
16274
+ max_tops_x100feet: (_Wa = getTextFromProduct({ message: (_Va = feature == null ? void 0 : feature.properties) == null ? void 0 : _Va.description, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] })) != null ? _Wa : null,
16275
+ pds_watch: getTextFromProduct({ message: (_Xa = feature == null ? void 0 : feature.properties) == null ? void 0 : _Xa.description, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`
16276
+ },
16277
+ metadata: {
16278
+ ms: performance.now() - tick,
16279
+ source: `events.api`,
16280
+ tracking: getEventTracking({ type: `API`, organization: { wmoidentifier: (__a = (_Za = (_Ya = feature == null ? void 0 : feature.properties) == null ? void 0 : _Ya.parameters) == null ? void 0 : _Za.WMOidentifier) == null ? void 0 : __a[0], featureId: feature == null ? void 0 : feature.id }, vtec: pVtec }),
16281
+ header: `ZCZC-ATMOSX-${(_ab = (_$a = feature == null ? void 0 : feature.properties) == null ? void 0 : _$a.parameters) == null ? void 0 : _ab.WMOidentifier}`,
16282
+ vtec: pVtec,
16283
+ hvtec: null,
16284
+ raw: (_bb = feature == null ? void 0 : feature.properties) == null ? void 0 : _bb.description,
16285
+ history: [
16286
+ {
16287
+ description: (_cb = feature == null ? void 0 : feature.properties) == null ? void 0 : _cb.description,
16288
+ issued: ((_db = feature == null ? void 0 : feature.properties) == null ? void 0 : _db.sent) ? new Date((_eb = feature == null ? void 0 : feature.properties) == null ? void 0 : _eb.sent).toISOString() : null,
16289
+ status: (_gb = (_fb = feature == null ? void 0 : feature.properties) == null ? void 0 : _fb.messageType) != null ? _gb : null
16290
+ }
16291
+ ]
16292
+ }
16293
+ }
16294
+ });
16340
16295
  }
16341
- const compGain = 2;
16342
- const norm = Math.tanh(compGain);
16343
- for (let i = 0; i < x.length; i++) x[i] = Math.tanh(x[i] * compGain) / norm;
16344
- return getFloatPCM16(x);
16345
- };
16296
+ validateEvents(processed);
16297
+ });
16346
16298
 
16347
- // src/@modules/@eas/eas.setAFSK.ts
16348
- var setAFSK = (bits, sampleRate) => {
16349
- const baud = 520.83;
16350
- const markFreq = 2083.3;
16351
- const spaceFreq = 1562.5;
16352
- const amplitude = 0.6;
16353
- const twoPi = Math.PI * 2;
16354
- const result = [];
16355
- let phase = 0;
16356
- let frac = 0;
16357
- for (let b = 0; b < bits.length; b++) {
16358
- const bit = bits[b];
16359
- const freq = bit ? markFreq : spaceFreq;
16360
- const samplesPerBit = sampleRate / baud + frac;
16361
- const n = Math.round(samplesPerBit);
16362
- frac = samplesPerBit - n;
16363
- const inc = twoPi * freq / sampleRate;
16364
- for (let i = 0; i < n; i++) {
16365
- result.push(Math.round(Math.sin(phase) * amplitude * 32767));
16366
- phase += inc;
16367
- if (phase > twoPi) phase -= twoPi;
16299
+ // src/@building/building.create.ts
16300
+ var createEvent = (stanza) => __async(null, null, function* () {
16301
+ const settings = bootstrap.settings;
16302
+ const StanzaSettings = settings.NOAAWeatherWireServiceSettings.StanzaSettings;
16303
+ const isVtecEvent = stanza.isVTEC && stanza.isUGC;
16304
+ const isUgcEvent = !stanza.isVTEC && stanza.isUGC;
16305
+ const isTextEvent = !stanza.isVTEC && !stanza.isUGC;
16306
+ const isNWWS = stanza.isNWWS;
16307
+ if (!isNWWS) return yield api(stanza);
16308
+ if (!StanzaSettings.DisableVTEC && isVtecEvent) return yield vtec(stanza);
16309
+ if (!StanzaSettings.DisableUGC && isUgcEvent) return yield ugc(stanza);
16310
+ if (!StanzaSettings.DisableText && isTextEvent) return yield text(stanza);
16311
+ return "nothing picked";
16312
+ });
16313
+
16314
+ // src/@modules/@database/database.stanza.ts
16315
+ var importStanza = (stanza) => __async(null, null, function* () {
16316
+ const settings = bootstrap.settings;
16317
+ try {
16318
+ if (!settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
16319
+ return;
16320
+ }
16321
+ bootstrap.database.prepare(`INSERT OR IGNORE INTO stanzas (type, stanza, issued) VALUES (?, ?, ?)`).run(stanza.getType.type, JSON.stringify(stanza), stanza.attributes.issue);
16322
+ const count = bootstrap.database.prepare(`SELECT COUNT(*) as total FROM stanzas`).get();
16323
+ const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxDatabaseHistory;
16324
+ if (count.total > max) {
16325
+ const toDelete = count.total - max;
16326
+ if (toDelete > 0) {
16327
+ bootstrap.database.prepare(`DELETE FROM stanzas WHERE id IN (SELECT id FROM stanzas ORDER BY issued ASC LIMIT ?)`).run(toDelete);
16328
+ }
16368
16329
  }
16330
+ } catch (error) {
16331
+ setWarning({ message: `An error occurred while importing stanza: ${error.message}` });
16369
16332
  }
16370
- const fadeSamples = Math.floor(sampleRate * 2e-3);
16371
- for (let i = 0; i < fadeSamples; i++) {
16372
- const gain = i / fadeSamples;
16373
- result[i] = Math.round(result[i] * gain);
16374
- result[result.length - 1 - i] = Math.round(result[result.length - 1 - i] * gain);
16375
- }
16376
- return Int16Array.from(result);
16377
- };
16378
-
16379
- // src/@modules/@eas/eas.setAsciiToBits.ts
16380
- var setAsciiToBits = (str) => {
16381
- const bits = [];
16382
- for (let i = 0; i < str.length; i++) {
16383
- const c = str.charCodeAt(i) & 255;
16384
- bits.push(0);
16385
- for (let b = 0; b < 8; b++) bits.push(c >> b & 1);
16386
- bits.push(1, 1);
16387
- }
16388
- return bits;
16389
- };
16333
+ });
16390
16334
 
16391
- // src/@modules/@eas/eas.getMergedPCM16.ts
16392
- var getMergedPCM16 = (arrays) => {
16393
- let total = 0;
16394
- for (const a of arrays) total += a.length;
16395
- const out = new Int16Array(total);
16396
- let o = 0;
16397
- for (const a of arrays) {
16398
- out.set(a, o);
16399
- o += a.length;
16400
- }
16401
- return out;
16335
+ // src/@modules/@xmpp/xmpp.xStanza.ts
16336
+ var xStanza = () => {
16337
+ bootstrap.session_xmpp.on(`stanza`, (stanza) => __async(null, null, function* () {
16338
+ var _a, _b, _c, _d;
16339
+ const msgFrom = (_b = (_a = stanza == null ? void 0 : stanza.attrs) == null ? void 0 : _a.from) != null ? _b : ``;
16340
+ const msgType = (_d = (_c = stanza == null ? void 0 : stanza.attrs) == null ? void 0 : _c.type) != null ? _d : ``;
16341
+ setEventEmit({
16342
+ event: `onServiceStatus`,
16343
+ metadata: {
16344
+ message: stanza,
16345
+ from: msgFrom,
16346
+ type: `stanza`
16347
+ }
16348
+ });
16349
+ bootstrap.cache.lastStanza = Date.now();
16350
+ if (stanza.is(`message`)) {
16351
+ const result = validate({ stanza });
16352
+ const isSkippable = result.isIgnored || result.isCapEvent || result.isCapEvent && !result.isCapAreaDescription;
16353
+ if (isSkippable) {
16354
+ return;
16355
+ }
16356
+ yield createEvent(result);
16357
+ yield importStanza(result);
16358
+ }
16359
+ if (stanza.is(`presence`) && msgFrom.startsWith("nwws@conference.nwws-oi.weather.gov/")) {
16360
+ const getOccupant = msgFrom.split(`/`).slice(1).join(`/`);
16361
+ const getAvailability = msgType === `unavailable`;
16362
+ setEventEmit({
16363
+ event: `onServiceStatus`,
16364
+ metadata: {
16365
+ message: `Occupant ${getOccupant} has ${getAvailability ? `left` : `joined`} the room`,
16366
+ data: {},
16367
+ type: `occupant`,
16368
+ error: false
16369
+ }
16370
+ });
16371
+ }
16372
+ }));
16402
16373
  };
16403
16374
 
16404
- // src/@modules/@eas/eas.setSameHeader.ts
16405
- var setSameHeader = (vtec2, repeats, sampleRate = 8e3, options = {}) => {
16375
+ // src/@modules/@xmpp/xmpp.xDeploy.ts
16376
+ var xDeploy = () => __async(null, null, function* () {
16406
16377
  var _a, _b;
16407
- const preMarkSec = (_a = options.preMarkSec) != null ? _a : 0.3;
16408
- const gapSec = (_b = options.gapSec) != null ? _b : 0.1;
16409
- const bursts = [];
16410
- const gap = new Int16Array(Math.floor(gapSec * sampleRate));
16411
- for (let i = 0; i < repeats; i++) {
16412
- const bodyBits = setAsciiToBits(vtec2);
16413
- const body = setAFSK(bodyBits, sampleRate);
16414
- const extendedBodyDuration = Math.round(preMarkSec * sampleRate);
16415
- const extendedBody = new Int16Array(extendedBodyDuration + gap.length);
16416
- for (let j2 = 0; j2 < extendedBodyDuration; j2++) {
16417
- extendedBody[j2] = Math.round(body[j2 % body.length] * 0.2);
16418
- }
16419
- extendedBody.set(gap, extendedBodyDuration);
16420
- bursts.push(extendedBody);
16421
- if (i !== repeats - 1) bursts.push(gap);
16378
+ let session;
16379
+ const settings = bootstrap.settings;
16380
+ (_b = (_a = settings.NOAAWeatherWireServiceSettings.CredentialSettings).Nickname) != null ? _b : _a.Nickname = settings.NOAAWeatherWireServiceSettings.CredentialSettings.Username;
16381
+ session = bootstrap.session_xmpp = client({
16382
+ service: "xmpp://nwws-oi.weather.gov",
16383
+ domain: "nwws-oi.weather.gov",
16384
+ username: settings.NOAAWeatherWireServiceSettings.CredentialSettings.Username,
16385
+ password: settings.NOAAWeatherWireServiceSettings.CredentialSettings.Password
16386
+ });
16387
+ try {
16388
+ yield xOffline();
16389
+ yield xError();
16390
+ yield xStanza();
16391
+ yield xOnline();
16392
+ yield session.start();
16393
+ } catch (error) {
16394
+ setEventEmit({
16395
+ event: `onServiceStatus`,
16396
+ metadata: {
16397
+ message: `Error occured while starting XMPP Session: ${error}`,
16398
+ data: {},
16399
+ type: `error`,
16400
+ error: true
16401
+ }
16402
+ });
16422
16403
  }
16423
- return getMergedPCM16(bursts);
16424
- };
16404
+ });
16425
16405
 
16426
- // src/@modules/@eas/eas.setAttentionTone.ts
16427
- var setAttentionTone = (ms, sampleRate) => {
16428
- const len = Math.floor(ms * sampleRate);
16429
- const out = new Int16Array(len);
16430
- const f1 = 853;
16431
- const f2 = 960;
16432
- const twoPi = Math.PI * 2;
16433
- const amp = 0.1;
16434
- const fadeLen = Math.floor(sampleRate * 0);
16435
- for (let i = 0; i < len; i++) {
16436
- const t = i / sampleRate;
16437
- const s = Math.sin(twoPi * f1 * t) + Math.sin(twoPi * f2 * t);
16438
- let gain = 1;
16439
- if (i < fadeLen) gain = i / fadeLen;
16440
- else if (i > len - fadeLen) gain = (len - i) / fadeLen;
16441
- const v = Math.max(-1, Math.min(1, s / 2 * amp * gain));
16442
- out[i] = Math.round(v * 32767);
16443
- }
16444
- return out;
16445
- };
16406
+ // src/@modules/@database/database.init.ts
16407
+ var import_fs4 = __toESM(require("fs"));
16408
+ var import_better_sqlite3 = __toESM(require("better-sqlite3"));
16446
16409
 
16447
- // src/@modules/@eas/eas.setNoise.ts
16448
- var setNoise = (int16, noiseLevel = 0.02) => {
16449
- const x = getPCMToFloat(int16);
16450
- for (let i = 0; i < x.length; i++) x[i] += (Math.random() * 2 - 1) * noiseLevel;
16451
- let peak = 0;
16452
- for (let i = 0; i < x.length; i++) peak = Math.max(peak, Math.abs(x[i]));
16453
- if (peak > 1) for (let i = 0; i < x.length; i++) x[i] *= 0.98 / peak;
16454
- return getFloatPCM16(x);
16455
- };
16410
+ // src/@modules/@database/database.shapefiles.ts
16411
+ var import_fs3 = __toESM(require("fs"));
16412
+ var import_path3 = require("path");
16413
+ var import_jszip = require("jszip");
16414
+ var import_shapefile = require("shapefile");
16456
16415
 
16457
- // src/@modules/@eas/eas.getPCM16.ts
16458
- var getPCM16 = (samples, sampleRate) => {
16459
- let o = 0;
16460
- const bytesPerSample = 2;
16461
- const blockAlign = 1 * bytesPerSample;
16462
- const byteRate = sampleRate * blockAlign;
16463
- const subchunk2Size = samples.length * bytesPerSample;
16464
- const chunkSize = 36 + subchunk2Size;
16465
- const buffer = Buffer.alloc(44 + subchunk2Size);
16466
- buffer.write("RIFF", o);
16467
- o += 4;
16468
- buffer.writeUInt32LE(chunkSize, o);
16469
- o += 4;
16470
- buffer.write("WAVE", o);
16471
- o += 4;
16472
- buffer.write("fmt ", o);
16473
- o += 4;
16474
- buffer.writeUInt32LE(16, o);
16475
- o += 4;
16476
- buffer.writeUInt16LE(1, o);
16477
- o += 2;
16478
- buffer.writeUInt16LE(1, o);
16479
- o += 2;
16480
- buffer.writeUInt32LE(sampleRate, o);
16481
- o += 4;
16482
- buffer.writeUInt32LE(byteRate, o);
16483
- o += 4;
16484
- buffer.writeUInt16LE(blockAlign, o);
16485
- o += 2;
16486
- buffer.writeUInt16LE(16, o);
16487
- o += 2;
16488
- buffer.write("data", o);
16489
- o += 4;
16490
- buffer.writeUInt32LE(subchunk2Size, o);
16491
- o += 4;
16492
- for (let i = 0; i < samples.length; i++, o += 2) {
16493
- buffer.writeInt16LE(samples[i].value, o);
16416
+ // src/@modules/@utilities/utilities.setSleep.ts
16417
+ var setSleep = (options) => __async(null, null, function* () {
16418
+ return new Promise((resolve6) => {
16419
+ setTimeout(() => {
16420
+ resolve6();
16421
+ }, options.timeout);
16422
+ });
16423
+ });
16424
+
16425
+ // src/@dictionaries/dictionaries.shapefileLinks.ts
16426
+ var shapefileLinks = [
16427
+ { name: "us_counties", id: "C", link: "https://www.weather.gov/source/gis/Shapefiles/County/c_16ap26.zip" },
16428
+ { name: "us_states_territories", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/County/s_16ap26.zip" },
16429
+ { name: "fire_weather_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/fz16ap26.zip" },
16430
+ { name: "costal_marine_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/mz16ap26.zip" },
16431
+ { name: "offshore_marine_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/oz16ap26.zip" },
16432
+ { name: "public_forecast_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/z_16ap26.zip" },
16433
+ { name: "county_warning_areas", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/w_16ap26.zip" },
16434
+ { name: "river_forecast_boundaries", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/Misc/rf05mr24.zip" },
16435
+ { name: "high_seas_marine_zones", id: "Z", link: "https://www.weather.gov/source/gis/Shapefiles/WSOM/hz17fe26.zip" }
16436
+ ];
16437
+
16438
+ // src/@modules/@database/database.shapefiles.ts
16439
+ var importShapefiles = () => __async(null, null, function* () {
16440
+ var _a, _b;
16441
+ const settings = bootstrap.settings;
16442
+ try {
16443
+ const tShapefiles = bootstrap.database.prepare(`SELECT COUNT(*) AS count FROM shapefiles`).get().count;
16444
+ if (tShapefiles === 0) {
16445
+ yield setSleep({ timeout: 1e3 });
16446
+ setWarning({ message: `Shapefiles are currently building, please DO NOT close your terminal. The shapefiles will not finish and will remain incomplete. If you do mess up, you will need to delete ${settings.Database} and restart the application.` });
16447
+ for (const shapefile of shapefileLinks) {
16448
+ const response2 = yield fetch(shapefile.link);
16449
+ const arrayBuff = yield response2.arrayBuffer();
16450
+ const content = yield (0, import_jszip.loadAsync)(arrayBuff);
16451
+ const directory = (0, import_path3.resolve)(__dirname, `../../shapefiles`);
16452
+ if (!import_fs3.default.existsSync(directory)) {
16453
+ import_fs3.default.mkdirSync(directory, { recursive: true });
16454
+ }
16455
+ for (const file of Object.keys(content.files)) {
16456
+ if (file.endsWith(".shp") || file.endsWith(".dbf")) {
16457
+ const data = yield content.files[file].async(`nodebuffer`);
16458
+ const output = (0, import_path3.resolve)(directory, `${(_a = shapefile == null ? void 0 : shapefile.name) != null ? _a : ``}_${(_b = shapefile == null ? void 0 : shapefile.id) != null ? _b : ``}${(0, import_path3.extname)(file)}`);
16459
+ import_fs3.default.writeFileSync(output, data);
16460
+ }
16461
+ }
16462
+ const filepath = (0, import_path3.resolve)(__dirname, "../../shapefiles", shapefile.name + "_" + shapefile.id);
16463
+ const { features } = yield (0, import_shapefile.read)(
16464
+ filepath,
16465
+ filepath
16466
+ );
16467
+ setWarning({ message: `Importing ${features.length} features from ${shapefile.name}_${shapefile.id}` });
16468
+ const insert = bootstrap.database.prepare(`INSERT OR REPLACE INTO shapefiles (id, location, geometry) VALUES (?, ?, ?)`);
16469
+ const transaction = bootstrap.database.transaction((entries) => {
16470
+ var _a2, _b2, _c;
16471
+ for (const entry of entries) {
16472
+ const { properties: properties2, geometry } = entry;
16473
+ let final2, location;
16474
+ if (properties2.FIPS) {
16475
+ final2 = `${properties2.STATE}${shapefile.id}${properties2.FIPS.substring(2)}`;
16476
+ location = `${properties2.COUNTYNAME}, ${properties2.STATE}`;
16477
+ } else if (properties2.FULLSTAID) {
16478
+ final2 = `${properties2.ST}${shapefile.id}${properties2.WFO}`;
16479
+ location = `${properties2.CITY}, ${properties2.STATE}`;
16480
+ } else if (properties2.STATE) {
16481
+ final2 = `${properties2.STATE}${shapefile.id}${(_a2 = properties2.ZONE) != null ? _a2 : properties2.SITE_ID}`;
16482
+ location = `${(_b2 = properties2.NAME) != null ? _b2 : `${properties2.RFC_NAME} ${properties2.RFC_CITY}`}, ${properties2.STATE}`;
16483
+ } else {
16484
+ final2 = (_c = properties2.ID) != null ? _c : properties2.WFO;
16485
+ location = properties2.NAME;
16486
+ }
16487
+ insert.run(final2, location, JSON.stringify(geometry));
16488
+ }
16489
+ });
16490
+ import_fs3.default.unlinkSync(`${filepath}.shp`);
16491
+ import_fs3.default.unlinkSync(`${filepath}.dbf`);
16492
+ setWarning({ message: `Cleaned up temporary files for ${shapefile.name}_${shapefile.id}` });
16493
+ transaction(features);
16494
+ }
16495
+ setWarning({ message: `Shapefiles have finished compiling, you can now continue and close this terminal` });
16496
+ import_fs3.default.rm((0, import_path3.resolve)(__dirname, "../../shapefiles"), { recursive: true, force: true }, () => {
16497
+ });
16498
+ }
16499
+ } catch (error) {
16500
+ setWarning({ message: `An error occurred while compiling shapefiles: ${error.message}` });
16494
16501
  }
16495
- return buffer;
16496
- };
16502
+ });
16497
16503
 
16498
- // src/@modules/@eas/eas.setEasTone.ts
16499
- var import_path3 = require("path");
16500
- var import_fs3 = require("fs");
16501
- var import_child_process = require("child_process");
16502
- var import_os = require("os");
16503
- var import_say = __toESM(require("say"));
16504
- var setEasTone = (options) => __async(null, null, function* () {
16504
+ // src/@modules/@database/database.init.ts
16505
+ var initializeDatabase = () => __async(null, null, function* () {
16505
16506
  const settings = bootstrap.settings;
16506
- const directory = settings.GlobalSettings.EASSettings.ArchiveDirectory;
16507
- const prefix = settings.GlobalSettings.EASSettings.IntroWavFile;
16508
- let message = options.message;
16509
- let header = options.header;
16510
- let buffTTS;
16511
- let buffRadio;
16512
- let buffFull = [];
16513
- const tmpTTS = (0, import_path3.join)(directory, `/temp/${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, "")}.wav`);
16514
- const outTTS = (0, import_path3.join)(directory, `/output/${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, "")}.wav`);
16515
- const vTTS = process.platform === `win32` ? `Microsoft David Desktop` : `en-US-GuyNerual`;
16516
- const vPlatform = (0, import_os.platform)();
16517
- if (!(0, import_fs3.existsSync)(directory)) {
16518
- (0, import_fs3.mkdirSync)(directory, { recursive: true });
16519
- }
16520
- if (!(0, import_fs3.existsSync)((0, import_path3.join)(directory, `/temp`))) {
16521
- (0, import_fs3.mkdirSync)((0, import_path3.join)(directory, `/temp`), { recursive: true });
16522
- }
16523
- if (!(0, import_fs3.existsSync)((0, import_path3.join)(directory, `/output`))) {
16524
- (0, import_fs3.mkdirSync)((0, import_path3.join)(directory, `/output`), { recursive: true });
16507
+ try {
16508
+ if (!import_fs4.default.existsSync(settings.Database)) {
16509
+ import_fs4.default.writeFileSync(settings.Database, "");
16510
+ setWarning({ message: `Creating new database at ${settings.Database}` });
16511
+ }
16512
+ bootstrap.database = new import_better_sqlite3.default(settings.Database);
16513
+ bootstrap.database.prepare(`CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )`).run();
16514
+ bootstrap.database.prepare(`CREATE TABLE IF NOT EXISTS shapefiles (id TEXT PRIMARY KEY, location TEXT, geometry TEXT)`).run();
16515
+ yield importShapefiles();
16516
+ } catch (error) {
16517
+ setWarning({ message: `An error occurred while initializing the database: ${error.message}` });
16525
16518
  }
16526
- for (const { regex, replacement } of transcribedMessageReplacements) {
16527
- message = message.replace(regex, replacement);
16519
+ });
16520
+
16521
+ // src/@modules/@database/database.cache.ts
16522
+ var getCachedEvents = () => __async(null, null, function* () {
16523
+ var _a;
16524
+ try {
16525
+ const settings = bootstrap.settings;
16526
+ const tick = performance.now();
16527
+ if (settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
16528
+ const max = (_a = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxRetentionHistory) != null ? _a : 500;
16529
+ const get = yield bootstrap.database.prepare(`SELECT * FROM stanzas ORDER BY rowid DESC LIMIT ?`).all(max);
16530
+ setWarning({ message: `Fetched ${get.length} cached events from the database in ${Math.floor(performance.now() - tick)} ms` });
16531
+ let events = get.map((row) => JSON.parse(row.stanza)).filter((stanza) => {
16532
+ if (!stanza) {
16533
+ return;
16534
+ }
16535
+ const isSkippable = stanza.isIgnored || stanza.isCapEvent || stanza.isCapEvent && !stanza.isCapAreaDescription;
16536
+ return !isSkippable;
16537
+ });
16538
+ events = events.sort((a, b) => b.issued - a.issued);
16539
+ yield Promise.all(events.map((event) => createEvent(event)));
16540
+ setWarning({ message: `Processed ${events.length} cached events in ${Math.floor(performance.now() - tick)} ms` });
16541
+ }
16542
+ } catch (error) {
16543
+ setWarning({ message: `An error occurred while fetching cached events: ${error.message} -> ${error.stack}` });
16528
16544
  }
16529
- if (vPlatform != `win32`) {
16530
- setWarning({
16531
- title: `EAS`,
16532
- message: `Generation isn't supported with this OS. Please wait for further updates before trying again`
16533
- });
16534
- return null;
16545
+ });
16546
+
16547
+ // src/@modules/@xmpp/xmpp.xReconnect.ts
16548
+ var xReconnect = (interval) => __async(null, null, function* () {
16549
+ const settings = bootstrap.settings;
16550
+ const lastStanza = Date.now() - bootstrap.cache.lastStanza;
16551
+ if (interval < 15) {
16552
+ setWarning({ message: `Reconnection interval of ${interval} seconds is too low, setting to 15 seconds` });
16553
+ interval = 15;
16554
+ bootstrap.settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.ReconnectionInterval = 15;
16535
16555
  }
16536
- import_say.default.export(message, vTTS, 1, tmpTTS);
16537
- while (!(0, import_fs3.existsSync)(tmpTTS) || (buffTTS = (0, import_fs3.readFileSync)(tmpTTS)).length == 0) {
16538
- yield setSleep({ timeout: 25 });
16556
+ const reconnectThreshold = interval * 1e3;
16557
+ if (!bootstrap.cache.isConnected && !bootstrap.cache.sigHault || !bootstrap.session_xmpp) {
16558
+ return;
16539
16559
  }
16540
- const vWav = getWavPCM16(buffTTS);
16541
- const vSamples = getSampledPCM16(vWav.samples, vWav.sampleRate, 8e3);
16542
- const vRadio = setRadioEffect(vSamples, 8e3);
16543
- if ((0, import_fs3.existsSync)(prefix)) {
16544
- let tBuffer = (0, import_fs3.readFileSync)(prefix);
16545
- let tWav = getWavPCM16(tBuffer);
16546
- if (tWav == null) {
16560
+ if (lastStanza > reconnectThreshold) {
16561
+ if (!bootstrap.cache.isReconnecting) {
16562
+ bootstrap.cache.isReconnecting = true;
16563
+ bootstrap.cache.isConnected = false;
16564
+ bootstrap.cache.tReconnects += 1;
16547
16565
  try {
16548
- const converted = (0, import_path3.join)(directory, `/temp/${Math.random().toString(36).substring(2, 15)}.converted.wav`);
16549
- (0, import_child_process.execSync)(`ffmpeg -y -i "${prefix}" -ar 8000 -ac 1 -sample_fmt s16 "${converted}"`, { stdio: "ignore" });
16550
- if ((0, import_fs3.existsSync)(converted)) {
16551
- tBuffer = (0, import_fs3.readFileSync)(converted);
16552
- tWav = getWavPCM16(tBuffer);
16566
+ setEventEmit({
16567
+ event: `onServiceStatus`,
16568
+ metadata: {
16569
+ message: `Attempting to reconnect to XMPP Service (Reconnect Attempt ${bootstrap.cache.tReconnects})`,
16570
+ data: {
16571
+ last_stanza: lastStanza,
16572
+ nickname: settings.NOAAWeatherWireServiceSettings.CredentialSettings.Nickname
16573
+ },
16574
+ type: `reconnect`,
16575
+ error: true
16576
+ }
16577
+ });
16578
+ yield bootstrap.session_xmpp.stop().catch(() => {
16579
+ });
16580
+ yield bootstrap.session_xmpp.start().catch(() => {
16581
+ });
16582
+ } catch (error) {
16583
+ setWarning({ message: `XMPP Reconnect Failed - ${error.message}` });
16584
+ } finally {
16585
+ bootstrap.cache.isReconnecting = false;
16586
+ }
16587
+ }
16588
+ }
16589
+ });
16590
+
16591
+ // src/@modules/@utilities/utilities.setCronSchedule.ts
16592
+ var import_fs5 = require("fs");
16593
+ var import_path4 = require("path");
16594
+ var setCronSchedule = () => __async(null, null, function* () {
16595
+ const settings = bootstrap.settings;
16596
+ const TTL = settings.GlobalSettings.EASSettings.ArchiveTTL;
16597
+ const TTLCUT = Date.now() - TTL * 1e3;
16598
+ const walk = (dir) => {
16599
+ if ((0, import_fs5.existsSync)(dir)) {
16600
+ const entries = (0, import_fs5.readdirSync)(dir, { withFileTypes: true });
16601
+ for (const entry of entries) {
16602
+ const fullPath = (0, import_path4.join)(dir, entry.name);
16603
+ if (entry.isDirectory()) {
16604
+ walk(fullPath);
16605
+ continue;
16606
+ }
16607
+ const stats = (0, import_fs5.statSync)(fullPath);
16608
+ if (stats.mtime.getTime() < TTLCUT) {
16553
16609
  try {
16554
- (0, import_fs3.unlinkSync)(converted);
16555
- } catch (e) {
16610
+ (0, import_fs5.unlinkSync)(fullPath);
16611
+ } catch (err) {
16612
+ console.error(`Failed to delete ${fullPath}:`, err);
16556
16613
  }
16557
16614
  }
16558
- } catch (e) {
16559
16615
  }
16560
16616
  }
16561
- if (tWav == null) {
16562
- setWarning({ title: `EAS`, message: `Intro tone isn't a valid .WAV file or isn't in PCM 16-bit format. Converted attempt failed; please convert it then try again.` });
16563
- return null;
16617
+ };
16618
+ walk(settings.GlobalSettings.EASSettings.ArchiveDirectory);
16619
+ if (settings.EnableWireService) {
16620
+ if (settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.Enabled) {
16621
+ void xReconnect(settings.NOAAWeatherWireServiceSettings.ReconnectionSettings.ReconnectionInterval);
16564
16622
  }
16565
- const tSamples = tWav.sampleRate != 8e3 ? getSampledPCM16(tWav.samples, tWav.sampleRate, 8e3) : tWav.samples;
16566
- buffRadio = setRadioEffect(tSamples, 8e3);
16623
+ } else {
16624
+ const response2 = yield createHttp({
16625
+ url: settings.NationalWeatherServiceSettings.EventsEndpoint,
16626
+ headers: {
16627
+ "User-Agent": "@atmosx/event-product-parser"
16628
+ }
16629
+ });
16630
+ if (response2.error) {
16631
+ return setEventEmit({
16632
+ event: `onServiceStatus`,
16633
+ metadata: {
16634
+ type: "fetch-api",
16635
+ message: `Failed to fetch latest events from National Weather Service API - ${response2.message}`,
16636
+ data: {},
16637
+ error: true
16638
+ }
16639
+ });
16640
+ }
16641
+ setEventEmit({
16642
+ event: `onServiceStatus`,
16643
+ metadata: {
16644
+ message: `Fetched latest events from National Weather Service API`,
16645
+ data: {},
16646
+ type: "fetch-api",
16647
+ error: false
16648
+ }
16649
+ });
16650
+ createEvent({ message: response2.message, isNWWS: false });
16567
16651
  }
16568
- buffFull = buffRadio != null ? [buffRadio, new Int16Array(Math.floor(0.5 * 8e3))] : [];
16569
- buffFull.push(
16570
- setSameHeader(header, 3, 8e3, {
16571
- preMarkSec: 1.1,
16572
- gapSec: 0.5
16573
- }),
16574
- new Int16Array(Math.floor(0.5 * 8e3)),
16575
- setAttentionTone(8, 8e3),
16576
- new Int16Array(Math.floor(0.5 * 8e3)),
16577
- vRadio
16578
- );
16579
- for (let i = 0; i < 3; i++) {
16580
- buffFull.push(setSameHeader(header, 1, 8e3, { preMarkSec: 0.5, gapSec: 0.1 }));
16581
- buffFull.push(new Int16Array(Math.floor(0.5 * 8e3)));
16652
+ });
16653
+
16654
+ // src/@manager/manager.updateEvents.ts
16655
+ var updateEvents = (selectedEvent) => __async(null, null, function* () {
16656
+ const events = bootstrap.cache.events.features;
16657
+ function update(evt) {
16658
+ return __async(this, null, function* () {
16659
+ if (new Date(evt.properties.expires) < /* @__PURE__ */ new Date()) {
16660
+ rmEvent(evt);
16661
+ }
16662
+ });
16582
16663
  }
16583
- const aSamples = getMergedPCM16(buffFull);
16584
- const aFinal = setNoise(aSamples, 2e-3);
16585
- const aBuffer = getPCM16(Array.from(aFinal).map((v) => ({ value: v })), 8e3);
16586
- (0, import_fs3.writeFileSync)(outTTS, aBuffer);
16587
- try {
16588
- (0, import_fs3.unlinkSync)(tmpTTS);
16589
- } catch (e) {
16664
+ if (!selectedEvent) {
16665
+ yield Promise.all(events.map((evt) => __async(null, null, function* () {
16666
+ yield update(evt);
16667
+ })));
16668
+ }
16669
+ if (selectedEvent) {
16670
+ yield update(selectedEvent);
16671
+ }
16672
+ });
16673
+
16674
+ // src/@core/core.start.ts
16675
+ var import_croner = require("croner");
16676
+ var startService = (configurations) => __async(null, null, function* () {
16677
+ if (!bootstrap.isReady) {
16678
+ return setWarning({
16679
+ message: `You can not create another instance without shutting down the current one first, please make sure to call the stop() method first!`
16680
+ });
16681
+ }
16682
+ const settings = setSettings(configurations);
16683
+ bootstrap.isReady = true;
16684
+ yield initializeDatabase();
16685
+ if (settings.EnableWireService) {
16686
+ (() => __async(null, null, function* () {
16687
+ yield getCachedEvents();
16688
+ yield xDeploy();
16689
+ }))();
16690
+ }
16691
+ yield setCronSchedule();
16692
+ let scheduleInterval = !settings.EnableWireService ? settings.NationalWeatherServiceSettings.CallbackInterval : 1;
16693
+ if (!settings.EnableWireService && scheduleInterval < 15) {
16694
+ setWarning({ message: `Schedule interval of ${scheduleInterval} seconds is too low, setting to 15 seconds` });
16695
+ bootstrap.settings.NationalWeatherServiceSettings.CallbackInterval = 15;
16696
+ scheduleInterval = 15;
16697
+ }
16698
+ bootstrap.cron = new import_croner.Cron(`*/${scheduleInterval} * * * * *`, () => __async(null, null, function* () {
16699
+ yield setCronSchedule();
16700
+ }));
16701
+ bootstrap.cron = new import_croner.Cron(`* * * * * *`, () => __async(null, null, function* () {
16702
+ yield updateNode();
16703
+ yield updateEvents();
16704
+ }));
16705
+ });
16706
+
16707
+ // src/@core/core.stop.ts
16708
+ var stopService = () => __async(null, null, function* () {
16709
+ if (bootstrap.isReady) {
16710
+ bootstrap.isReady = false;
16711
+ if (bootstrap.session_xmpp) {
16712
+ try {
16713
+ yield bootstrap.session_xmpp.stop();
16714
+ } catch (e) {
16715
+ }
16716
+ bootstrap.cache.isConnected = false;
16717
+ bootstrap.cache.sigHault = true;
16718
+ bootstrap.session_xmpp = null;
16719
+ }
16590
16720
  }
16591
- return outTTS;
16592
16721
  });
16593
16722
 
16594
16723
  // src/@core/core.setNode.ts