@atmosx/event-product-parser 3.0.44 → 3.0.47

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 (68) hide show
  1. package/README.md +77 -31
  2. package/SUPPORTED_EVENTS.md +369 -0
  3. package/dist/cjs/index.cjs +681 -403
  4. package/dist/esm/index.mjs +659 -382
  5. package/dist/index.d.mts +54 -25
  6. package/dist/index.d.ts +54 -25
  7. package/package.json +1 -1
  8. package/src/@building/building.attachments.ts +83 -0
  9. package/src/@building/building.enhance.ts +7 -3
  10. package/src/@building/building.office.ts +2 -2
  11. package/src/@building/building.properties.ts +12 -11
  12. package/src/@building/building.signature.ts +11 -11
  13. package/src/@building/building.tags.ts +2 -2
  14. package/src/@building/building.tracking.ts +3 -3
  15. package/src/@building/building.validate.ts +2 -2
  16. package/src/@core/core.createEvent.ts +83 -0
  17. package/src/@dictionaries/{dictionaries.eventActions.ts → dictionaries.actions.ts} +1 -1
  18. package/src/@dictionaries/{dictionaries.eventAwipAbreviations.ts → dictionaries.awips.ts} +1 -1
  19. package/src/@dictionaries/{dictionaries.eventCancelMessages.ts → dictionaries.cancellation.ts} +2 -1
  20. package/src/@dictionaries/{dictionaries.eventCauses.ts → dictionaries.causes.ts} +1 -1
  21. package/src/@dictionaries/{dictionaries.statusCorrelationText.ts → dictionaries.correlations.ts} +1 -1
  22. package/src/@dictionaries/{dictionaries.betterEventNames.ts → dictionaries.enhanced.ts} +13 -2
  23. package/src/@dictionaries/{dictionaries.eventTypes.ts → dictionaries.events.ts} +1 -1
  24. package/src/@dictionaries/{dictionaries.regExp.ts → dictionaries.expressions.ts} +2 -1
  25. package/src/@dictionaries/{dictionaries.hailStrings.ts → dictionaries.hail.ts} +4 -1
  26. package/src/@dictionaries/{dictionaries.officeICAOs.ts → dictionaries.icao.ts} +1 -1
  27. package/src/@dictionaries/{dictionaries.eventsMatchText.ts → dictionaries.matches.ts} +1 -1
  28. package/src/@dictionaries/{dictionaries.eventProducts.ts → dictionaries.products.ts} +1 -1
  29. package/src/@dictionaries/{dictionaries.eventRecords.ts → dictionaries.records.ts} +1 -1
  30. package/src/@dictionaries/{dictionaries.eventSeverity.ts → dictionaries.severity.ts} +1 -1
  31. package/src/@dictionaries/{dictionaries.shapefileLinks.ts → dictionaries.shapefiles.ts} +1 -1
  32. package/src/@dictionaries/dictionaries.states.ts +72 -0
  33. package/src/@dictionaries/{dictionaries.eventStatus.ts → dictionaries.status.ts} +1 -1
  34. package/src/@dictionaries/{dictionaries.eventTags.ts → dictionaries.tags.ts} +1 -1
  35. package/src/@dictionaries/{dictionaries.testSignatures.ts → dictionaries.testing.ts} +3 -2
  36. package/src/@events/events.api.ts +18 -15
  37. package/src/@events/events.text.ts +2 -2
  38. package/src/@events/events.ugc.ts +2 -2
  39. package/src/@manager/manager.mkEvent.ts +3 -3
  40. package/src/@manager/manager.rmEvent.ts +3 -2
  41. package/src/@manager/manager.updateListener.ts +163 -0
  42. package/src/@modules/@database/database.broadcastify.ts +67 -0
  43. package/src/@modules/@database/database.init.ts +14 -1
  44. package/src/@modules/@database/database.shapefiles.ts +3 -6
  45. package/src/@modules/@eas/eas.getCleanDescription.ts +2 -0
  46. package/src/@modules/@eas/eas.getTTS.ts +19 -8
  47. package/src/@modules/@eas/eas.setEasTone.ts +15 -10
  48. package/src/@modules/@stanza/stanza.getAwipsType.ts +2 -2
  49. package/src/@modules/@stanza/stanza.validate.ts +3 -3
  50. package/src/@modules/@utilities/utilities.createHttp.ts +56 -47
  51. package/src/@modules/@utilities/utilities.setCronSchedule.ts +5 -2
  52. package/src/@modules/@xmpp/xmpp.xReconnect.ts +1 -1
  53. package/src/@parsers/@hvtec/hvtec.extract.ts +8 -8
  54. package/src/@parsers/@pvtec/pvtec.extract.ts +12 -12
  55. package/src/@parsers/@text/text.getDescriptionFromProduct.ts +2 -2
  56. package/src/@parsers/@text/text.getEmbed.ts +58 -0
  57. package/src/@parsers/@ugc/ugc.header.ts +3 -3
  58. package/src/@types/type.event.ts +3 -3
  59. package/src/@types/{type.webhook.ts → type.listener.ts} +11 -7
  60. package/src/@types/type.properties.ts +10 -9
  61. package/src/@types/type.settings.ts +13 -6
  62. package/src/bootstrap.ts +13 -6
  63. package/src/index.ts +2 -1
  64. package/test.js +30 -22
  65. package/src/@building/building.outlooks.ts +0 -36
  66. package/src/@manager/manager.createWebhook.ts +0 -129
  67. package/src/@manager/manager.updateWebhooks.ts +0 -49
  68. package/src/@modules/@utilities/utilities.isImageReady.ts +0 -27
