@atmosx/event-product-parser 2.0.15 → 3.0.0

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 (116) hide show
  1. package/README.md +4 -237
  2. package/dist/cjs/index.cjs +2233 -3100
  3. package/dist/esm/index.mjs +2233 -3103
  4. package/package.json +3 -3
  5. package/src/@building/building.clean.ts +30 -0
  6. package/src/@building/building.create.ts +42 -0
  7. package/src/@building/building.enhance.ts +56 -0
  8. package/src/@building/building.geometry.ts +42 -0
  9. package/src/@building/building.headers.ts +37 -0
  10. package/src/@building/building.office.ts +43 -0
  11. package/src/@building/building.polygon.ts +71 -0
  12. package/src/@building/building.properties.ts +89 -0
  13. package/src/@building/building.signature.ts +78 -0
  14. package/src/@building/building.tags.ts +24 -0
  15. package/src/@building/building.tracking.ts +68 -0
  16. package/src/@building/building.validate.ts +132 -0
  17. package/src/@core/core.callback.ts +39 -0
  18. package/src/@core/core.getEvents.ts +25 -0
  19. package/src/@core/core.getNodes.ts +25 -0
  20. package/src/@core/core.listener.ts +24 -0
  21. package/src/@core/core.setNode.ts +81 -0
  22. package/src/@core/core.start.ts +54 -0
  23. package/src/@core/core.stop.ts +32 -0
  24. package/src/@dictionaries/dictionaries.betterEventNames.ts +85 -0
  25. package/src/@dictionaries/dictionaries.eventActions.ts +28 -0
  26. package/src/@dictionaries/{awips.ts → dictionaries.eventAwipAbreviations.ts} +12 -6
  27. package/src/@dictionaries/dictionaries.eventCancelMessages.ts +29 -0
  28. package/src/@dictionaries/dictionaries.eventCauses.ts +36 -0
  29. package/src/@dictionaries/dictionaries.eventProducts.ts +25 -0
  30. package/src/@dictionaries/dictionaries.eventRecords.ts +25 -0
  31. package/src/@dictionaries/dictionaries.eventSeverity.ts +27 -0
  32. package/src/@dictionaries/dictionaries.eventStatus.ts +31 -0
  33. package/src/@dictionaries/{signatures.ts → dictionaries.eventTags.ts} +13 -68
  34. package/src/@dictionaries/dictionaries.eventTypes.ts +82 -0
  35. package/src/@dictionaries/dictionaries.eventsOffshore.ts +31 -0
  36. package/src/@dictionaries/dictionaries.hailStrings.ts +31 -0
  37. package/src/@dictionaries/{icao.ts → dictionaries.officeICAOs.ts} +13 -6
  38. package/src/@dictionaries/dictionaries.regExp.ts +28 -0
  39. package/src/@dictionaries/dictionaries.shapefileLinks.ts +36 -0
  40. package/src/@dictionaries/dictionaries.statusCorrelationText.ts +40 -0
  41. package/src/@dictionaries/dictionaries.test_signatures.ts +23 -0
  42. package/src/@dictionaries/dictionaries.transcribedMessageReplacements.ts +68 -0
  43. package/src/@events/events.api.ts +113 -0
  44. package/src/@events/events.text.ts +79 -0
  45. package/src/@events/events.ugc.ts +83 -0
  46. package/src/@events/events.vtec.ts +87 -0
  47. package/src/@manager/manager.mkEvent.ts +79 -0
  48. package/src/@manager/manager.rmEvent.ts +44 -0
  49. package/src/@manager/manager.setHash.ts +37 -0
  50. package/src/@manager/manager.updateNodes.ts +51 -0
  51. package/src/@modules/@database/database.cache.ts +48 -0
  52. package/src/@modules/@database/database.init.ts +45 -0
  53. package/src/@modules/@database/database.shapefiles.ts +97 -0
  54. package/src/@modules/@database/database.stanza.ts +47 -0
  55. package/src/@modules/@stanza/stanza.getAwipsType.ts +46 -0
  56. package/src/@modules/@stanza/stanza.validate.ts +50 -0
  57. package/src/@modules/@utilities/utilities.createHttp.ts +75 -0
  58. package/src/@modules/@utilities/utilities.getFormattedTime.ts +43 -0
  59. package/src/@modules/@utilities/utilities.getSettings.ts +25 -0
  60. package/src/@modules/@utilities/utilities.getShapeNearestPoint.ts +114 -0
  61. package/src/@modules/@utilities/utilities.setCronSchedule.ts +38 -0
  62. package/src/@modules/@utilities/utilities.setEventEmit.ts +41 -0
  63. package/src/@modules/@utilities/utilities.setListener.ts +30 -0
  64. package/src/@modules/@utilities/utilities.setSettings.ts +42 -0
  65. package/src/@modules/@utilities/utilities.setSleep.ts +33 -0
  66. package/src/@modules/@utilities/utilities.setTimeoutAction.ts +59 -0
  67. package/src/@modules/@utilities/utilities.setWarning.ts +34 -0
  68. package/src/@modules/@xmpp/xmpp.xDeploy.ts +58 -0
  69. package/src/@modules/@xmpp/xmpp.xError.ts +38 -0
  70. package/src/@modules/@xmpp/xmpp.xOffline.ts +38 -0
  71. package/src/@modules/@xmpp/xmpp.xOnline.ts +61 -0
  72. package/src/@modules/@xmpp/xmpp.xReconnect.ts +59 -0
  73. package/src/@modules/@xmpp/xmpp.xStanza.ts +63 -0
  74. package/src/@parsers/@hvtec/hvtec.extract.ts +40 -0
  75. package/src/@parsers/@pvtec/pvtec.expires.ts +26 -0
  76. package/src/@parsers/@pvtec/pvtec.extract.ts +50 -0
  77. package/src/@parsers/@text/text.getDescriptionFromProduct.ts +53 -0
  78. package/src/@parsers/@text/text.getPolygonFromProduct.ts +32 -0
  79. package/src/@parsers/@text/text.getTextFromProduct.ts +43 -0
  80. package/src/@parsers/@text/text.getXML.ts +61 -0
  81. package/src/@parsers/@ugc/ugc.coordinates.ts +110 -0
  82. package/src/@parsers/@ugc/ugc.expiry.ts +32 -0
  83. package/src/@parsers/@ugc/ugc.extract.ts +37 -0
  84. package/src/@parsers/@ugc/ugc.header.ts +30 -0
  85. package/src/@parsers/@ugc/ugc.locations.ts +29 -0
  86. package/src/@parsers/@ugc/ugc.zones.ts +52 -0
  87. package/src/@types/type.event.ts +67 -0
  88. package/src/@types/type.properties.ts +75 -0
  89. package/src/@types/types.attributes.ts +28 -0
  90. package/src/@types/types.compiled.ts +35 -0
  91. package/src/@types/types.hash.ts +24 -0
  92. package/src/@types/types.hvtec.ts +25 -0
  93. package/src/@types/types.pvtec.ts +29 -0
  94. package/src/@types/types.settings.ts +71 -0
  95. package/src/@types/types.stanza.ts +37 -0
  96. package/src/@types/types.ugc.ts +24 -0
  97. package/src/bootstrap.ts +82 -164
  98. package/src/index.ts +48 -216
  99. package/test.js +65 -49
  100. package/src/@dictionaries/events.ts +0 -168
  101. package/src/@parsers/@events/api.ts +0 -146
  102. package/src/@parsers/@events/cap.ts +0 -123
  103. package/src/@parsers/@events/text.ts +0 -104
  104. package/src/@parsers/@events/ugc.ts +0 -107
  105. package/src/@parsers/@events/vtec.ts +0 -76
  106. package/src/@parsers/events.ts +0 -392
  107. package/src/@parsers/hvtec.ts +0 -46
  108. package/src/@parsers/pvtec.ts +0 -72
  109. package/src/@parsers/stanza.ts +0 -97
  110. package/src/@parsers/text.ts +0 -165
  111. package/src/@parsers/ugc.ts +0 -247
  112. package/src/@submodules/database.ts +0 -200
  113. package/src/@submodules/eas.ts +0 -490
  114. package/src/@submodules/utils.ts +0 -184
  115. package/src/@submodules/xmpp.ts +0 -142
  116. package/src/types.ts +0 -259
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atmosx/event-product-parser",
3
- "version": "2.0.015",
3
+ "version": "3.0.0",
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",
@@ -11,7 +11,7 @@
11
11
  },
