@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.
Files changed (118) hide show
  1. package/.github/docs/docs-functions.md +1 -1
  2. package/.github/docs/docs-general-configurations.md +1 -1
  3. package/.github/docs/docs-integrations.md +1 -1
  4. package/.github/docs/docs-listeners.md +1 -1
  5. package/.github/docs/docs-source-configuration.md +1 -1
  6. package/.github/docs/docs-technical.md +1 -1
  7. package/README.md +7 -5
  8. package/dist/cjs/index.cjs +21216 -6908
  9. package/dist/esm/index.mjs +21207 -6900
  10. package/package.json +49 -47
  11. package/pnpm-workspace.yaml +4 -0
  12. package/src/@building/CreateEvent.ts +20 -22
  13. package/src/@building/GetEventAttachments.ts +8 -8
  14. package/src/@building/GetEventEnhancedName.ts +2 -4
  15. package/src/@building/GetEventGeometry.ts +5 -5
  16. package/src/@building/GetEventHeader.ts +11 -11
  17. package/src/@building/GetEventNodes.ts +12 -12
  18. package/src/@building/GetEventOffice.ts +11 -11
  19. package/src/@building/GetEventProperties.ts +60 -55
  20. package/src/@building/GetEventSignature.ts +7 -7
  21. package/src/@building/GetEventTags.ts +1 -1
  22. package/src/@building/GetEventTracking.ts +28 -32
  23. package/src/@core/ClearEvents.ts +7 -7
  24. package/src/@core/CreateListener.ts +2 -2
  25. package/src/@core/GetEvents.ts +2 -2
  26. package/src/@core/GetNodes.ts +2 -2
  27. package/src/@core/GetRandomEvent.ts +2 -2
  28. package/src/@core/GetVersion.ts +2 -2
  29. package/src/@core/ManualEvent.ts +20 -21
  30. package/src/@core/QueryStanza.ts +7 -7
  31. package/src/@core/SetNode.ts +32 -26
  32. package/src/@core/StartService.ts +18 -18
  33. package/src/@core/StopService.ts +8 -8
  34. package/src/@enums/Expressions.ts +1 -1
  35. package/src/@enums/Tags.ts +1 -1
  36. package/src/@events/ParseAPI.ts +44 -39
  37. package/src/@events/ParseText.ts +19 -19
  38. package/src/@events/ParseUGC.ts +21 -21
  39. package/src/@events/ParseVTEC.ts +32 -33
  40. package/src/@manager/MakeEvents.ts +33 -30
  41. package/src/@manager/RemoveEvent.ts +38 -34
  42. package/src/@manager/SetHash.ts +16 -11
  43. package/src/@manager/UpdateEvents.ts +10 -10
  44. package/src/@manager/UpdateNode.ts +13 -13
  45. package/src/@manager/ValidateEvents.ts +36 -37
  46. package/src/@modules/@database/GetCachedEvents.ts +10 -12
  47. package/src/@modules/@database/ImportBroadcastify.ts +12 -13
  48. package/src/@modules/@database/ImportShapefiles.ts +17 -18
  49. package/src/@modules/@database/ImportStanza.ts +11 -11
  50. package/src/@modules/@database/InitializeDatabase.ts +16 -16
  51. package/src/@modules/@eas/GenerateEASMessage.ts +53 -47
  52. package/src/@modules/@eas/GetPCM16.ts +11 -6
  53. package/src/@modules/@eas/GetSampledPCM16.ts +12 -6
  54. package/src/@modules/@eas/GetTTS.ts +12 -7
  55. package/src/@modules/@eas/GetWavPCM16.ts +5 -5
  56. package/src/@modules/@eas/SetAFSK.ts +11 -6
  57. package/src/@modules/@eas/SetAttentionTone.ts +9 -4
  58. package/src/@modules/@eas/SetNoise.ts +10 -5
  59. package/src/@modules/@eas/SetRadioEffect.ts +10 -5
  60. package/src/@modules/@eas/SetSameHeader.ts +20 -12
  61. package/src/@modules/@stanza/GetAwipsType.ts +14 -15
  62. package/src/@modules/@stanza/ValidateStanza.ts +25 -13
  63. package/src/@modules/@utilities/CreateHttp.ts +24 -24
  64. package/src/@modules/@utilities/GetMatched.ts +8 -3
  65. package/src/@modules/@utilities/GetSettings.ts +3 -3
  66. package/src/@modules/@utilities/GetShapeNearestPoint.ts +22 -17
  67. package/src/@modules/@utilities/QueueManager.ts +70 -0
  68. package/src/@modules/@utilities/SetCronSchedule.ts +20 -20
  69. package/src/@modules/@utilities/SetDebug.ts +10 -10
  70. package/src/@modules/@utilities/SetEventEmit.ts +15 -15
  71. package/src/@modules/@utilities/SetListener.ts +6 -6
  72. package/src/@modules/@utilities/SetSettings.ts +5 -5
  73. package/src/@modules/@utilities/SetSleep.ts +3 -3
  74. package/src/@modules/@utilities/SetTimeoutAction.ts +25 -25
  75. package/src/@modules/@utilities/SetWarning.ts +8 -8
  76. package/src/@modules/@xmpp/DeployXMPP.ts +16 -16
  77. package/src/@modules/@xmpp/ErrorXMPP.ts +4 -4
  78. package/src/@modules/@xmpp/OfflineXMPP.ts +11 -11
  79. package/src/@modules/@xmpp/OnlineXMPP.ts +16 -16
  80. package/src/@modules/@xmpp/ReconnectXMPP.ts +27 -27
  81. package/src/@modules/@xmpp/StanzaXMPP.ts +23 -23
  82. package/src/@parsers/@hvtec/HVExtract.ts +9 -9
  83. package/src/@parsers/@text/GetDescriptionFromProduct.ts +18 -19
  84. package/src/@parsers/@text/GetEmbededText.ts +3 -3
  85. package/src/@parsers/@text/GetStringText.ts +6 -6
  86. package/src/@parsers/@text/GetTextFromProduct.ts +10 -10
  87. package/src/@parsers/@text/GetXML.ts +5 -5
  88. package/src/@parsers/@ugc/GetCache.ts +2 -2
  89. package/src/@parsers/@ugc/{GetUGCHeader.ts → GetHeader.ts} +2 -2
  90. package/src/@parsers/@ugc/GetLocations.ts +5 -5
  91. package/src/@parsers/@ugc/GetZonePolygon.ts +10 -10
  92. package/src/@parsers/@ugc/GetZones.ts +1 -1
  93. package/src/@parsers/@ugc/SetCache.ts +11 -6
  94. package/src/@parsers/@ugc/UGCExtract.ts +10 -10
  95. package/src/@parsers/{@pvtec → @vtec}/VTECExtract.ts +19 -19
  96. package/src/@tasks/CreateTasks.ts +110 -0
  97. package/src/@tasks/TaskGenerateAudio.ts +34 -0
  98. package/src/@tasks/TaskGenerateJSON.ts +34 -0
  99. package/src/@tasks/TaskGenerateText.ts +34 -0
  100. package/src/@tasks/TaskSendNTFY.ts +91 -0
  101. package/src/@tasks/TaskSendWebhook.ts +100 -0
  102. package/src/@types/HVTEC.ts +4 -4
  103. package/src/@types/Hash.ts +3 -3
  104. package/src/@types/Settings.ts +1 -1
  105. package/src/@types/StanzaCompiled.ts +13 -13
  106. package/src/@types/UGC.ts +3 -3
  107. package/src/@types/VTEC.ts +10 -10
  108. package/src/{@types → @types-lower}/Event.ts +4 -4
  109. package/src/{@types → @types-lower}/Properties.ts +2 -1
  110. package/src/{@types → @types-lower}/Stanza.ts +1 -1
  111. package/src/bootstrap.ts +26 -26
  112. package/src/index.ts +30 -27
  113. package/tools/build.js +45 -0
  114. package/tsconfig.json +21 -1
  115. package/src/@manager/Tasks.ts +0 -246
  116. package/tsup.config.ts +0 -16
  117. /package/src/@parsers/{@pvtec → @vtec}/GetExpiry.ts +0 -0
  118. /package/src/{@types → @types-lower}/Attributes.ts +0 -0