package/dist/index.d.mts CHANGED
@@ -1,11 +1,17 @@
1
- type TypeWebhook = {
2
- webhook: string;
3
- title: string;
4
- message: string;
5
- upload: boolean;
6
- eas: boolean;
7
- rate: number;
1
+ type TypeListener = {
8
2
  events: string[];
3
+ webhook?: {
4
+ enabled: boolean;
5
+ destination: string;
6
+ ratelimit: number;
7
+ title: string;
8
+ message: string;
9
+ };
10
+ uploads?: {
11
+ file?: boolean;
12
+ eas?: boolean;
13
+ event?: boolean;
14
+ };
9
15
  };
10
16
 
11
17
  type TypeSettings = {
@@ -37,6 +43,11 @@ type TypeSettings = {
37
43
  CallbackInterval: number;
38
44
  EventsEndpoint: string;
39
45
  };
46
+ BroadcastifySettings: {
47
+ BroadcastifyAttachments: boolean;
48
+ BroadcastifyDatabase: string;
49
+ BroadcastifyTags: string[];
50
+ };
40
51
  GlobalSettings: {
41
52
  EventManagement: boolean;
42
53
  BetterEventNames: boolean;
@@ -46,7 +57,7 @@ type TypeSettings = {
46
57
  ShapefileSkipPoints: number;
47
58
  NodeTTL: number;
48
59
  NodeMinDistance: number;
49
- WebhookSettings?: TypeWebhook;
60
+ ListenerSettings?: TypeListener[];
50
61
  EventFiltering: {
51
62
  ListeningEvents: string[];
52
63
  ListeningICAO: string[];
@@ -57,10 +68,12 @@ type TypeSettings = {
57
68
  NodeLocationFiltering: boolean;
58
69
  IgnoreTestProducts: boolean;
59
70
  };
60
- EASSettings: {
61
- ArchiveTTL: number;
62
- ArchiveDirectory: string;
63
- IntroWavFile: string;
71
+ ArchiveSettings: {
72
+ TTL: number;
73
+ EventDirectory: string;
74
+ TextDirectory: string;
75
+ EasDirectory: string;
76
+ EasToneout: string;
64
77
  };
65
78
  };
66
79
  };
@@ -78,8 +91,9 @@ type TypeAttributes = {
78
91
 
79
92
  type TypeEventProperties = {
80
93
  locations: string;
94
+ locations_array: string[];
81
95
  description: string;
82
- attributes: TypeAttributes;
96
+ attributes?: TypeAttributes;
83
97
  geocode: {
84
98
  office: {
85
99
  name: string;
@@ -90,7 +104,7 @@ type TypeEventProperties = {
90
104
  polygon: string;
91
105
  polygon_generated: boolean;
92
106
  };
93
- parameters: {
107
+ parameters?: {
94
108
  tags: string[];
95
109
  instructions: string;
96
110
  source: string;
@@ -123,13 +137,13 @@ type TypeEventProperties = {
123
137
  max_tops_x100feet: string;
124
138
  pds_watch: boolean;
125
139
  };
126
- spc_parameters: {
127
- spc_number: string;
128
- spc_concerning: string;
129
- spc_max_tornado: string;
130
- spc_max_hail: string;
131
- spc_max_wind: string;
132
- spc_watch_issuance: string;
140
+ discussion_parameters?: {
141
+ discussion_number: string;
142
+ discussion_concerning: string;
143
+ discussion_max_tornado: string;
144
+ discussion_max_hail: string;
145
+ discussion_max_wind: string;
146
+ discussion_watch_issuance: string;
133
147
  };
134
148
  };
135
149
 
@@ -177,8 +191,8 @@ type TypeEvent = {
177
191
  tracking: string;
178
192
  hash?: string;
179
193
  header: string;
180
- vtec: TypePVTEC | null;
181
- hvtec: TypeHVTEC[];
194
+ vtec?: TypePVTEC | null;
195
+ hvtec?: TypeHVTEC[] | null;
182
196
  nodes?: {
183
197
  id?: string | number;
184
198
  coordinates: [number, number];
@@ -194,7 +208,10 @@ type TypeEvent = {
194
208
  issued: string;
195
209
  status: string;
196
210
  }[];
197
- attachments?: string[];
211
+ attachments?: {
212
+ name: string;
213
+ link: string;
214
+ }[];
198
215
  raw: string;
199
216
  };
200
217
  } & TypeEventProperties;
@@ -215,6 +232,7 @@ declare const stopService: () => Promise<void>;
215
232
  interface GenerateEASOptions {
216
233
  message: string;
217
234
  header: string;
235
+ title: string;
218
236
  }
219
237
  declare const setEasTone: (options: GenerateEASOptions) => Promise<string>;
220
238
 
@@ -232,6 +250,17 @@ declare const getEvents: () => any;
232
250
 
233
251
  declare const getNodes: () => any;
234
252
 
253
+ interface CreateEventOptions {
254
+ event: string;
255
+ status: string;
256
+ issued: Date;
257
+ expires: Date;
258
+ locations: string;
259
+ description: string;
260
+ coordinates: number[][];
261
+ }
262
+ declare const createEvent: (options: CreateEventOptions) => void;
263
+
235
264
  declare const getRandomEvent: () => any;
236
265
 
237
266
  type TypeStanza = {
@@ -267,4 +296,4 @@ declare class Manager {
267
296
  trycatch(): void;
268
297
  }
269
298
 
270
- export { Manager, type TypeEvent, clearEvents, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, query, setEasTone, setNode, setSettings, startService, stopService };
299
+ export { Manager, type TypeEvent, clearEvents, createEvent, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, query, setEasTone, setNode, setSettings, startService, stopService };
package/dist/index.d.ts CHANGED
@@ -1,11 +1,17 @@
1
- type TypeWebhook = {
2
- webhook: string;
3
- title: string;
4
- message: string;
5
- upload: boolean;
6
- eas: boolean;
7
- rate: number;
1
+ type TypeListener = {
8
2
  events: string[];
3
+ webhook?: {
4
+ enabled: boolean;
5
+ destination: string;
6
+ ratelimit: number;
7
+ title: string;
8
+ message: string;
9
+ };
10
+ uploads?: {
11
+ file?: boolean;
12
+ eas?: boolean;
13
+ event?: boolean;
14
+ };
9
15
  };
10
16
 
11
17
  type TypeSettings = {
@@ -37,6 +43,11 @@ type TypeSettings = {
37
43
  CallbackInterval: number;
38
44
  EventsEndpoint: string;
39
45
  };
46
+ BroadcastifySettings: {
47
+ BroadcastifyAttachments: boolean;
48
+ BroadcastifyDatabase: string;
49
+ BroadcastifyTags: string[];
50
+ };
40
51
  GlobalSettings: {
41
52
  EventManagement: boolean;
42
53
  BetterEventNames: boolean;
@@ -46,7 +57,7 @@ type TypeSettings = {
46
57
  ShapefileSkipPoints: number;
47
58
  NodeTTL: number;
48
59
  NodeMinDistance: number;
49
- WebhookSettings?: TypeWebhook;
60
+ ListenerSettings?: TypeListener[];
50
61
  EventFiltering: {
51
62
  ListeningEvents: string[];
52
63
  ListeningICAO: string[];
@@ -57,10 +68,12 @@ type TypeSettings = {
57
68
  NodeLocationFiltering: boolean;
58
69
  IgnoreTestProducts: boolean;
59
70
  };
60
- EASSettings: {
61
- ArchiveTTL: number;
62
- ArchiveDirectory: string;
63
- IntroWavFile: string;
71
+ ArchiveSettings: {
72
+ TTL: number;
73
+ EventDirectory: string;
74
+ TextDirectory: string;
75
+ EasDirectory: string;
76
+ EasToneout: string;
64
77
  };
65
78
  };
66
79
  };
@@ -78,8 +91,9 @@ type TypeAttributes = {
78
91
 
79
92
  type TypeEventProperties = {
80
93
  locations: string;
94
+ locations_array: string[];
81
95
  description: string;
82
- attributes: TypeAttributes;
96
+ attributes?: TypeAttributes;
83
97
  geocode: {
84
98
  office: {
85
99
  name: string;
@@ -90,7 +104,7 @@ type TypeEventProperties = {
90
104
  polygon: string;
91
105
  polygon_generated: boolean;
92
106
  };
93
- parameters: {
107
+ parameters?: {
94
108
  tags: string[];
95
109
  instructions: string;
96
110
  source: string;
@@ -123,13 +137,13 @@ type TypeEventProperties = {
123
137
  max_tops_x100feet: string;
124
138
  pds_watch: boolean;
125
139
  };
126
- spc_parameters: {
127
- spc_number: string;
128
- spc_concerning: string;
129
- spc_max_tornado: string;
130
- spc_max_hail: string;
131
- spc_max_wind: string;
132
- spc_watch_issuance: string;
140
+ discussion_parameters?: {
141
+ discussion_number: string;
142
+ discussion_concerning: string;
143
+ discussion_max_tornado: string;
144
+ discussion_max_hail: string;
145
+ discussion_max_wind: string;
146
+ discussion_watch_issuance: string;
133
147
  };
134
148
  };
135
149
 
@@ -177,8 +191,8 @@ type TypeEvent = {
177
191
  tracking: string;
178
192
  hash?: string;
179
193
  header: string;
180
- vtec: TypePVTEC | null;
181
- hvtec: TypeHVTEC[];
194
+ vtec?: TypePVTEC | null;
195
+ hvtec?: TypeHVTEC[] | null;
182
196
  nodes?: {
183
197
  id?: string | number;
184
198
  coordinates: [number, number];
@@ -194,7 +208,10 @@ type TypeEvent = {
194
208
  issued: string;
195
209
  status: string;
196
210
  }[];
197
- attachments?: string[];
211
+ attachments?: {
212
+ name: string;
213
+ link: string;
214
+ }[];
198
215
  raw: string;
199
216
  };
200
217
  } & TypeEventProperties;
@@ -215,6 +232,7 @@ declare const stopService: () => Promise<void>;
215
232
  interface GenerateEASOptions {
216
233
  message: string;
217
234
  header: string;
235
+ title: string;
218
236
  }
219
237
  declare const setEasTone: (options: GenerateEASOptions) => Promise<string>;
220
238
 
@@ -232,6 +250,17 @@ declare const getEvents: () => any;
232
250
 
233
251
  declare const getNodes: () => any;
234
252
 
253
+ interface CreateEventOptions {
254
+ event: string;
255
+ status: string;
256
+ issued: Date;
257
+ expires: Date;
258
+ locations: string;
259
+ description: string;
260
+ coordinates: number[][];
261
+ }
262
+ declare const createEvent: (options: CreateEventOptions) => void;
263
+
235
264
  declare const getRandomEvent: () => any;
236
265
 
237
266
  type TypeStanza = {
@@ -267,4 +296,4 @@ declare class Manager {
267
296
  trycatch(): void;
268
297
  }
269
298
 
270
- export { Manager, type TypeEvent, clearEvents, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, query, setEasTone, setNode, setSettings, startService, stopService };
299
+ export { Manager, type TypeEvent, clearEvents, createEvent, Manager as default, getCleanedEvent, getEventGeometry, getEvents, getNodes, getRandomEvent, query, setEasTone, setNode, setSettings, startService, stopService };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atmosx/event-product-parser",
3
- "version": "3.0.44",
3
+ "version": "3.0.47",
4
4
  "description": "NOAA Weather Wire & NWS API Parser - Built for standalone and Project AtmosphericX Integration.",
5
5
  "main": "dist/cjs/index.cjs",
6
6
  "module": "dist/esm/index.mjs",
@@ -0,0 +1,83 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { bootstrap } from "../bootstrap"
21
+ import { TypeEvent } from "../@types/type.event"
22
+ import { getLatestIssuance } from "../@modules/@utilities/utilities.getLatestIssuance";
23
+ import { dict_states } from "../@dictionaries/dictionaries.states"
24
+ import { dict_expressions } from "../@dictionaries/dictionaries.expressions"
25
+
26
+ interface GetEventAttachmentsResponse {
27
+ name: string
28
+ link: string
29
+ }
30
+
31
+ type BroadcastifyResponse = {
32
+ state: string
33
+ county: string
34
+ feed: string
35
+ type: string
36
+ link: string
37
+ }
38
+
39
+ export const getEventAttachments = (event: TypeEvent): GetEventAttachmentsResponse[] | null => {
40
+ let attachments = [];
41
+ const latestTime = getLatestIssuance();
42
+ const spcNumber = event?.properties?.discussion_parameters?.discussion_number;
43
+ const watchNumber = event?.properties?.watch_parameters?.watch_number;
44
+ const locations = event?.properties?.locations_array;
45
+ const events = [
46
+ { target: "Day 1", attachment: `https://www.spc.noaa.gov/products/outlook/day1otlk_${latestTime}.png` },
47
+ { target: "Day 2", attachment: `https://www.spc.noaa.gov/products/outlook/day2otlk.png` },
48
+ { target: "Day 3", attachment: `https://www.spc.noaa.gov/products/outlook/day3otlk.png` },
49
+ { target: "Mesoscale Discussion", attachment: `https://www.spc.noaa.gov/products/md/mcd${spcNumber}.png` },
50
+ { target: "Tornado Watch", attachment: `https://www.spc.noaa.gov/products/watch/ww${watchNumber}_radar_big.gif` },
51
+ { target: "PDS Tornado Watch", attachment: `https://www.spc.noaa.gov/products/watch/ww${watchNumber}_radar_big.gif` },
52
+ { target: "Severe Thunderstorm Watch", attachment: `https://www.spc.noaa.gov/products/watch/ww${watchNumber}_radar_big.gif` },
53
+ { target: "PDS Severe Thunderstorm Watch", attachment: `https://www.spc.noaa.gov/products/watch/ww${watchNumber}_radar_big.gif` }
54
+ ]
55
+
56
+ if (events.find((e) => e.target === event.properties.event)) {
57
+ attachments.push({ name: `Image: Graphic`, link: events.find((e) => e.target === event.properties.event).attachment });
58
+ }
59
+
60
+ for (const location of locations) {
61
+ if (dict_expressions.location.test(location)) {
62
+ const lines = [`Northern`, `Southern`, `Eastern`, `Western`, `Inland`, `Costal`, `County`]
63
+ const county = location?.split(',')[0]?.trim().replace(new RegExp(`^(${lines.join('|')}) `), '')
64
+ const state = dict_states[location?.split(',')[1]?.trim()]
65
+ const feeds = bootstrap.database.prepare(`SELECT * FROM broadcastify WHERE state = ? AND county = ?`).all(state, county).sort((a, b) => {
66
+ const typeOrder = ['Other', 'Public Safety'];
67
+ const indexA = typeOrder.indexOf(a.type);
68
+ const indexB = typeOrder.indexOf(b.type);
69
+ return indexA - indexB;
70
+ });
71
+ const tags = bootstrap.settings.BroadcastifySettings.BroadcastifyTags;
72
+ const filtered = feeds.filter((feed: BroadcastifyResponse) => tags.includes(feed.type));
73
+ if (filtered.length > 0) {
74
+ filtered.map((filtered: BroadcastifyResponse) => {
75
+ if (!attachments.some((a) => a.link === filtered.link)) {
76
+ attachments.push({ name: `${filtered.type}: ${filtered.feed}`, link: filtered.link });
77
+ }
78
+ });
79
+ }
80
+ }
81
+ }
82
+ return attachments;
83
+ }
@@ -20,7 +20,7 @@
20
20
  import { TypeEvent } from "../@types/type.event";
21
21
  import { TypeSettings } from "../@types/type.settings";
22
22
  import { bootstrap } from "../bootstrap"
23
- import { betterEventNames } from "../@dictionaries/dictionaries.betterEventNames"
23
+ import { dict_enhanced } from "../@dictionaries/dictionaries.enhanced"
24
24
 
25
25
  export const getEventEnhancedName = (event: TypeEvent): string => {
26
26
  const configurations = bootstrap.settings as TypeSettings
@@ -31,9 +31,10 @@ export const getEventEnhancedName = (event: TypeEvent): string => {
31
31
  }
32
32
 
33
33
  const damage = event?.properties?.parameters?.damage_threat
34
- const tornado = event?.properties?.parameters.tornado_threat;
34
+ const tornado = event?.properties?.parameters?.tornado_threat;
35
+ const pdswatch = event?.properties?.watch_parameters?.pds_watch;
35
36
  const description = event?.properties?.description?.toLowerCase()
36
- for (const [eventKey, eventConfig] of Object.entries(betterEventNames)) {
37
+ for (const [eventKey, eventConfig] of Object.entries(dict_enhanced)) {
37
38
  if (eventKey !== name) continue;
38
39
  for (const [paramKey, paramValue] of Object.entries(eventConfig)) {
39
40
  let matches = true;
@@ -46,6 +47,9 @@ export const getEventEnhancedName = (event: TypeEvent): string => {
46
47
  if (paramValue?.tornado) {
47
48
  if (paramValue.tornado !== tornado) matches = false;
48
49
  }
50
+ if (paramValue?.pdswatch) {
51
+ if (paramValue.pdswatch !== pdswatch) matches = false;
52
+ }
49
53
  if (matches) {
50
54
  name = paramKey;
51
55
  break;
@@ -19,7 +19,7 @@
19
19
 
20
20
  import { TypeAttributes } from "../@types/type.attributes";
21
21
  import { TypePVTEC } from "../@types/type.pvtec";
22
- import { officeICAOs } from "../@dictionaries/dictionaries.officeICAOs";
22
+ import { dict_icao } from "../@dictionaries/dictionaries.icao";
23
23
 
24
24
  interface GetOfficeOptions {
25
25
  attributes: TypeAttributes
@@ -38,6 +38,6 @@ export const getEventOffice = (options: GetOfficeOptions): GetOfficeResponse =>
38
38
  (options.organization != null ?
39
39
  (Array.isArray(options.organization) ? options.organization?.[0] : options.organization)
40
40
  : null));
41
- const name = officeICAOs?.[office] ?? null;
41
+ const name = dict_icao?.[office] ?? null;
42
42
  return { office, name };
43
43
  }
@@ -22,7 +22,7 @@ import { TypeAttributes } from "../@types/type.attributes";
22
22
  import { TypeUGC } from "../@types/type.ugc";
23
23
  import { TypePVTEC } from "../@types/type.pvtec";
24
24
  import { TypeHVTEC } from "../@types/type.hvtec";
25
- import { regExp } from "../@dictionaries/dictionaries.regExp";
25
+ import { dict_expressions } from "../@dictionaries/dictionaries.expressions";
26
26
  import { getDescriptionFromProduct } from "../@parsers/@text/text.getDescriptionFromProduct";
27
27
  import { getPolygonFromProduct } from "../@parsers/@text/text.getPolygonFromProduct";
28
28
  import { getTextFromProduct } from "../@parsers/@text/text.getTextFromProduct";
@@ -38,10 +38,11 @@ interface GetPropertiesOptions {
38
38
  }
39
39
 
40
40
  export const properties = (options: GetPropertiesOptions): TypeEventProperties => {
41
- const organization = options.message.match(regExp.wmo)?.[0] ?? null
41
+ const organization = options.message.match(dict_expressions.wmo)?.[0] ?? null
42
42
  const polygons = getPolygonFromProduct(options.message)
43
43
  const properties = {
44
44
  locations: options?.ugc?.locations?.join(`; `) ?? null,
45
+ locations_array: options?.ugc?.locations ?? [],
45
46
  description: getDescriptionFromProduct({ message: options.message, handle: options?.pVtec?.vtec ?? null }),
46
47
  attributes: options.attributes,
47
48
  geocode: {
@@ -65,16 +66,16 @@ export const properties = (options: GetPropertiesOptions): TypeEventProperties =
65
66
  wind_threat: getTextFromProduct({ message: options.message, find: [`WIND THREAT...`]}) ?? null,
66
67
  hail_threat: getTextFromProduct({ message: options.message, find: [`HAIL THREAT...`], removal: []}) ?? null,
67
68
  },
68
- spc_parameters: {
69
- spc_number: getTextFromProduct({ message: options.message, find: [`Mesoscale Discussion `], removal: [`Mesoscale Discussion`, `Number`, `...`] }) ?? null,
70
- spc_concerning: getTextFromProduct({ message: options.message, find: [`Concerning...`] }) ?? null,
71
- spc_max_tornado: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
72
- spc_max_hail: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
73
- spc_max_wind: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
74
- spc_watch_issuance: getTextFromProduct({ message: options.message, find: [`Probability of Watch Issuance...`], removal: [`percent`]}) ?? null,
69
+ discussion_parameters: {
70
+ discussion_number: getTextFromProduct({ message: options.message, find: [`Mesoscale Discussion `], removal: [`Mesoscale Discussion`, `Number`, `...`] })?.toString()?.padStart(4, "0") ?? null,
71
+ discussion_concerning: getTextFromProduct({ message: options.message, find: [`Concerning...`] }) ?? null,
72
+ discussion_max_tornado: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
73
+ discussion_max_hail: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
74
+ discussion_max_wind: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
75
+ discussion_watch_issuance: getTextFromProduct({ message: options.message, find: [`Probability of Watch Issuance...`], removal: [`percent`]}) ?? null,
75
76
  },
76
77
  watch_parameters: {
77
- watch_number: getTextFromProduct({ message: options.message, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim() ?? null,
78
+ watch_number: (options?.pVtec?.is_watch) && (getTextFromProduct({ message: options.message, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim()?.toString()?.padStart(4, "0") ?? options?.pVtec?.tracking?.slice(-4)?.toString()?.padStart(4, "0") ?? null),
78
79
  watch_type: options.message.includes(`TORNADO WATCH`) ? `Tornado` : options?.message.includes(`SEVERE`) ? `Severe` : null,
79
80
  additional_tornadoes_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
80
81
  strong_tornadoes_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
@@ -85,7 +86,7 @@ export const properties = (options: GetPropertiesOptions): TypeEventProperties =
85
86
  max_hail_in: getTextFromProduct({ message: options.message, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] }) ?? null,
86
87
  max_wind_surface: getTextFromProduct({ message: options.message, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] }) ?? null,
87
88
  max_tops_x100feet: getTextFromProduct({ message: options.message, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] }) ?? null,
88
- pds_watch: (getTextFromProduct({ message: options.message, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`)
89
+ pds_watch: (getTextFromProduct({ message: options.message, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES` ? true : null)
89
90
  }
90
91
  }
91
92
  if (isNaN(Number(properties.watch_parameters.watch_number))) {
@@ -18,23 +18,23 @@
18
18
  */
19
19
 
20
20
  import { TypeEvent } from "../@types/type.event";
21
- import { statusCorrelationText } from "../@dictionaries/dictionaries.statusCorrelationText";
22
- import { eventCancelMessages } from "../@dictionaries/dictionaries.eventCancelMessages";
23
- import { testSignatures} from "../@dictionaries/dictionaries.testSignatures"
24
- import { eventProducts } from "../@dictionaries/dictionaries.eventProducts";
25
- import { hailStrings } from "../@dictionaries/dictionaries.hailStrings"
21
+ import { dict_correlations } from "../@dictionaries/dictionaries.correlations";
22
+ import { dict_cancellation } from "../@dictionaries/dictionaries.cancellation";
23
+ import { dict_testing} from "../@dictionaries/dictionaries.testing"
24
+ import { dict_products } from "../@dictionaries/dictionaries.products";
25
+ import { dict_hail } from "../@dictionaries/dictionaries.hail"
26
26
 
27
27
 
28
28
  export const getEventSignature = (event: TypeEvent): TypeEvent => {
29
29
  const properties = event?.properties;
30
30
  const vtec = event?.properties?.metadata?.vtec
31
- const status = statusCorrelationText
31
+ const status = dict_correlations
32
32
  .find((c: { type: string }) => c.type === properties?.status);
33
- const csig = eventCancelMessages.find(sig => properties.description.toLowerCase().includes(sig.toLowerCase()));
33
+ const csig = dict_cancellation.find(sig => properties.description.toLowerCase().includes(sig.toLowerCase()));
34
34
  properties.status_metadata = { ...properties.status_metadata, is_issued: true, is_test: false};
35
35
 
36
- if (properties.parameters.estimated_hail_size) {
37
- properties.parameters.estimated_hail_size += ` (${hailStrings[properties.parameters.estimated_hail_size] ?? '--'})`
36
+ if (properties?.parameters?.estimated_hail_size) {
37
+ properties.parameters.estimated_hail_size += ` (${dict_hail[properties?.parameters?.estimated_hail_size] ?? '--'})`
38
38
  }
39
39
 
40
40
  if (status) {
@@ -46,8 +46,8 @@ export const getEventSignature = (event: TypeEvent): TypeEvent => {
46
46
  }
47
47
 
48
48
  const getProduct = vtec?.vtec?.split(`.`)[0]?.replace(`/`, ``)
49
- const isTestProduct = eventProducts[getProduct] == `Test Product`
50
- if (isTestProduct || testSignatures.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase()) ?? properties?.parameters?.instructions?.toLowerCase().includes(sig.toLowerCase()))) {
49
+ const isTestProduct = dict_products[getProduct] == `Test Product`
50
+ if (isTestProduct || dict_testing.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase()) ?? properties?.parameters?.instructions?.toLowerCase().includes(sig.toLowerCase()))) {
51
51
  properties.status_metadata = { ...properties.status_metadata, is_test: true }
52
52
  }
53
53
 
@@ -17,8 +17,8 @@
17
17
 
18
18
  */
19
19
 
20
- import { eventTags } from "../@dictionaries/dictionaries.eventTags";
20
+ import { dict_tags } from "../@dictionaries/dictionaries.tags";
21
21
 
22
22
  export const getEventTags = (message: string): string[] => {
23
- return Object.entries(eventTags).filter(([key]) => message?.toLowerCase().includes(key.toLowerCase())).map(([, value]) => value)
23
+ return Object.entries(dict_tags).filter(([key]) => message?.toLowerCase().includes(key.toLowerCase())).map(([, value]) => value)
24
24
  }
@@ -52,7 +52,7 @@ export const getEventTracking = (options: GetTrackingOptions): string => {
52
52
  if (options.type === `API`) {
53
53
  if (options.vtec) {
54
54
  const vtecValue = Array.isArray(options.vtec)
55
- ? options.vtec[0] : options.vtec;
55
+ ? options.vtec[0].vtec : options.vtec?.vtec;
56
56
  const splitPVTEC = vtecValue.split('.');
57
57
  return `${splitPVTEC[2]}.${splitPVTEC[3]}.${splitPVTEC[4]}.${splitPVTEC[5]}`;
58
58
  }
@@ -60,9 +60,9 @@ export const getEventTracking = (options: GetTrackingOptions): string => {
60
60
  const station = wmoMatch?.[2] ?? 'N/A';
61
61
  if (options.organization.featureId) {
62
62
  const idMatch = options.organization.featureId.match(/([a-f0-9]+)\.(\d+)\.(\d+)$/);
63
- return `${station}.${idMatch?.[1] ?? 'N/A'}`;
63
+ return `${station}.${idMatch?.[0]?.replace(/\./g, '') ?? 'N/A'}`;
64
64
  }
65
65
  const id = wmoMatch?.[1] ?? 'N/A';
66
- return `${station}.${id}`;
66
+ return `${station}.${id?.replace(/\./g, '') ?? 'N/A'}`;
67
67
  }
68
68
  }
@@ -26,7 +26,7 @@ import { getEventSignature } from "./building.signature"
26
26
  import { mkEvent } from "../@manager/manager.mkEvent";
27
27
  import { rmEvent } from "../@manager/manager.rmEvent";
28
28
  import { getEventGeometry } from "./building.geometry";
29
- import { getEventAttachments } from "./building.outlooks";
29
+ import { getEventAttachments } from "./building.attachments";
30
30
  import { updateNode } from "../@manager/manager.updateNodes";
31
31
  import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
32
32
 
@@ -67,7 +67,7 @@ export const validateEvents = async (events: TypeEvent[]): Promise<void> => {
67
67
  return false;
68
68
  }
69
69
 
70
- if (properties.metadata?.vtec?.is_watch) {
70
+ if (properties.metadata?.vtec?.is_watch && properties.metadata.source != `events.api`) {
71
71
  const isSPC = properties.metadata?.vtec?.prediction_center;
72
72
  setEventEmit({ event: isSPC ? `onStormPredictionWatch` : `onNonStormPredictionWatch`, metadata: define })
73
73
  if (bools?.SPCWatchesOnly && !isSPC) {