@atmosx/event-product-parser 3.0.61 → 3.0.63
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/docs/docs-functions.md +1 -1
- package/.github/docs/docs-general-configurations.md +1 -1
- package/.github/docs/docs-integrations.md +1 -1
- package/.github/docs/docs-listeners.md +1 -1
- package/.github/docs/docs-source-configuration.md +1 -1
- package/.github/docs/docs-technical.md +1 -1
- package/README.md +7 -5
- package/dist/cjs/index.cjs +21216 -6908
- package/dist/esm/index.mjs +21207 -6900
- package/package.json +49 -47
- package/pnpm-workspace.yaml +4 -0
- package/src/@building/CreateEvent.ts +20 -22
- package/src/@building/GetEventAttachments.ts +8 -8
- package/src/@building/GetEventEnhancedName.ts +2 -4
- package/src/@building/GetEventGeometry.ts +5 -5
- package/src/@building/GetEventHeader.ts +11 -11
- package/src/@building/GetEventNodes.ts +12 -12
- package/src/@building/GetEventOffice.ts +11 -11
- package/src/@building/GetEventProperties.ts +60 -55
- package/src/@building/GetEventSignature.ts +7 -7
- package/src/@building/GetEventTags.ts +1 -1
- package/src/@building/GetEventTracking.ts +28 -32
- package/src/@core/ClearEvents.ts +7 -7
- package/src/@core/CreateListener.ts +2 -2
- package/src/@core/GetEvents.ts +2 -2
- package/src/@core/GetNodes.ts +2 -2
- package/src/@core/GetRandomEvent.ts +2 -2
- package/src/@core/GetVersion.ts +2 -2
- package/src/@core/ManualEvent.ts +20 -21
- package/src/@core/QueryStanza.ts +7 -7
- package/src/@core/SetNode.ts +32 -26
- package/src/@core/StartService.ts +18 -18
- package/src/@core/StopService.ts +8 -8
- package/src/@enums/Expressions.ts +1 -1
- package/src/@enums/Tags.ts +1 -1
- package/src/@events/ParseAPI.ts +44 -39
- package/src/@events/ParseText.ts +19 -19
- package/src/@events/ParseUGC.ts +21 -21
- package/src/@events/ParseVTEC.ts +32 -33
- package/src/@manager/MakeEvents.ts +33 -30
- package/src/@manager/RemoveEvent.ts +38 -34
- package/src/@manager/SetHash.ts +16 -11
- package/src/@manager/UpdateEvents.ts +10 -10
- package/src/@manager/UpdateNode.ts +13 -13
- package/src/@manager/ValidateEvents.ts +36 -37
- package/src/@modules/@database/GetCachedEvents.ts +10 -12
- package/src/@modules/@database/ImportBroadcastify.ts +12 -13
- package/src/@modules/@database/ImportShapefiles.ts +17 -18
- package/src/@modules/@database/ImportStanza.ts +11 -11
- package/src/@modules/@database/InitializeDatabase.ts +16 -16
- package/src/@modules/@eas/GenerateEASMessage.ts +53 -47
- package/src/@modules/@eas/GetPCM16.ts +11 -6
- package/src/@modules/@eas/GetSampledPCM16.ts +12 -6
- package/src/@modules/@eas/GetTTS.ts +12 -7
- package/src/@modules/@eas/GetWavPCM16.ts +5 -5
- package/src/@modules/@eas/SetAFSK.ts +11 -6
- package/src/@modules/@eas/SetAttentionTone.ts +9 -4
- package/src/@modules/@eas/SetNoise.ts +10 -5
- package/src/@modules/@eas/SetRadioEffect.ts +10 -5
- package/src/@modules/@eas/SetSameHeader.ts +20 -12
- package/src/@modules/@stanza/GetAwipsType.ts +14 -15
- package/src/@modules/@stanza/ValidateStanza.ts +25 -13
- package/src/@modules/@utilities/CreateHttp.ts +24 -24
- package/src/@modules/@utilities/GetMatched.ts +8 -3
- package/src/@modules/@utilities/GetSettings.ts +3 -3
- package/src/@modules/@utilities/GetShapeNearestPoint.ts +22 -17
- package/src/@modules/@utilities/QueueManager.ts +70 -0
- package/src/@modules/@utilities/SetCronSchedule.ts +20 -20
- package/src/@modules/@utilities/SetDebug.ts +10 -10
- package/src/@modules/@utilities/SetEventEmit.ts +15 -15
- package/src/@modules/@utilities/SetListener.ts +6 -6
- package/src/@modules/@utilities/SetSettings.ts +5 -5
- package/src/@modules/@utilities/SetSleep.ts +3 -3
- package/src/@modules/@utilities/SetTimeoutAction.ts +25 -25
- package/src/@modules/@utilities/SetWarning.ts +8 -8
- package/src/@modules/@xmpp/DeployXMPP.ts +16 -16
- package/src/@modules/@xmpp/ErrorXMPP.ts +4 -4
- package/src/@modules/@xmpp/OfflineXMPP.ts +11 -11
- package/src/@modules/@xmpp/OnlineXMPP.ts +16 -16
- package/src/@modules/@xmpp/ReconnectXMPP.ts +27 -27
- package/src/@modules/@xmpp/StanzaXMPP.ts +23 -23
- package/src/@parsers/@hvtec/HVExtract.ts +9 -9
- package/src/@parsers/@text/GetDescriptionFromProduct.ts +18 -19
- package/src/@parsers/@text/GetEmbededText.ts +3 -3
- package/src/@parsers/@text/GetStringText.ts +6 -6
- package/src/@parsers/@text/GetTextFromProduct.ts +10 -10
- package/src/@parsers/@text/GetXML.ts +5 -5
- package/src/@parsers/@ugc/GetCache.ts +2 -2
- package/src/@parsers/@ugc/{GetUGCHeader.ts → GetHeader.ts} +2 -2
- package/src/@parsers/@ugc/GetLocations.ts +5 -5
- package/src/@parsers/@ugc/GetZonePolygon.ts +10 -10
- package/src/@parsers/@ugc/GetZones.ts +1 -1
- package/src/@parsers/@ugc/SetCache.ts +11 -6
- package/src/@parsers/@ugc/UGCExtract.ts +10 -10
- package/src/@parsers/{@pvtec → @vtec}/VTECExtract.ts +19 -19
- package/src/@tasks/CreateTasks.ts +110 -0
- package/src/@tasks/TaskGenerateAudio.ts +34 -0
- package/src/@tasks/TaskGenerateJSON.ts +34 -0
- package/src/@tasks/TaskGenerateText.ts +34 -0
- package/src/@tasks/TaskSendNTFY.ts +91 -0
- package/src/@tasks/TaskSendWebhook.ts +100 -0
- package/src/@types/HVTEC.ts +4 -4
- package/src/@types/Hash.ts +3 -3
- package/src/@types/Settings.ts +1 -1
- package/src/@types/StanzaCompiled.ts +13 -13
- package/src/@types/UGC.ts +3 -3
- package/src/@types/VTEC.ts +10 -10
- package/src/{@types → @types-lower}/Event.ts +4 -4
- package/src/{@types → @types-lower}/Properties.ts +2 -1
- package/src/{@types → @types-lower}/Stanza.ts +1 -1
- package/src/bootstrap.ts +26 -26
- package/src/index.ts +30 -27
- package/tools/build.js +45 -0
- package/tsconfig.json +21 -1
- package/src/@manager/Tasks.ts +0 -246
- package/tsup.config.ts +0 -16
- /package/src/@parsers/{@pvtec → @vtec}/GetExpiry.ts +0 -0
- /package/src/{@types → @types-lower}/Attributes.ts +0 -0
package/package.json
CHANGED
|
@@ -1,47 +1,49 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@atmosx/event-product-parser",
|
|
3
|
-
"version": "3.0.
|
|
4
|
-
"description": "NOAA Weather Wire & NWS API Parser - Built for standalone and Project AtmosphericX Integration.",
|
|
5
|
-
"main": "dist/cjs/index.cjs",
|
|
6
|
-
"module": "dist/esm/index.mjs",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/AtmosphericX/event-product-parser",
|
|
10
|
-
"branch": "v3-beta-branch"
|
|
11
|
-
},
|
|
12
|
-
"scripts": {
|
|
13
|
-
"start": "cd ./test && node ./index.js",
|
|
14
|
-
"build": "
|
|
15
|
-
"
|
|
16
|
-
"publish
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
|
|
36
|
-
"
|
|
37
|
-
"
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
41
|
-
"
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "@atmosx/event-product-parser",
|
|
3
|
+
"version": "3.0.63",
|
|
4
|
+
"description": "NOAA Weather Wire & NWS API Parser - Built for standalone and Project AtmosphericX Integration.",
|
|
5
|
+
"main": "dist/cjs/index.cjs",
|
|
6
|
+
"module": "dist/esm/index.mjs",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/AtmosphericX/event-product-parser",
|
|
10
|
+
"branch": "v3-beta-branch"
|
|
11
|
+
},
|
|
12
|
+
"scripts": {
|
|
13
|
+
"start": "cd ./test && node ./index.js",
|
|
14
|
+
"build": "node ./tools/build.js && cd ./test && node index.js",
|
|
15
|
+
"watch": "node ./tools/build.js --watch",
|
|
16
|
+
"publish": "node ./tools/build.js && npm publish --access public",
|
|
17
|
+
"publish-beta-branch": "node ./tools/build.js && npm publish --tag v3-beta-branch --access public"
|
|
18
|
+
},
|
|
19
|
+
"keywords": [
|
|
20
|
+
"NWWS",
|
|
21
|
+
"NOAA Weather Wire Service",
|
|
22
|
+
"TypeScript",
|
|
23
|
+
"XMPP",
|
|
24
|
+
"Parser",
|
|
25
|
+
"JavaScript",
|
|
26
|
+
"CommonJS",
|
|
27
|
+
"ESM"
|
|
28
|
+
],
|
|
29
|
+
"author": "k3yomi, StarflightWx",
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"bugs": {
|
|
32
|
+
"url": "https://github.com/AtmosphericX/event-product-parser/issues"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/AtmosphericX/event-product-parser#readme",
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@xmpp/client": "0.14.0",
|
|
37
|
+
"better-sqlite3": "12.9.0",
|
|
38
|
+
"croner": "10.0.1",
|
|
39
|
+
"esbuild": "^0.28.1",
|
|
40
|
+
"fast-glob": "^3.3.3",
|
|
41
|
+
"jszip": "3.10.1",
|
|
42
|
+
"polygon-clipping": "0.15.7",
|
|
43
|
+
"shapefile": "0.6.6",
|
|
44
|
+
"typescript": "5.9.3"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@types/node": "25.2.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -17,40 +17,38 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeStanzaCompiled } from "
|
|
21
|
-
import { TypeSettings } from "
|
|
22
|
-
import {
|
|
23
|
-
import { ParseText } from "
|
|
24
|
-
import { ParseUGC } from "
|
|
25
|
-
import { ParseVTEC } from "
|
|
26
|
-
import { ParseAPI } from "
|
|
27
|
-
import { ValidateEvents } from "
|
|
20
|
+
import { TypeStanzaCompiled } from "types/StanzaCompiled"
|
|
21
|
+
import { TypeSettings } from "types/Settings"
|
|
22
|
+
import { Bootstrap } from "@bootstrap"
|
|
23
|
+
import { ParseText } from "@events/ParseText"
|
|
24
|
+
import { ParseUGC } from "@events/ParseUGC"
|
|
25
|
+
import { ParseVTEC } from "@events/ParseVTEC"
|
|
26
|
+
import { ParseAPI } from "@events/ParseAPI"
|
|
27
|
+
import { ValidateEvents } from "@manager/ValidateEvents"
|
|
28
28
|
|
|
29
|
-
export const CreateEvent = async (
|
|
30
|
-
const settings =
|
|
29
|
+
export const CreateEvent = async (Stanza: TypeStanzaCompiled): Promise<void | string> => {
|
|
30
|
+
const settings = Bootstrap.Settings as TypeSettings
|
|
31
31
|
const StanzaSettings = settings.NOAAWeatherWireServiceSettings.StanzaSettings;
|
|
32
32
|
|
|
33
|
-
const isVtecEvent = (
|
|
34
|
-
const isUgcEvent = (!
|
|
35
|
-
const isTextEvent = (!
|
|
36
|
-
|
|
37
|
-
|
|
33
|
+
const isVtecEvent = (Stanza.VTEC && Stanza.UGC)
|
|
34
|
+
const isUgcEvent = (!Stanza.VTEC && Stanza.UGC)
|
|
35
|
+
const isTextEvent = (!Stanza.VTEC && !Stanza.UGC)
|
|
36
|
+
|
|
37
|
+
const isNWWS = (Stanza.NWWS)
|
|
38
38
|
switch (true) {
|
|
39
39
|
case (!isNWWS):
|
|
40
|
-
await ParseAPI(
|
|
40
|
+
await ParseAPI(Stanza)
|
|
41
41
|
break;
|
|
42
42
|
case (isNWWS && !StanzaSettings.DisableVTEC && isVtecEvent):
|
|
43
|
-
await ParseVTEC(
|
|
43
|
+
await ParseVTEC(Stanza)
|
|
44
44
|
break;
|
|
45
45
|
case (isNWWS && !StanzaSettings.DisableUGC && isUgcEvent):
|
|
46
|
-
await ParseUGC(
|
|
46
|
+
await ParseUGC(Stanza)
|
|
47
47
|
break;
|
|
48
48
|
case (isNWWS && !StanzaSettings.DisableText && isTextEvent):
|
|
49
|
-
await ParseText(
|
|
49
|
+
await ParseText(Stanza)
|
|
50
50
|
break;
|
|
51
51
|
}
|
|
52
|
-
|
|
53
|
-
await ValidateEvents(bootstrap.cache.processed)
|
|
54
|
-
}
|
|
52
|
+
await ValidateEvents(Bootstrap.Cache.Parsed)
|
|
55
53
|
return 'nothing picked';
|
|
56
54
|
}
|
|
@@ -17,11 +17,11 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeEvent } from "
|
|
21
|
-
import {
|
|
22
|
-
import { EnumStates } from "
|
|
23
|
-
import { EnumExpressions } from "
|
|
24
|
-
import { GetLatestIssuance } from "
|
|
20
|
+
import { TypeEvent } from "types-lower/Event"
|
|
21
|
+
import { Bootstrap } from "@bootstrap"
|
|
22
|
+
import { EnumStates } from "@enums/States"
|
|
23
|
+
import { EnumExpressions } from "@enums/Expressions"
|
|
24
|
+
import { GetLatestIssuance } from "@utilities/GetLatestIssuance"
|
|
25
25
|
|
|
26
26
|
interface GetEventAttachmentsResponse {
|
|
27
27
|
name: string
|
|
@@ -38,7 +38,7 @@ type BroadcastifyResponse = {
|
|
|
38
38
|
|
|
39
39
|
export const GetEventAttachments = (event: TypeEvent): GetEventAttachmentsResponse[] | null => {
|
|
40
40
|
let attachments = [];
|
|
41
|
-
const settings =
|
|
41
|
+
const settings = Bootstrap.Settings;
|
|
42
42
|
const issuanceTime = GetLatestIssuance();
|
|
43
43
|
const spcNumber = event?.properties?.discussion_parameters?.discussion_number;
|
|
44
44
|
const watchNumber = event?.properties?.watch_parameters?.watch_number;
|
|
@@ -64,13 +64,13 @@ export const GetEventAttachments = (event: TypeEvent): GetEventAttachmentsRespon
|
|
|
64
64
|
const lines = [`Northern`, `Southern`, `Eastern`, `Western`, `Inland`, `Costal`, `County`]
|
|
65
65
|
const county = location?.split(',')[0]?.trim().replace(new RegExp(`^(${lines.join('|')}) `), '')
|
|
66
66
|
const state = EnumStates[location?.split(',')[1]?.trim()]
|
|
67
|
-
const feeds =
|
|
67
|
+
const feeds = Bootstrap.Database.prepare(`SELECT * FROM broadcastify WHERE state = ? AND county = ?`).all(state, county).sort((a, b) => {
|
|
68
68
|
const typeOrder = ['Other', 'Public Safety'];
|
|
69
69
|
const indexA = typeOrder.indexOf(a.type);
|
|
70
70
|
const indexB = typeOrder.indexOf(b.type);
|
|
71
71
|
return indexA - indexB;
|
|
72
72
|
})
|
|
73
|
-
const tags =
|
|
73
|
+
const tags = Bootstrap.Settings.BroadcastifySettings.BroadcastifyTags;
|
|
74
74
|
const filtered = feeds.filter((feed: BroadcastifyResponse) => tags.includes(feed.type));
|
|
75
75
|
if (filtered.length > 0) {
|
|
76
76
|
filtered.map((filtered: BroadcastifyResponse) => {
|
|
@@ -17,10 +17,8 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeEvent } from "
|
|
21
|
-
import {
|
|
22
|
-
import { EnumEnhanced } from "../@enums/Enhanced"
|
|
23
|
-
import { bootstrap } from "../bootstrap"
|
|
20
|
+
import { TypeEvent } from "types-lower/Event"
|
|
21
|
+
import { EnumEnhanced } from "@enums/Enhanced"
|
|
24
22
|
|
|
25
23
|
export const GetEventEnhancedName = (event: TypeEvent): string => {
|
|
26
24
|
let name = event?.properties?.event;
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeSettings } from "
|
|
21
|
-
import { TypeEvent } from "
|
|
22
|
-
import { GetSettings } from "
|
|
23
|
-
import { getZonePolygon } from "
|
|
20
|
+
import { TypeSettings } from "types/Settings"
|
|
21
|
+
import { TypeEvent } from "types-lower/Event"
|
|
22
|
+
import { GetSettings } from "@utilities/GetSettings"
|
|
23
|
+
import { getZonePolygon } from "@parsers/ugc/GetZonePolygon"
|
|
24
24
|
|
|
25
25
|
interface GetGeometryResponse {
|
|
26
26
|
type: `Polygon` | `MultiPolygon`
|
|
@@ -36,7 +36,7 @@ export const GetEventGeometry = (event: TypeEvent): GetGeometryResponse => {
|
|
|
36
36
|
coordinates: generated != null ? JSON.parse(Buffer.from(generated, 'base64').toString('utf-8')) : null
|
|
37
37
|
}
|
|
38
38
|
if (settings.GlobalSettings.UseShapefileCoordinates && generated == null && ugc != null) {
|
|
39
|
-
geo = getZonePolygon({
|
|
39
|
+
geo = getZonePolygon({Zones: ugc, Union: false})
|
|
40
40
|
if (geo == null) {
|
|
41
41
|
geo = {
|
|
42
42
|
type: `Polygon`,
|
|
@@ -17,21 +17,21 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import {
|
|
21
|
-
import { TypeEventProperties } from "
|
|
20
|
+
import { TypeVTEC } from "types/VTEC"
|
|
21
|
+
import { TypeEventProperties } from "types-lower/Properties"
|
|
22
22
|
|
|
23
23
|
interface GetHeaderOptions {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
Properties: TypeEventProperties
|
|
25
|
+
VTEC?: TypeVTEC
|
|
26
|
+
Type: {
|
|
27
|
+
Type: string
|
|
28
|
+
Prefix: string
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export const GetEventHeader = (
|
|
33
|
-
const properties =
|
|
34
|
-
const vtec =
|
|
32
|
+
export const GetEventHeader = ({ Properties, VTEC, Type }: GetHeaderOptions): string => {
|
|
33
|
+
const properties = Properties
|
|
34
|
+
const vtec = VTEC ?? null
|
|
35
35
|
const ugc = properties.geocode.ugc != null ? properties.geocode.ugc.join(`-`) : `0`;
|
|
36
|
-
return `ZCZC-ATMOSX-${
|
|
36
|
+
return `ZCZC-ATMOSX-${Type?.Prefix}-${ugc}-${vtec?.Status ?? `Issued`}-${new Date().toISOString().replace(/[-:]/g, '').split('.')[0]}-${properties.geocode.office.office ?? `KWNS`}`
|
|
37
37
|
}
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeEvent } from "
|
|
21
|
-
import {
|
|
22
|
-
import { GetEventGeometry } from "
|
|
23
|
-
import { GetShapeNearestPoint } from "
|
|
20
|
+
import { TypeEvent } from "types-lower/Event"
|
|
21
|
+
import { Bootstrap } from "@bootstrap"
|
|
22
|
+
import { GetEventGeometry } from "@building/GetEventGeometry"
|
|
23
|
+
import { GetShapeNearestPoint } from "@utilities/GetShapeNearestPoint"
|
|
24
24
|
|
|
25
25
|
interface GetEventNodesResponse {
|
|
26
26
|
nodes: {
|
|
@@ -36,9 +36,9 @@ interface GetEventNodesResponse {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
export const GetEventNodes = async (event: TypeEvent): Promise<GetEventNodesResponse> => {
|
|
39
|
-
const nodes =
|
|
39
|
+
const nodes = Bootstrap.Cache.Nodes.features;
|
|
40
40
|
if (!nodes || nodes.length === 0) {
|
|
41
|
-
return { nodes: [], filtered:
|
|
41
|
+
return { nodes: [], filtered: false, updated: Date.now() };
|
|
42
42
|
}
|
|
43
43
|
const metadata = { nodes: [], proximity: false, filtered: false };
|
|
44
44
|
const geometry = await GetEventGeometry(event);
|
|
@@ -47,23 +47,23 @@ export const GetEventNodes = async (event: TypeEvent): Promise<GetEventNodesResp
|
|
|
47
47
|
}
|
|
48
48
|
for (const node of nodes) {
|
|
49
49
|
const [longitude, latitude] = node.geometry.coordinates;
|
|
50
|
-
const getPoint = GetShapeNearestPoint(geometry.coordinates, [longitude, latitude])
|
|
51
|
-
const miles = getPoint.
|
|
50
|
+
const getPoint = GetShapeNearestPoint({ Coordinates: geometry.coordinates, Point: [longitude, latitude] });
|
|
51
|
+
const miles = getPoint.Distance ?? null;
|
|
52
52
|
const kilometers = Number((miles * 1.609344).toFixed(3));
|
|
53
53
|
|
|
54
54
|
const info = {
|
|
55
55
|
id: node.properties?.identifier,
|
|
56
56
|
coordinates: [longitude, latitude],
|
|
57
|
-
nearest: getPoint.
|
|
57
|
+
nearest: getPoint.Point,
|
|
58
58
|
miles,
|
|
59
59
|
kilometers,
|
|
60
60
|
proximity: false
|
|
61
61
|
}
|
|
62
|
-
|
|
63
|
-
if (miles != null && (bootstrap.settings.GlobalSettings.EventFiltering.NodeLocationFiltering) && (miles < bootstrap.settings.GlobalSettings.NodeMaxDistance)) {
|
|
64
|
-
metadata.proximity = true;
|
|
62
|
+
if (miles != null && (miles < Bootstrap.Settings.GlobalSettings.NodeMaxDistance)) {
|
|
65
63
|
info.proximity = true;
|
|
64
|
+
metadata.proximity = true;
|
|
66
65
|
}
|
|
66
|
+
metadata.nodes.push(info)
|
|
67
67
|
}
|
|
68
68
|
return {
|
|
69
69
|
nodes: metadata.nodes,
|
|
@@ -17,14 +17,14 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeAttributes } from "
|
|
21
|
-
import {
|
|
22
|
-
import { EnumICAO } from "
|
|
20
|
+
import { TypeAttributes } from "types-lower/Attributes"
|
|
21
|
+
import { TypeVTEC } from "types/VTEC"
|
|
22
|
+
import { EnumICAO } from "@enums/ICAO"
|
|
23
23
|
|
|
24
24
|
interface GetOfficeOptions {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
Attributes: TypeAttributes
|
|
26
|
+
Organization: string
|
|
27
|
+
VTEC: TypeVTEC
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
interface GetOfficeResponse {
|
|
@@ -32,11 +32,11 @@ interface GetOfficeResponse {
|
|
|
32
32
|
name: string | null
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export const GetEventOffice = (
|
|
36
|
-
const office =
|
|
37
|
-
?
|
|
38
|
-
(
|
|
39
|
-
(Array.isArray(
|
|
35
|
+
export const GetEventOffice = ({ Attributes, Organization, VTEC }: GetOfficeOptions): GetOfficeResponse => {
|
|
36
|
+
const office = VTEC != null
|
|
37
|
+
? VTEC?.Tracking?.split(`.`)[0] : (Attributes?.cccc ??
|
|
38
|
+
(Organization != null ?
|
|
39
|
+
(Array.isArray(Organization) ? Organization?.[0] : Organization)
|
|
40
40
|
: null));
|
|
41
41
|
const name = EnumICAO?.[office] ?? null;
|
|
42
42
|
return { office, name };
|
|
@@ -17,76 +17,81 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeEventProperties } from "
|
|
21
|
-
import { TypeAttributes } from "
|
|
22
|
-
import { TypeUGC } from "
|
|
23
|
-
import {
|
|
24
|
-
import { TypeHVTEC } from "
|
|
25
|
-
import { EnumExpressions } from "
|
|
26
|
-
import { GetDescriptionFromProduct } from "
|
|
27
|
-
import { getPolygonFromProduct } from "
|
|
28
|
-
import { GetTextFromProduct } from "
|
|
29
|
-
import { GetEventOffice } from "
|
|
30
|
-
import { GetEventTags } from "
|
|
20
|
+
import { TypeEventProperties } from "types-lower/Properties"
|
|
21
|
+
import { TypeAttributes } from "types-lower/Attributes"
|
|
22
|
+
import { TypeUGC } from "types/UGC"
|
|
23
|
+
import { TypeVTEC } from "types/VTEC"
|
|
24
|
+
import { TypeHVTEC } from "types/HVTEC"
|
|
25
|
+
import { EnumExpressions } from "@enums/Expressions"
|
|
26
|
+
import { GetDescriptionFromProduct } from "@parsers/text/GetDescriptionFromProduct"
|
|
27
|
+
import { getPolygonFromProduct } from "@parsers/text/GetPolygonFromProduct"
|
|
28
|
+
import { GetTextFromProduct } from "@parsers/text/GetTextFromProduct"
|
|
29
|
+
import { GetEventOffice } from "@building/GetEventOffice"
|
|
30
|
+
import { GetEventTags } from "@building/GetEventTags"
|
|
31
31
|
|
|
32
32
|
interface GetEventPropertiesOptions {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
hVtec?: TypeHVTEC
|
|
33
|
+
Message: string
|
|
34
|
+
Attributes: TypeAttributes
|
|
35
|
+
UGC?: TypeUGC
|
|
36
|
+
VTEC?: TypeVTEC
|
|
38
37
|
}
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
const
|
|
39
|
+
|
|
40
|
+
export const GetEventProperties = ({ Message, Attributes, UGC, VTEC }: GetEventPropertiesOptions): TypeEventProperties => {
|
|
41
|
+
const organization = Message.match(EnumExpressions.wmo)?.[0] ?? null
|
|
42
|
+
const polygons = getPolygonFromProduct(Message)
|
|
43
43
|
const properties = {
|
|
44
|
-
locations:
|
|
45
|
-
locations_array:
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
locations: UGC?.Locations?.join(`; `) ?? null,
|
|
45
|
+
locations_array: UGC?.Locations ?? [],
|
|
46
|
+
location_states: [...new Set(
|
|
47
|
+
UGC?.Locations
|
|
48
|
+
?.map((location: string) => location.match(/,\s*([A-Z]{2})\b/)?.[1])
|
|
49
|
+
.filter(Boolean) ?? []
|
|
50
|
+
)],
|
|
51
|
+
description: GetDescriptionFromProduct({ Message: Message, Handle: VTEC?.Raw ?? null }),
|
|
52
|
+
attributes: Attributes,
|
|
48
53
|
geocode: {
|
|
49
|
-
office: GetEventOffice({
|
|
54
|
+
office: GetEventOffice({ Attributes: Attributes, Organization: organization, VTEC: VTEC }),
|
|
50
55
|
organization: organization,
|
|
51
|
-
ugc:
|
|
56
|
+
ugc: UGC?.Zones ?? [],
|
|
52
57
|
polygon: polygons.length > 0 ? Buffer.from(JSON.stringify([polygons])).toString('base64') : null,
|
|
53
58
|
polygon_generated: polygons.length > 0 ? true : false
|
|
54
59
|
},
|
|
55
60
|
parameters: {
|
|
56
|
-
tags: GetEventTags(
|
|
57
|
-
instructions: GetTextFromProduct({
|
|
58
|
-
source: GetTextFromProduct({
|
|
59
|
-
hazards: GetTextFromProduct({
|
|
60
|
-
impacts: GetTextFromProduct({
|
|
61
|
-
estimated_hail_size: GetTextFromProduct({
|
|
62
|
-
estimated_wind_gusts: GetTextFromProduct({
|
|
63
|
-
damage_threat: GetTextFromProduct({
|
|
64
|
-
tornado_threat: GetTextFromProduct({
|
|
65
|
-
flood_threat: GetTextFromProduct({
|
|
66
|
-
wind_threat: GetTextFromProduct({
|
|
67
|
-
hail_threat: GetTextFromProduct({
|
|
61
|
+
tags: GetEventTags(Message),
|
|
62
|
+
instructions: GetTextFromProduct({ Message: Message, Find: [`For your protection`, `do not`, `use extreme caution`], Append: `...`, Removal: [`.`]}) ?? null,
|
|
63
|
+
source: GetTextFromProduct({ Message: Message, Find: [`SOURCE...`], Removal: [`.`]}) ?? null,
|
|
64
|
+
hazards: GetTextFromProduct({ Message: Message, Find: [`HAZARD...`], Removal: [`.`]}) ?? null,
|
|
65
|
+
impacts: GetTextFromProduct({ Message: Message, Find: [`IMPACT...`], Removal: [`.`]}) ?? null,
|
|
66
|
+
estimated_hail_size: GetTextFromProduct({ Message: Message, Find: [`MAX HAIL SIZE...`, `HAIL...`], Removal: ['in']}) ?? null,
|
|
67
|
+
estimated_wind_gusts: GetTextFromProduct({ Message: Message, Find: [`MAX WIND GUST...`, `WIND...`]}) ?? null,
|
|
68
|
+
damage_threat: GetTextFromProduct({ Message: Message, Find: [`DAMAGE THREAT...`], Removal: []}) ?? null,
|
|
69
|
+
tornado_threat: GetTextFromProduct({ Message: Message, Find: [`TORNADO...`, `WATERSPOUT...`] }) ?? null,
|
|
70
|
+
flood_threat: GetTextFromProduct({ Message: Message, Find: [`FLASH FLOOD...`]}) ?? null,
|
|
71
|
+
wind_threat: GetTextFromProduct({ Message: Message, Find: [`WIND THREAT...`]}) ?? null,
|
|
72
|
+
hail_threat: GetTextFromProduct({ Message: Message, Find: [`HAIL THREAT...`], Removal: []}) ?? null,
|
|
68
73
|
},
|
|
69
74
|
discussion_parameters: {
|
|
70
|
-
discussion_number: GetTextFromProduct({
|
|
71
|
-
discussion_concerning: GetTextFromProduct({
|
|
72
|
-
discussion_max_tornado: GetTextFromProduct({
|
|
73
|
-
discussion_max_hail: GetTextFromProduct({
|
|
74
|
-
discussion_max_wind: GetTextFromProduct({
|
|
75
|
-
discussion_watch_issuance: GetTextFromProduct({
|
|
75
|
+
discussion_number: GetTextFromProduct({ Message: Message, Find: [`Mesoscale Discussion `], Removal: [`Mesoscale Discussion`, `Number`, `...`] })?.toString()?.padStart(4, "0") ?? null,
|
|
76
|
+
discussion_concerning: GetTextFromProduct({ Message: Message, Find: [`Concerning...`] }) ?? null,
|
|
77
|
+
discussion_max_tornado: GetTextFromProduct({ Message: Message, Find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
|
|
78
|
+
discussion_max_hail: GetTextFromProduct({ Message: Message, Find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
|
|
79
|
+
discussion_max_wind: GetTextFromProduct({ Message: Message, Find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
|
|
80
|
+
discussion_watch_issuance: GetTextFromProduct({ Message: Message, Find: [`Probability of Watch Issuance...`], Removal: [`percent`]}) ?? null,
|
|
76
81
|
},
|
|
77
82
|
watch_parameters: {
|
|
78
|
-
watch_number:
|
|
79
|
-
watch_type:
|
|
80
|
-
additional_tornadoes_probability: GetTextFromProduct({
|
|
81
|
-
strong_tornadoes_probability: GetTextFromProduct({
|
|
82
|
-
severe_wind_probability: GetTextFromProduct({
|
|
83
|
-
severe_hail_probability: GetTextFromProduct({
|
|
84
|
-
hail_2in_probability: GetTextFromProduct({
|
|
85
|
-
combined_hail_wind_probability: GetTextFromProduct({
|
|
86
|
-
max_hail_in: GetTextFromProduct({
|
|
87
|
-
max_wind_surface: GetTextFromProduct({
|
|
88
|
-
max_tops_x100feet: GetTextFromProduct({
|
|
89
|
-
pds_watch: (GetTextFromProduct({
|
|
83
|
+
watch_number: VTEC?.Watch ? ( GetTextFromProduct({ Message: Message, Find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], Removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim()?.toString()?.padStart(4, "0") ?? VTEC?.Tracking?.slice(-4)?.toString()?.padStart(4, "0") ?? null) : null,
|
|
84
|
+
watch_type: Message.includes(`TORNADO WATCH`) ? `Tornado` : Message.includes(`SEVERE`) ? `Severe` : null,
|
|
85
|
+
additional_tornadoes_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 2 OR MORE TORNADOES`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
86
|
+
strong_tornadoes_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
87
|
+
severe_wind_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
88
|
+
severe_hail_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
89
|
+
hail_2in_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
90
|
+
combined_hail_wind_probability: GetTextFromProduct({ Message: Message, Find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
91
|
+
max_hail_in: GetTextFromProduct({ Message: Message, Find: [`MAX HAIL /INCHES/`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
92
|
+
max_wind_surface: GetTextFromProduct({ Message: Message, Find: [`MAX WIND GUSTS SURFACE /KNOTS/`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
93
|
+
max_tops_x100feet: GetTextFromProduct({ Message: Message, Find: [`MAX TOPS /X 100 FEET/`], Removal: [`%`, `<`, `:`] }) ?? null,
|
|
94
|
+
pds_watch: (GetTextFromProduct({ Message: Message, Find: [`PARTICULARLY DANGEROUS SITUATION`], Removal: [`%`, `<`, `:`] }) === `YES` ? true : null)
|
|
90
95
|
}
|
|
91
96
|
}
|
|
92
97
|
if (isNaN(Number(properties.watch_parameters.watch_number))) {
|
|
@@ -17,12 +17,12 @@
|
|
|
17
17
|
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { TypeEvent } from "
|
|
21
|
-
import { EnumCorrelations } from "
|
|
22
|
-
import { EnumCancellation } from "
|
|
23
|
-
import { EnumTesting} from "
|
|
24
|
-
import { EnumProducts } from "
|
|
25
|
-
import { EnumHail } from "
|
|
20
|
+
import { TypeEvent } from "types-lower/Event"
|
|
21
|
+
import { EnumCorrelations } from "@enums/Correlations"
|
|
22
|
+
import { EnumCancellation } from "@enums/Cancellation"
|
|
23
|
+
import { EnumTesting} from "@enums/Testing"
|
|
24
|
+
import { EnumProducts } from "@enums/Products"
|
|
25
|
+
import { EnumHail } from "@enums/Hail"
|
|
26
26
|
|
|
27
27
|
export const GetEventSignature = (event: TypeEvent): TypeEvent => {
|
|
28
28
|
const properties = event?.properties;
|
|
@@ -44,7 +44,7 @@ export const GetEventSignature = (event: TypeEvent): TypeEvent => {
|
|
|
44
44
|
properties.status_metadata = { ...properties.status_metadata, is_expired: true };
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const getProduct = vtec?.
|
|
47
|
+
const getProduct = vtec?.Raw?.split(`.`)[0]?.replace(`/`, ``)
|
|
48
48
|
const isTestProduct = EnumProducts[getProduct] == `Test Product`
|
|
49
49
|
if (isTestProduct || EnumTesting.some(sig => properties.description?.toLowerCase().includes(sig.toLowerCase()) ?? properties?.parameters?.instructions?.toLowerCase().includes(sig.toLowerCase()))) {
|
|
50
50
|
properties.status_metadata = { ...properties.status_metadata, is_test: true }
|