@@ -17,49 +17,45 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeAttributes } from "../@types/Attributes";
21
- import { TypeEventProperties } from "../@types/Properties";
22
- import { TypeStanzaCompiled } from "../@types/StanzaCompiled";
23
- import { TypePVTEC } from "../@types/VTEC";
20
+ import { TypeAttributes } from "types-lower/Attributes"
21
+ import { TypeEventProperties } from "types-lower/Properties"
22
+ import { TypeStanzaCompiled } from "types/StanzaCompiled"
23
+ import { TypeVTEC } from "types/VTEC"
24
24
 
25
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
26
+ Type: `RAW` | `VTEC` | `API`
27
+ Stanza?: TypeStanzaCompiled
28
+ Attributes?: TypeAttributes
29
+ Properties?: TypeEventProperties
30
+ WMO?: {
31
+ Identifier: string
32
+ ID: string
33
33
  }
34
- vtec?: TypePVTEC
34
+ VTEC?: TypeVTEC
35
35
  }
36
36
 
37
- export const GetEventTracking = (options: GetTrackingOptions): string => {
38
- const properties = 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 = properties.watch_parameters.watch_number ?? null
37
+ export const GetEventTracking = ({ Type, Stanza, Attributes, Properties, WMO, VTEC }: GetTrackingOptions): string => {
38
+ if (Type === `RAW`) {
39
+ const getWatchNumber = Properties?.watch_parameters?.watch_number ?? null
44
40
  if (getWatchNumber) {
45
- return `${properties.geocode.office.office}.${stanza.getType.prefix}.A.${getWatchNumber}`
41
+ return `${Properties.geocode.office.office}.${Stanza.Type.Prefix}.A.${getWatchNumber}`
46
42
  }
47
- return `${properties.geocode.office.office}.${attributes.ttaaii}.${attributes.id.slice(-4).replace(`.`, ``) ?? '0'}`
43
+ return `${Properties.geocode.office.office}.${Attributes.ttaaii}.${Attributes.id.slice(-4).replace(`.`, ``) ?? '0'}`
48
44
  }
49
- if (options.type === `VTEC`) {
50
- return vtec.tracking;
45
+ if (Type === `VTEC`) {
46
+ return VTEC?.Tracking;
51
47
  }
52
- if (options.type === `API`) {
53
- if (options.vtec) {
54
- const vtecValue = Array.isArray(options.vtec)
55
- ? options.vtec[0].vtec : options.vtec?.vtec;
56
- const splitPVTEC = vtecValue.split('.');
57
- return `${splitPVTEC[2]}.${splitPVTEC[3]}.${splitPVTEC[4]}.${splitPVTEC[5]}`;
48
+ if (Type === `API`) {
49
+ if (VTEC) {
50
+ const vtecValue = Array.isArray(VTEC)
51
+ ? VTEC[0].vtec : VTEC?.Raw;
52
+ const splitVTEC = vtecValue.split('.');
53
+ return `${splitVTEC[2]}.${splitVTEC[3]}.${splitVTEC[4]}.${splitVTEC[5]}`;
58
54
  }
59
- const wmoMatch = options.organization?.wmoidentifier?.match(/([A-Z]{4}\d{2})\s+([A-Z]{4})/);
55
+ const wmoMatch = WMO?.Identifier?.match(/([A-Z]{4}\d{2})\s+([A-Z]{4})/);
60
56
  const station = wmoMatch?.[2] ?? '---';
61
- if (options.organization.featureId) {
62
- const idMatch = options.organization.featureId.match(/([a-f0-9]+)\.(\d+)\.(\d+)$/);
57
+ if (WMO?.ID) {
58
+ const idMatch = WMO?.ID.match(/([a-f0-9]+)\.(\d+)\.(\d+)$/);
63
59
  return `${station}.${idMatch?.[0]?.replace(/\./g, '') ?? '---'}`;
64
60
  }
65
61
  const id = wmoMatch?.[1] ?? '---';
@@ -17,15 +17,15 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../bootstrap";
21
- import { SetEventEmit } from "../@modules/@utilities/SetEventEmit";
20
+ import { Bootstrap } from "@bootstrap"
21
+ import { SetEventEmit } from "@utilities/SetEventEmit"
22
22
 
23
23
  export const ClearEvents = (): void => {
24
- bootstrap.cache.events.features = [];
25
- bootstrap.cache.hashes = [];
24
+ Bootstrap.Cache.Events.features = [];
25
+ Bootstrap.Cache.Hashes = [];
26
26
  SetEventEmit({
27
- event: `onEventCache`,
28
- metadata: bootstrap.cache.events,
29
- message: `Manually cleared event cache.`
27
+ Event: `onEventCache`,
28
+ Metadata: Bootstrap.Cache.Events,
29
+ Message: `Manually cleared event cache.`
30
30
  })
31
31
  }
@@ -17,8 +17,8 @@
17
17
 
18
18
  */
19
19
 
20
- import { SetListener } from "../@modules/@utilities/SetListener";
20
+ import { SetListener } from "@utilities/SetListener"
21
21
 
22
22
  export const CreateListener = (event: string, callback: () => void) => {
23
- SetListener({event, callback})
23
+ SetListener({Event: event, Callback: callback})
24
24
  }
@@ -17,8 +17,8 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../bootstrap";
20
+ import { Bootstrap } from "@bootstrap"
21
21
 
22
22
  export const GetEvents = (): any => {
23
- return bootstrap.cache.events
23
+ return Bootstrap.Cache.Events
24
24
  }
@@ -17,8 +17,8 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../bootstrap";
20
+ import { Bootstrap } from "@bootstrap"
21
21
 
22
22
  export const GetNodes = (): any => {
23
- return bootstrap.cache.nodes
23
+ return Bootstrap.Cache.Nodes
24
24
  }
@@ -17,8 +17,8 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../bootstrap";
20
+ import { Bootstrap } from "@bootstrap"
21
21
 
22
22
  export const GetRandomEvent = (): any => {
23
- return bootstrap.cache.events.features[Math.floor(Math.random() * bootstrap.cache.events.features.length)]
23
+ return Bootstrap.Cache.Events.features[Math.floor(Math.random() * Bootstrap.Cache.Events.features.length)]
24
24
  }
@@ -17,8 +17,8 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../bootstrap";
20
+ import { Bootstrap } from "@bootstrap"
21
21
 
22
22
  export const GetVersion = (): any => {
23
- return bootstrap.version
23
+ return Bootstrap.Version
24
24
  }
@@ -17,39 +17,38 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeAttributes } from "../@types/Attributes";
21
- import { EnumExpressions } from "../@enums/Expressions"
22
- import { GetAwipsType } from "../@modules/@stanza/GetAwipsType";
23
- import { CreateEvent } from "../@building/CreateEvent";
20
+ import { EnumExpressions } from "@enums/Expressions"
21
+ import { GetAwipsType } from "@stanza/GetAwipsType"
22
+ import { CreateEvent } from "@building/CreateEvent"
24
23
 
25
24
  interface CreateEventOptions {
26
- message: string
27
- awipsid?: string
25
+ Message: string
26
+ Awipsid?: string
28
27
  }
29
28
 
30
- export const ManualEvent = async (options: CreateEventOptions): Promise<void> => {
31
- const isCapEvent = options.message.includes(`<?xml`);
32
- const isCapAreaDescription = options.message.includes(`<areaDesc>`)
33
- const isVTEC = options.message.match(EnumExpressions.pvtec) != null;
34
- const isUGC = options.message.match(EnumExpressions.ugc1) != null;
29
+ export const ManualEvent = async ({ Message, Awipsid }: CreateEventOptions): Promise<void> => {
30
+ const isCapEvent = Message.includes(`<?xml`);
31
+ const isCapAreaDescription = Message.includes(`<areaDesc>`)
32
+ const isVTEC = Message.match(EnumExpressions.vtec) != null;
33
+ const isUGC = Message.match(EnumExpressions.ugc1) != null;
35
34
  const attributes = {
36
35
  "xmlns": "@atmosx/event-product-parser",
37
36
  "id": "manual_processor.0000",
38
37
  "issue": new Date().toISOString(),
39
38
  "ttaaii": "XXXXX",
40
39
  "cccc": "XXX",
41
- "awipsid": options.awipsid ?? "XXXXXX",
40
+ "awipsid": Awipsid ?? "XXXXXX",
42
41
  }
43
- const getType = GetAwipsType({ attributes })
42
+ const getType = GetAwipsType({ Attributes: attributes})
44
43
  const result = {
45
- message: options.message,
46
- attributes,
47
- isCapEvent,
48
- isVTEC,
49
- isUGC,
50
- isCapAreaDescription,
51
- isIgnored: false,
52
- isNWWS: true,
44
+ Message: Message,
45
+ Attributes: attributes,
46
+ CapEvent: isCapEvent,
47
+ VTEC: isVTEC,
48
+ UGC: isUGC,
49
+ CapAreaDescription: isCapAreaDescription,
50
+ Ignored: false,
51
+ NWWS: true,
53
52
  getType
54
53
  }
55
54
  await CreateEvent(result);
@@ -17,12 +17,12 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeStanza } from "../@types/Stanza";
21
- import { bootstrap } from "../bootstrap";
20
+ import { TypeStanza } from "types-lower/Stanza"
21
+ import { Bootstrap } from "@bootstrap"
22
22
 
23
23
  interface QueryStanzaOptions {
24
- search: string
25
- max?: number
24
+ Search: string
25
+ Max?: number
26
26
  }
27
27
 
28
28
  type QueryStanza = {
@@ -30,10 +30,10 @@ type QueryStanza = {
30
30
  stanza: string
31
31
  }
32
32
 
33
- export const QueryStanza = async (options: QueryStanzaOptions): Promise<TypeStanza[]> => {
34
- const get = await bootstrap.database.prepare(
33
+ export const QueryStanza = async ({ Search, Max }: QueryStanzaOptions): Promise<TypeStanza[]> => {
34
+ const get = await Bootstrap.Database.prepare(
35
35
  `SELECT * FROM stanzas WHERE stanza LIKE ? LIMIT ?`)
36
- .all(`%${options.search}%`, options.max ?? 100) as QueryStanza[];
36
+ .all(`%${Search}%`, Max ?? 100) as QueryStanza[];
37
37
  const events = get.map((row) => JSON.parse(row.stanza));
38
38
  return events as TypeStanza[];
39
39
  }
@@ -17,47 +17,52 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../bootstrap";
21
- import { SetWarning } from "../@modules/@utilities/SetWarning"
22
- import { SetEventEmit } from "../@modules/@utilities/SetEventEmit";
20
+ import { Bootstrap } from "@bootstrap"
21
+ import { SetWarning } from "@utilities/SetWarning"
22
+ import { SetEventEmit } from "@utilities/SetEventEmit"
23
23
 
24
24
  interface GetNodeOptions {
25
- identifier: string
26
- delete?: boolean
27
- coordinates: { longitude: number; latitude: number }
25
+ Identifier: string
26
+ Delete?: boolean
27
+ Coordinates: { Longitude: number; Latitude: number }
28
28
  }
29
29
 
30
- export const SetNode = (options: GetNodeOptions) => {
31
- const nodes = bootstrap.cache.nodes.features;
32
- const exists = nodes.find((node) => node.properties.identifier === options.identifier);
33
- if (options.delete) {
30
+ export const SetNode = ({ Identifier, Delete, Coordinates }: GetNodeOptions) => {
31
+ const nodes = Bootstrap.Cache.Nodes.features;
32
+ const exists = nodes.find((node) => node.properties.identifier === Identifier);
33
+ if (Delete) {
34
34
  if (exists) {
35
35
  const index = nodes.indexOf(exists);
36
36
  nodes.splice(index, 1);
37
+ SetWarning({ Message: `Node with identifier '${Identifier}' deleted.` })
37
38
  return SetEventEmit({
38
- event: `onNodeDelete`,
39
- metadata: {
40
- type: `node-delete`,
41
- node: exists
39
+ Event: `onNodeDelete`,
40
+ Metadata: {
41
+ Type: `node-delete`,
42
+ Node: exists
42
43
  }
43
44
  })
44
45
  }
45
- return SetWarning({ message: `Node with identifier '${options.identifier}' not found.` })
46
+ return SetWarning({ Message: `Node with identifier '${Identifier}' not found.` })
46
47
  }
47
48
  if (exists) {
48
49
  const index = nodes.indexOf(exists);
50
+ if (exists.geometry.coordinates[0] === Coordinates.Longitude && exists.geometry.coordinates[1] === Coordinates.Latitude) {
51
+ return;
52
+ }
49
53
  nodes[index] = {
50
54
  ...exists,
51
55
  geometry: {
52
56
  type: "Point",
53
- coordinates: [options.coordinates.longitude, options.coordinates.latitude]
57
+ coordinates: [Coordinates.Longitude, Coordinates.Latitude]
54
58
  }
55
59
  };
60
+ SetWarning({ Message: `Node with identifier '${Identifier}' updated.` })
56
61
  return SetEventEmit({
57
- event: `onNodeUpdate`,
58
- metadata: {
59
- type: `node-update`,
60
- node: nodes[index]
62
+ Event: `onNodeUpdate`,
63
+ Metadata: {
64
+ Type: `node-update`,
65
+ Node: nodes[index]
61
66
  }
62
67
  })
63
68
  }
@@ -65,17 +70,18 @@ export const SetNode = (options: GetNodeOptions) => {
65
70
  type: "Feature",
66
71
  geometry: {
67
72
  type: "Point",
68
- coordinates: [options.coordinates.longitude, options.coordinates.latitude]
73
+ coordinates: [Coordinates.Longitude, Coordinates.Latitude]
69
74
  },
70
75
  properties: {
71
- identifier: options.identifier
76
+ identifier: Identifier
72
77
  }
73
78
  });
79
+ SetWarning({ Message: `Node with identifier '${Identifier}' added.` })
74
80
  return SetEventEmit({
75
- event: `onNodeAdd`,
76
- metadata: {
77
- type: `node-add`,
78
- node: nodes[nodes.length - 1]
81
+ Event: `onNodeAdd`,
82
+ Metadata: {
83
+ Type: `node-add`,
84
+ Node: nodes[nodes.length - 1]
79
85
  }
80
86
  })
81
87
  }
@@ -17,26 +17,26 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeSettings } from "../@types/Settings";
21
- import { bootstrap } from "../bootstrap";
22
- import { SetWarning } from "../@modules/@utilities/SetWarning"
23
- import { SetSettings } from "../@modules/@utilities/SetSettings"
24
- import { DeployXMPP } from "../@modules/@xmpp/DeployXMPP"
25
- import { InitializeDatabase } from "../@modules/@database/InitializeDatabase";
26
- import { GetCachedEvents } from "../@modules/@database/GetCachedEvents";
27
- import { SetCronSchedule } from "../@modules/@utilities/SetCronSchedule";
28
- import { UpdateNode } from "../@manager/UpdateNode";
29
- import { UpdateEvents } from "../@manager/UpdateEvents";
30
- import { Cron } from "croner";
20
+ import { TypeSettings } from "types/Settings"
21
+ import { Bootstrap } from "@bootstrap"
22
+ import { SetWarning } from "@utilities/SetWarning"
23
+ import { SetSettings } from "@utilities/SetSettings"
24
+ import { SetCronSchedule } from "@utilities/SetCronSchedule"
25
+ import { DeployXMPP } from "@xmpp/DeployXMPP"
26
+ import { InitializeDatabase } from "@database/InitializeDatabase"
27
+ import { GetCachedEvents } from "@database/GetCachedEvents"
28
+ import { UpdateNode } from "@manager/UpdateNode"
29
+ import { UpdateEvents } from "@manager/UpdateEvents"
30
+ import { Cron } from "croner"
31
31
 
32
32
  export const StartService = async (configurations: TypeSettings): Promise<void> => {
33
- if (!bootstrap.isReady) {
33
+ if (!Bootstrap.Ready) {
34
34
  return SetWarning({
35
- message: `You can not create another instance without shutting down the current one first, please make sure to call the stop() method first!`
35
+ Message: `You can not create another instance without shutting down the current one first, please make sure to call the stop() method first!`
36
36
  })
37
37
  }
38
38
  const settings = SetSettings(configurations);
39
- bootstrap.isReady = true;
39
+ Bootstrap.Ready = true;
40
40
  await InitializeDatabase();
41
41
  if (settings.EnableWireService) {
42
42
  (async () => {
@@ -47,14 +47,14 @@ export const StartService = async (configurations: TypeSettings): Promise<void>
47
47
  await SetCronSchedule()
48
48
  let scheduleInterval = !settings.EnableWireService ? settings.NationalWeatherServiceSettings.CallbackInterval : 1;
49
49
  if (!settings.EnableWireService && scheduleInterval < 15) {
50
- SetWarning({ message: `Schedule interval of ${scheduleInterval} seconds is too low, setting to 15 seconds` })
51
- bootstrap.settings.NationalWeatherServiceSettings.CallbackInterval = 15;
50
+ SetWarning({ Message: `Schedule interval of ${scheduleInterval} seconds is too low, setting to 15 seconds` })
51
+ Bootstrap.Settings.NationalWeatherServiceSettings.CallbackInterval = 15;
52
52
  scheduleInterval = 15;
53
53
  }
54
- bootstrap.cron = new Cron(`*/${scheduleInterval} * * * * *`, async () => {
54
+ Bootstrap.Job = new Cron(`*/${scheduleInterval} * * * * *`, async () => {
55
55
  await SetCronSchedule();
56
56
  })
57
- bootstrap.cron = new Cron(`* * * * * *`, async () => {
57
+ Bootstrap.Job = new Cron(`* * * * * *`, async () => {
58
58
  await UpdateNode();
59
59
  await UpdateEvents();
60
60
  })
@@ -17,16 +17,16 @@
17
17
 
18
18
  */
19
19
 
20
- import { bootstrap } from "../bootstrap";
20
+ import { Bootstrap } from "@bootstrap"
21
21
 
22
22
  export const StopService = async (): Promise<void> => {
23
- if (bootstrap.isReady) {
24
- bootstrap.isReady = false;
25
- if (bootstrap.session_xmpp) {
26
- try { await bootstrap.session_xmpp.stop(); } catch {}
27
- bootstrap.cache.isConnected = false;
28
- bootstrap.cache.sigHault = true;
29
- bootstrap.session_xmpp = null;
23
+ if (Bootstrap.Ready) {
24
+ Bootstrap.Ready = false;
25
+ if (Bootstrap.Session) {
26
+ try { await Bootstrap.Session.stop(); } catch {}
27
+ Bootstrap.Cache.Connected = false;
28
+ Bootstrap.Cache.Hault = true;
29
+ Bootstrap.Session = null;
30
30
  }
31
31
  }
32
32
  }
@@ -19,7 +19,7 @@
19
19
 
20
20
  export const EnumExpressions: { [key: string]: RegExp } = {
21
21
  location: new RegExp(/^([A-Za-z.\-' ]+),\s*([A-Z]{2})$/),
22
- pvtec: new RegExp(`[OTEX].(NEW|CON|EXT|EXA|EXB|UPG|CAN|EXP|COR|ROU).[A-Z]{4}.[A-Z]{2}.[WAYSFON].[0-9]{4}.[0-9]{6}T[0-9]{4}Z-[0-9]{6}T[0-9]{4}Z`, "g"),
22
+ vtec: new RegExp(`[OTEX].(NEW|CON|EXT|EXA|EXB|UPG|CAN|EXP|COR|ROU).[A-Z]{4}.[A-Z]{2}.[WAYSFON].[0-9]{4}.[0-9]{6}T[0-9]{4}Z-[0-9]{6}T[0-9]{4}Z`, "g"),
23
23
  hvtec: new RegExp(`[a-zA-Z0-9]{4}.[A-Z0-9].[A-Z]{2}.[0-9]{6}T[0-9]{4}Z.[0-9]{6}T[0-9]{4}Z.[0-9]{6}T[0-9]{4}Z.[A-Z]{2}`, "imu"),
24
24
  wmo: new RegExp(`[A-Z0-9]{6}\\s[A-Z]{4}\\s\\d{6}`, "imu"),
25
25
  ugc1: new RegExp(`(\\w{2}[CZ](\\d{3}((-|>)\\s?(\\n\\n)?))+)`, "imu"),
@@ -148,7 +148,7 @@ export const EnumTags = {
148
148
  { match: /Source\.\.\.Doppler Radar/i, tag: "Confirmed By Radar" },
149
149
  { match: /Source\.\.\.Automated Gauges/i, tag: "Confirmed By Automated Gauges" },
150
150
  { match: /Source\.\.\.Radar Confirmed/i, tag: "Confirmed By Radar" },
151
- { match: /Source\.\.\.Radar Indicated/i, tag: "Indicated By Radar" },
151
+ { match: /Source\.\.\.Radar Indicated/i, tag: "Radar Indicated" },
152
152
  { match: /Source\.\.\.Public/i, tag: "Confirmed By Public" },
153
153
  { match: /Source\.\.\.Amateur Radio/i, tag: "Confirmed By Amateur Radio" },
154
154
  { match: /Source\.\.\.Emergency Management/i, tag: "Confirmed By Emergency Management" },
@@ -17,22 +17,22 @@
17
17
 
18
18
  */
19
19
 
20
- import { TypeStanzaCompiled } from "../@types/StanzaCompiled"
21
- import { TypePVTEC } from "../@types/VTEC";
22
- import { EnumICAO } from "../@enums/ICAO";
23
- import { bootstrap } from "../bootstrap";
24
- import { GetEventTracking } from "../@building/GetEventTracking";
25
- import { VTECExtract } from "../@parsers/@pvtec/VTECExtract"
26
- import { GetEventTags } from "../@building/GetEventTags";
27
- import { GetTextFromProduct } from "../@parsers/@text/GetTextFromProduct";
28
- import { SetDebug } from "../@modules/@utilities/SetDebug";
20
+ import { TypeStanzaCompiled } from "types/StanzaCompiled"
21
+ import { TypeVTEC } from "types/VTEC"
22
+ import { EnumICAO } from "@enums/ICAO"
23
+ import { Bootstrap } from "@bootstrap"
24
+ import { GetEventTracking } from "@building/GetEventTracking"
25
+ import { VTECExtract } from "@parsers/vtec/VTECExtract"
26
+ import { GetEventTags } from "@building/GetEventTags"
27
+ import { GetTextFromProduct } from "@parsers/text/GetTextFromProduct"
28
+ import { SetDebug } from "@utilities/SetDebug"
29
29
 
30
- export const ParseAPI = async (stanza: TypeStanzaCompiled): Promise<void> => {
31
- const messages = Object.values(JSON.parse(stanza.message).features) as any;
30
+ export const ParseAPI = async (Stanza: TypeStanzaCompiled): Promise<void> => {
31
+ const messages = Object.values(JSON.parse(Stanza.Message).features) as any;
32
32
  for (const feature of messages) {
33
33
  const tick = performance.now();
34
- const pVtec = VTECExtract(feature?.properties?.parameters?.VTEC?.[0]) ?? null as TypePVTEC[]
35
- bootstrap.cache.processed.push({
34
+ const VTEC = VTECExtract(feature?.properties?.parameters?.VTEC?.[0]) ?? null as TypeVTEC[]
35
+ Bootstrap.Cache.Parsed.push({
36
36
  type: `Feature`,
37
37
  geometry: {
38
38
  type: `Point`,
@@ -45,13 +45,18 @@ export const ParseAPI = async (stanza: TypeStanzaCompiled): Promise<void> => {
45
45
  issued: feature?.properties?.sent ? new Date(feature?.properties?.sent).toISOString() : null,
46
46
  expires: feature?.properties?.expires ? new Date(feature?.properties?.expires).toISOString() : null,
47
47
  locations: feature?.properties?.areaDesc ?? null,
48
- locations_array: feature?.properties?.areaDesc ? feature?.properties?.areaDesc.split(';') : [],
48
+ locations_array: feature?.properties?.areaDesc ? feature?.properties?.areaDesc.split('; ') : [],
49
+ location_states: [...new Set(
50
+ feature?.properties?.areaDesc?.split(';')
51
+ ?.map((location: string) => location.match(/,\s*([A-Z]{2})\b/)?.[1])
52
+ .filter(Boolean) ?? []
53
+ )],
49
54
  description: feature?.properties?.description ?? null,
50
55
  attributes: feature?.properties?.attributes ?? {},
51
56
  geocode: {
52
57
  office: {
53
- office: pVtec ? pVtec?.[0]?.tracking.split(`.`)[0] : null,
54
- name: EnumICAO[pVtec ? pVtec?.[0]?.tracking.split(`.`)[0] : null] ?? null,
58
+ office: VTEC ? VTEC?.[0]?.Tracking.split(`.`)[0] : null,
59
+ name: EnumICAO[VTEC ? VTEC?.[0]?.Tracking.split(`.`)[0] : null] ?? null,
55
60
  },
56
61
  organization: feature?.properties?.parameters?.WMOidentifier?.[0],
57
62
  ugc: feature?.properties?.geocode?.UGC ?? [],
@@ -61,9 +66,9 @@ export const ParseAPI = async (stanza: TypeStanzaCompiled): Promise<void> => {
61
66
  parameters: {
62
67
  tags: GetEventTags(feature?.properties?.description),
63
68
  instructions: feature?.properties?.instruction ?? null,
64
- source: GetTextFromProduct({ message: feature?.properties?.description, find: [`SOURCE...`], removal: [`.`]}) ?? null,
65
- hazards: GetTextFromProduct({ message: feature?.properties?.description, find: [`HAZARD...`], removal: [`.`]}) ?? null,
66
- impacts: GetTextFromProduct({ message: feature?.properties?.description, find: [`IMPACT...`], removal: [`.`]}) ?? null,
69
+ source: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`SOURCE...`], Removal: [`.`]}) ?? null,
70
+ hazards: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`HAZARD...`], Removal: [`.`]}) ?? null,
71
+ impacts: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`IMPACT...`], Removal: [`.`]}) ?? null,
67
72
  estimated_hail_size: feature?.properties?.parameters?.maxHailSize?.[0] ?? null,
68
73
  estimated_wind_gusts: feature?.properties?.parameters?.maxWindGust?.[0] ?? null,
69
74
  damage_threat: feature?.properties?.parameters?.thunderstormDamageThreat?.[0] ?? null,
@@ -73,33 +78,33 @@ export const ParseAPI = async (stanza: TypeStanzaCompiled): Promise<void> => {
73
78
  hail_threat: feature?.properties?.parameters?.hailThreat?.[0] ?? null,
74
79
  },
75
80
  discussion_parameters: {
76
- discussion_number: GetTextFromProduct({ message: feature?.properties?.description, find: [`Mesoscale Discussion `], removal: [`Mesoscale Discussion`, `Number`, `...`] })?.toString()?.padStart(4, "0") ?? null,
77
- discussion_concerning: GetTextFromProduct({ message: feature?.properties?.description, find: [`Concerning...`] }) ?? null,
78
- discussion_max_tornado: GetTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
79
- discussion_max_hail: GetTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
80
- discussion_max_wind: GetTextFromProduct({ message: feature?.properties?.description, find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
81
- discussion_watch_issuance: GetTextFromProduct({ message: feature?.properties?.description, find: [`Probability of Watch Issuance...`], removal: [`percent`]}) ?? null,
81
+ discussion_number: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`Mesoscale Discussion `], Removal: [`Mesoscale Discussion`, `Number`, `...`] })?.toString()?.padStart(4, "0") ?? null,
82
+ discussion_concerning: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`Concerning...`] }) ?? null,
83
+ discussion_max_tornado: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`MOST PROBABLE PEAK TORNADO INTENSITY...`] }) ?? null,
84
+ discussion_max_hail: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`MOST PROBABLE PEAK HAIL SIZE...`] }) ?? null,
85
+ discussion_max_wind: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`MOST PROBABLE PEAK WIND GUST...`] }) ?? null,
86
+ discussion_watch_issuance: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`Probability of Watch Issuance...`], Removal: [`percent`]}) ?? null,
82
87
  },
83
88
  watch_parameters: {
84
- watch_number: (pVtec?.[0]?.is_watch) && (GetTextFromProduct({ message: feature?.properties?.description, find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim()?.toString()?.padStart(4, "0") ?? pVtec?.[0]?.tracking?.slice(-4)?.toString()?.padStart(4, "0") ?? null),
89
+ watch_number: (VTEC?.[0]?.Watch) && (GetTextFromProduct({ Message: feature?.properties?.description, Find: [`ITIES FOR`, `UPDATE FOR`, `Watch Number `], Removal: [`%`, `<`, `:`] })?.replace(/(WT|WS|)/g, '')?.trim()?.toString()?.padStart(4, "0") ?? VTEC?.[0]?.Tracking?.slice(-4)?.toString()?.padStart(4, "0") ?? null),
85
90
  watch_type: feature?.properties?.description.includes(`TORNADO WATCH`) ? `Tornado` : feature?.properties?.description.includes(`SEVERE`) ? `Severe` : null,
86
- additional_tornadoes_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 2 OR MORE TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
87
- strong_tornadoes_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], removal: [`%`, `<`, `:`] }) ?? null,
88
- severe_wind_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
89
- severe_hail_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
90
- hail_2in_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], removal: [`%`, `<`, `:`] }) ?? null,
91
- combined_hail_wind_probability: GetTextFromProduct({ message: feature?.properties?.description, find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], removal: [`%`, `<`, `:`] }) ?? null,
92
- max_hail_in: GetTextFromProduct({ message: feature?.properties?.description, find: [`MAX HAIL /INCHES/`], removal: [`%`, `<`, `:`] }) ?? null,
93
- max_wind_surface: GetTextFromProduct({ message: feature?.properties?.description, find: [`MAX WIND GUSTS SURFACE /KNOTS/`], removal: [`%`, `<`, `:`] }) ?? null,
94
- max_tops_x100feet: GetTextFromProduct({ message: feature?.properties?.description, find: [`MAX TOPS /X 100 FEET/`], removal: [`%`, `<`, `:`] }) ?? null,
95
- pds_watch: (GetTextFromProduct({ message: feature?.properties?.description, find: [`PARTICULARLY DANGEROUS SITUATION`], removal: [`%`, `<`, `:`] }) === `YES`)
91
+ additional_tornadoes_probability: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`PROB OF 2 OR MORE TORNADOES`], Removal: [`%`, `<`, `:`] }) ?? null,
92
+ strong_tornadoes_probability: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`PROB OF 1 OR MORE STRONG /EF2-EF5/ TORNADOES`], Removal: [`%`, `<`, `:`] }) ?? null,
93
+ severe_wind_probability: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`PROB OF 10 OR MORE SEVERE WIND EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
94
+ severe_hail_probability: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`PROB OF 10 OR MORE SEVERE HAIL EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
95
+ hail_2in_probability: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`PROB OF 1 OR MORE HAIL EVENTS >= 2 INCHES`], Removal: [`%`, `<`, `:`] }) ?? null,
96
+ combined_hail_wind_probability: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`PROB OF 6 OR MORE COMBINED SEVERE HAIL/WIND EVENTS`], Removal: [`%`, `<`, `:`] }) ?? null,
97
+ max_hail_in: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`MAX HAIL /INCHES/`], Removal: [`%`, `<`, `:`] }) ?? null,
98
+ max_wind_surface: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`MAX WIND GUSTS SURFACE /KNOTS/`], Removal: [`%`, `<`, `:`] }) ?? null,
99
+ max_tops_x100feet: GetTextFromProduct({ Message: feature?.properties?.description, Find: [`MAX TOPS /X 100 FEET/`], Removal: [`%`, `<`, `:`] }) ?? null,
100
+ pds_watch: (GetTextFromProduct({ Message: feature?.properties?.description, Find: [`PARTICULARLY DANGEROUS SITUATION`], Removal: [`%`, `<`, `:`] }) === `YES`)
96
101
  },