12
12
  "scripts": {
13
13
  "start": "cd ./test && node ./index.js",
14
- "build": "tsup && cd ./test && node ./index.js",
14
+ "build": "tsup && cd ./test && node ./index.js",
15
15
  "publish": "tsup && npm publish --access public",
16
16
  "publish-beta": "tsup && npm publish --tag beta --access public"
17
17
  },
@@ -33,11 +33,11 @@
33
33
  "homepage": "https://github.com/AtmosphericX/event-product-parser#readme",
34
34
  "dependencies": {
35
35
  "@xmpp/client": "0.14.0",
36
- "axios": "1.13.2",
37
36
  "better-sqlite3": "11.10.0",
38
37
  "croner": "10.0.1",
39
38
  "jszip": "3.10.1",
40
39
  "polygon-clipping": "0.15.7",
40
+ "request": "^2.88.2",
41
41
  "say": "0.16.0",
42
42
  "shapefile": "0.6.6",
43
43
  "typescript": "5.9.3",
@@ -0,0 +1,30 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ export const getCleanedEvent = <T extends Record<string, any>>(event: T): T => {
21
+ for (const key of Object.keys(event)) {
22
+ const value = event[key];
23
+ if (value === null || value === undefined) {
24
+ delete event[key];
25
+ } else if (typeof value === "object" && value !== null && !Array.isArray(value)) {
26
+ (event as Record<string, any>)[key] = getCleanedEvent(value as Record<string, any>) as any;
27
+ }
28
+ }
29
+ return event;
30
+ };
@@ -0,0 +1,42 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { TypeStanzaCompiled } from "../@types/types.compiled"
21
+ import { TypeSettings } from "../@types/types.settings"
22
+ import { bootstrap } from "../bootstrap"
23
+ import { text } from "../@events/events.text"
24
+ import { ugc } from "../@events/events.ugc"
25
+ import { vtec } from "../@events/events.vtec"
26
+ import { api } from "../@events/events.api"
27
+
28
+ export const createEvent = async (stanza: TypeStanzaCompiled): Promise<void | string> => {
29
+ const settings = bootstrap.settings as TypeSettings
30
+ const StanzaSettings = settings.NOAAWeatherWireServiceSettings.StanzaSettings;
31
+
32
+ const isVtecEvent = (stanza.isVTEC && stanza.isUGC)
33
+ const isUgcEvent = (!stanza.isVTEC && stanza.isUGC)
34
+ const isTextEvent = (!stanza.isVTEC && !stanza.isUGC)
35
+ const isNWWS = (stanza.isNWWS)
36
+
37
+ if (!isNWWS) return await api(stanza)
38
+ if (!StanzaSettings.DisableVTEC && isVtecEvent) return await vtec(stanza)
39
+ if (!StanzaSettings.DisableUGC && isUgcEvent) return await ugc(stanza);
40
+ if (!StanzaSettings.DisableText && isTextEvent) return await text(stanza);
41
+ return 'nothing picked';
42
+ }
@@ -0,0 +1,56 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { TypeEvent } from "../@types/type.event";
21
+ import { TypeSettings } from "../@types/types.settings";
22
+ import { bootstrap } from "../bootstrap"
23
+ import { betterEventNames } from "../@dictionaries/dictionaries.betterEventNames"
24
+
25
+ export const getEventEnhancedName = (event: TypeEvent): string => {
26
+ const configurations = bootstrap.settings as TypeSettings
27
+ let name = event?.properties?.event
28
+
29
+ if (!configurations?.GlobalSettings?.BetterEventNames) {
30
+ return name
31
+ }
32
+
33
+ const damage = event?.properties?.parameters?.damage_threat
34
+ const tornado = event?.properties?.parameters.tornado_threat;
35
+ const description = event?.properties?.description?.toLowerCase()
36
+ for (const [eventKey, eventConfig] of Object.entries(betterEventNames)) {
37
+ if (eventKey !== name) continue;
38
+ for (const [paramKey, paramValue] of Object.entries(eventConfig)) {
39
+ let matches = true;
40
+ if (paramValue?.description) {
41
+ if (!description.includes(paramValue.description.toLowerCase())) matches = false;
42
+ }
43
+ if (paramValue?.damage) {
44
+ if (paramValue.damage !== damage) matches = false;
45
+ }
46
+ if (paramValue?.tornado) {
47
+ if (paramValue.tornado !== tornado) matches = false;
48
+ }
49
+ if (matches) {
50
+ name = paramKey;
51
+ break;
52
+ }
53
+ }
54
+ }
55
+ return name;
56
+ }
@@ -0,0 +1,42 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { getSettings } from "../@modules/@utilities/utilities.getSettings";
21
+ import { TypeSettings } from "../@types/types.settings"
22
+ import { TypeEvent } from "../@types/type.event"
23
+ import { getZonePolygon } from "../@parsers/@ugc/ugc.coordinates";
24
+
25
+ interface GetGeometryResponse {
26
+ type: `Polygon` | `MultiPolygon`
27
+ coordinates: any[]
28
+ }
29
+
30
+ export const getEventGeometry = async (event: TypeEvent): Promise<GetGeometryResponse> => {
31
+ const settings = getSettings() as TypeSettings
32
+ const generated = event?.properties?.geocode?.polygon ?? null;
33
+ const ugc = event?.properties?.geocode?.ugc ?? null;
34
+ let geo: GetGeometryResponse = {
35
+ type: `Polygon`,
36
+ coordinates: generated != null ? JSON.parse(Buffer.from(generated, 'base64').toString('utf-8')) : null
37
+ }
38
+ if (settings.GlobalSettings.UseShapefileCoordinates && generated == null && ugc != null) {
39
+ geo = await getZonePolygon({zones: ugc, isUnion: false})
40
+ }
41
+ return geo;
42
+ }
@@ -0,0 +1,37 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { TypePVTEC } from "../@types/types.pvtec";
21
+ import { TypeEventProperties } from "../@types/type.properties";
22
+
23
+ interface GetHeaderOptions {
24
+ properties: TypeEventProperties
25
+ vtec?: TypePVTEC
26
+ getType: {
27
+ type: string
28
+ prefix: string
29
+ }
30
+ }
31
+
32
+ export const getEventHeader = (options: GetHeaderOptions): string => {
33
+ const properties = options.properties
34
+ const vtec = options.vtec ?? null
35
+ const ugc = properties.geocode.ugc != null ? properties.geocode.ugc.join(`-`) : `0`;
36
+ return `ZCZC-ATMOSX-${options.getType.prefix}-${ugc}-${vtec?.status ?? `Issued`}-${new Date().toISOString().replace(/[-:]/g, '').split('.')[0]}-${properties.geocode.office.office ?? `KWNS`}`
37
+ }
@@ -0,0 +1,43 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { TypeAttributes } from "../@types/types.attributes";
21
+ import { TypePVTEC } from "../@types/types.pvtec";
22
+ import { officeICAOs } from "../@dictionaries/dictionaries.officeICAOs";
23
+
24
+ interface GetOfficeOptions {
25
+ attributes: TypeAttributes
26
+ organization: string
27
+ pVtec: TypePVTEC
28
+ }
29
+
30
+ interface GetOfficeResponse {
31
+ office: string | null
32
+ name: string | null
33
+ }
34
+
35
+ export const getEventOffice = (options: GetOfficeOptions): GetOfficeResponse => {
36
+ const office = options.pVtec != null
37
+ ? options.pVtec?.tracking?.split(`-`)[0] : (options.attributes?.cccc ||
38
+ (options.organization != null ?
39
+ (Array.isArray(options.organization) ? options.organization?.[0] : options.organization)
40
+ : null));
41
+ const name = officeICAOs?.[office] ?? null;
42
+ return { office, name };
43
+ }
@@ -0,0 +1,71 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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
+
21
+ import { TypeEvent } from "../@types/type.event"
22
+ import { getEventGeometry } from "./building.geometry"
23
+ import { bootstrap } from "../bootstrap"
24
+ import { getShapeNearestPoint } from "../@modules/@utilities/utilities.getShapeNearestPoint"
25
+
26
+ interface GetEventNodesResponse {
27
+ nodes: {
28
+ id?: string | number
29
+ coordinates: [number, number]
30
+ nearest: [number, number]
31
+ miles: number | null
32
+ kilometers: number | null
33
+ proximity: boolean
34
+ }[]
35
+ filtered: boolean
36
+ updated: number
37
+ }
38
+
39
+ export const getEventNodes = async (event: TypeEvent): Promise<GetEventNodesResponse> => {
40
+ const metadata = { nodes: [], proximity: false, filtered: false }
41
+ const geometry = await getEventGeometry(event);
42
+ if (!geometry || !geometry.coordinates) {
43
+ return { nodes: [], filtered: false, updated: Date.now() }
44
+ }
45
+ const nodes = bootstrap.cache.nodes.features;
46
+ for (const node of nodes) {
47
+ const [longitude, latitude] = node.geometry.coordinates;
48
+ const getPoint = getShapeNearestPoint(geometry.coordinates, [longitude, latitude])
49
+ const miles = getPoint.distance ?? null;
50
+ const kilometers = Number((miles * 1.609344).toFixed(3));
51
+
52
+ const info = {
53
+ id: node.properties?.identifier,
54
+ coordinates: [longitude, latitude],
55
+ nearest: getPoint.point,
56
+ miles,
57
+ kilometers,
58
+ proximity: getPoint.proximity
59
+ }
60
+ metadata.nodes.push(info)
61
+ if (bootstrap.settings.GlobalSettings.EventFiltering.NodeLocationFiltering && miles < bootstrap.settings.GlobalSettings.NodeMinDistance) {
62
+ metadata.proximity = true;
63
+ info.proximity = true;
64
+ }
65
+ }
66
+ return {
67
+ nodes: metadata.nodes,
68
+ filtered: metadata.proximity,
69
+ updated: Date.now()
70
+ }
71
+ }
@@ -0,0 +1,89 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { TypeEventProperties } from "../@types/type.properties";
21
+ import { TypeAttributes } from "../@types/types.attributes";
22
+ import { TypeUGC } from "../@types/types.ugc";
23
+ import { TypePVTEC } from "../@types/types.pvtec";
24
+ import { TypeHVTEC } from "../@types/types.hvtec";
25
+ import { regExp } from "../@dictionaries/dictionaries.regExp";
26
+ import { getDescriptionFromProduct } from "../@parsers/@text/text.getDescriptionFromProduct";
27
+ import { getPolygonFromProduct } from "../@parsers/@text/text.getPolygonFromProduct";
28
+ import { getTextFromProduct } from "../@parsers/@text/text.getTextFromProduct";
29
+ import { getEventOffice } from "./building.office";
30
+ import { getEventTags } from "./building.tags";
31
+
32
+ interface GetPropertiesOptions {
33
+ message: string
34
+ attributes: TypeAttributes
35
+ ugc?: TypeUGC
36
+ pVtec?: TypePVTEC
37
+ hVtec?: TypeHVTEC
38
+ }
39
+
40
+ export const properties = (options: GetPropertiesOptions): TypeEventProperties => {
41
+ const organization = options.message.match(regExp.wmo)?.[0] ?? null
42
+ const polygons = getPolygonFromProduct(options.message)
43
+ return {
44
+ locations: options?.ugc?.locations?.join(`; `) ?? null,
45
+ description: getDescriptionFromProduct({ message: options.message, handle: options?.pVtec?.vtec ?? null }),
46
+ attributes: options.attributes,
47
+ geocode: {
48
+ office: getEventOffice({ attributes: options.attributes, organization: organization, pVtec: options.pVtec }),
49
+ organization: organization,
50
+ ugc: options?.ugc?.zones ?? [],
51
+ polygon: polygons.length > 0 ? Buffer.from(JSON.stringify([polygons])).toString('base64') : null,
52
+ polygon_generated: polygons.length > 0 ? true : false
53
+ },
54
+ parameters: {
55
+ tags: getEventTags(options.message),
56
+ instructions: getTextFromProduct({ message: options.message, find: [`For your protection`, `do not`, `use extreme caution`], append: `...`, removal: [`.`]}) ?? null,
57
+ source: getTextFromProduct({ message: options.message, find: [`SOURCE...`], removal: [`.`]}) ?? null,
58
+ hazards: getTextFromProduct({ message: options.message, find: [`HAZARD...`], removal: [`.`]}) ?? null,
59
+ impacts: getTextFromProduct({ message: options.message, find: [`IMPACT...`], removal: [`.`]}) ?? null,
60
+ estimated_hail_size: getTextFromProduct({ message: options.message, find: [`MAX HAIL SIZE...`, `HAIL...`], removal: ['in']}) ?? null,
61
+ estimated_wind_gusts: getTextFromProduct({ message: options.message, find: [`MAX WIND GUST...`, `WIND...`]}) ?? null,
62
+ damage_threat: getTextFromProduct({ message: options.message, find: [`DAMAGE THREAT...`], removal: []}) ?? null,
63
+ tornado_threat: getTextFromProduct({ message: options.message, find: [`TORNADO...`, `WATERSPOUT...`] }) ?? null,
64
+ flood_threat: getTextFromProduct({ message: options.message, find: [`FLASH FLOOD...`]}) ?? null,
65
+ wind_threat: getTextFromProduct({ message: options.message, find: [`WIND THREAT...`]}) ?? null,
66
+ hail_threat: getTextFromProduct({ message: options.message, find: [`HAIL THREAT...`], removal: []}) ?? null,
67
+ },
68
+ spc_parameters: {
69
+ spc_max_tornado: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
70
+ spc_max_hail: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
71
+ spc_max_wind: getTextFromProduct({ message: options.message, find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
72
+ spc_watch_issuance: getTextFromProduct({ message: options.message, find: [`Probability of Watch Issuance...`], removal: [`percent`]}) ?? null,
73
+ },
74
+ watch_parameters: {
75
+ watch_number: getTextFromProduct({ message: options.message, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim() ?? null,
76
+ watch_type: options.message.includes(`TORNADO WATCH`) ? `Tornado` : options?.message.includes(`SEVERE`) ? `Severe` : null,
77
+ additional_tornadoes_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
78
+ strong_tornadoes_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
79
+ severe_wind_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
80
+ severe_hail_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
81
+ hail_2in_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] }) ?? null,
82
+ combined_hail_wind_probability: getTextFromProduct({ message: options.message, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
83
+ max_hail_in: getTextFromProduct({ message: options.message, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] }) ?? null,
84
+ max_wind_surface: getTextFromProduct({ message: options.message, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] }) ?? null,
85
+ max_tops_x100feet: getTextFromProduct({ message: options.message, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] }) ?? null,
86
+ pds_watch: (getTextFromProduct({ message: options.message, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`)
87
+ }
88
+ }
89
+ }
@@ -0,0 +1,78 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { TypeEvent } from "../@types/type.event";
21
+ import { statusCorrelationText } from "../@dictionaries/dictionaries.statusCorrelationText";
22
+ import { eventCancelMessages } from "../@dictionaries/dictionaries.eventCancelMessages";
23
+ import { test_signatures} from "../@dictionaries/dictionaries.test_signatures"
24
+ import { eventProducts } from "../@dictionaries/dictionaries.eventProducts";
25
+ import { hailStrings } from "../@dictionaries/dictionaries.hailStrings"
26
+ import { getFormattedTime } from "../@modules/@utilities/utilities.getFormattedTime";
27
+
28
+
29
+ /*
30
+ export const hailStrings: Record<string, string> = {
31
+ "0.75": "Penny",
32
+ "0.88": "Nickel",
33
+ "1.00": "Quarter",
34
+ "1.25": "Half Dollar",
35
+ "1.50": "Ping Pong Ball",
36
+ "1.75": "Golf Ball",
37
+ "2.00": "Hen Egg",
38
+ "2.50": "Tennis Ball",
39
+ "2.75": "Baseball",
40
+ "4.00": "CD/DVD"
41
+ }
42
+ */
43
+
44
+ export const getEventSignature = (event: TypeEvent): TypeEvent => {
45
+ const properties = event?.properties;
46
+ const vtec = event?.properties?.metadata?.vtec
47
+ const status = statusCorrelationText
48
+ .find((c: { type: string }) => c.type === properties?.status);
49
+ const csig = eventCancelMessages.find(sig => properties.description.toLowerCase().includes(sig.toLowerCase()));
50
+ properties.status_metadata = { ...properties.status_metadata, is_issued: true, is_test: false};
51
+
52
+ if (properties.parameters.estimated_hail_size) {
53
+ properties.parameters.estimated_hail_size += ` (${hailStrings[properties.parameters.estimated_hail_size]})`
54
+ }
55
+
56
+ if (status) {
57
+ properties.status = status.name ?? properties.status;
58
+ properties.status_metadata = { ...properties.status_metadata, is_updated: !!status.isUpdate, is_issued: !!status.isIssued, is_expired: !!status.isCancel };
59
+ }
60
+ if (csig) {
61
+ properties.status_metadata = { ...properties.status_metadata, is_expired: true };
62
+ }
63
+ if (vtec) {
64
+ const getProduct = vtec.split(`.`)[0]?.replace(`/`, ``)
65
+ const isTestProduct = eventProducts[getProduct] == `Test Product`
66
+ if (isTestProduct || test_signatures.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase()) || properties?.parameters?.instructions?.toLowerCase().includes(sig.toLowerCase()))) {
67
+ properties.status_metadata = { ...properties.status_metadata, is_test: true }
68
+ }
69
+ }
70
+ if (new Date(properties.expires).getTime() < Date.now()) {
71
+ properties.status_metadata = { ...properties.status_metadata, is_expired: true };
72
+ }
73
+ properties.status_metadata = {
74
+ ...properties.status_metadata,
75
+ }
76
+
77
+ return event
78
+ }
@@ -0,0 +1,24 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { eventTags } from "../@dictionaries/dictionaries.eventTags";
21
+
22
+ export const getEventTags = (message: string): string[] => {
23
+ return Object.entries(eventTags).filter(([key]) => message?.toLowerCase().includes(key.toLowerCase())).map(([, value]) => value)
24
+ }
@@ -0,0 +1,68 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, Everwatch1, & 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 { TypeAttributes } from "../@types/types.attributes";
21
+ import { TypeEventProperties } from "../@types/type.properties";
22
+ import { TypeStanzaCompiled } from "../@types/types.compiled";
23
+ import { TypePVTEC } from "../@types/types.pvtec";
24
+
25
+ interface GetTrackingOptions {
26
+ type: `RAW` | `VTEC` | `API`
27
+ stanza?: TypeStanzaCompiled
28
+ attributes?: TypeAttributes
29
+ properties?: TypeEventProperties
30
+ organization?: {
31
+ wmoidentifier: string
32
+ featureId: string
33
+ }
34
+ vtec?: TypePVTEC
35
+ }
36
+
37
+ export const getEventTracking = (options: GetTrackingOptions): string => {
38
+ const proprties = options.properties
39
+ const attributes = options.attributes
40
+ const stanza = options.stanza
41
+ const vtec = options.vtec
42
+ if (options.type === `RAW`) {
43
+ const getWatchNumber = proprties.watch_parameters.watch_number ?? null
44
+ if (getWatchNumber) {
45
+ return `${proprties.geocode.office.office}-${stanza.getType.prefix}-A-${getWatchNumber}`
46
+ }
47
+ return `${proprties.geocode.office.office}-${attributes.ttaaii}-${attributes.id.slice(-4).replace(`.`, ``) ?? '0'}`
48
+ }
49
+ if (options.type === `VTEC`) {
50
+ return vtec.tracking;
51
+ }
52
+ if (options.type === `API`) {
53
+ if (options.vtec) {
54
+ const vtecValue = Array.isArray(options.vtec)
55
+ ? options.vtec[0] : options.vtec;
56
+ const splitPVTEC = vtecValue.split('.');
57
+ return `${splitPVTEC[2]}-${splitPVTEC[3]}-${splitPVTEC[4]}-${splitPVTEC[5]}`;
58
+ }
59
+ const wmoMatch = options.organization?.wmoidentifier?.match(/([A-Z]{4}\d{2})\s+([A-Z]{4})/);
60
+ const station = wmoMatch?.[2] ?? 'N/A';
61
+ if (options.organization.featureId) {
62
+ const idMatch = options.organization.featureId.match(/([a-f0-9]+)\.(\d+)\.(\d+)$/);
63
+ return `${station}-${idMatch?.[1] ?? 'N/A'}`;
64
+ }
65
+ const id = wmoMatch?.[1] ?? 'N/A';
66
+ return `${station}-${id}`;
67
+ }
68
+ }