97
102
  metadata: {
98
103
  ms: performance.now() - tick,
99
104
  source: `events.api`,
100
- tracking: GetEventTracking({ type: `API`, organization: { wmoidentifier: feature?.properties?.parameters?.WMOidentifier?.[0], featureId: feature?.id}, vtec: pVtec?.[0]}),
105
+ tracking: GetEventTracking({ Type: `API`, WMO: { Identifier: feature?.properties?.parameters?.WMOidentifier?.[0], ID: feature?.id}, VTEC: VTEC?.[0]}),
101
106
  header: `ZCZC-ATMOSX-${feature?.properties?.parameters?.WMOidentifier}`,
102
- vtec: pVtec?.[0],
107
+ vtec: VTEC?.[0],
103
108
  hvtec: null,
104
109
  raw: feature?.properties?.description,
105
110
  history: [
@@ -112,6 +117,6 @@ export const ParseAPI = async (stanza: TypeStanzaCompiled): Promise<void> => {
112
117
  }
113
118
  }
114
119
  })
115
- SetDebug({ title: `ParseAPI`, message: `${Math.round(performance.now() - tick)}ms` })
120
+ SetDebug({ Title: `ParseAPI`, Message: `${Math.round(performance.now() - tick)}ms` })
116
121
  }
117
122
  }