@atmosx/event-product-parser 3.0.63 → 3.0.75

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 (164) hide show
  1. package/.github/docs/docs-functions.md +1 -1
  2. package/.github/docs/docs-general-configurations.md +1 -11
  3. package/.github/docs/docs-integrations.md +3 -2
  4. package/README.md +4 -4
  5. package/dist/cjs/index.cjs +3590 -623
  6. package/dist/esm/index.mjs +3589 -624
  7. package/package.json +11 -4
  8. package/src/bootstrap.ts +50 -33
  9. package/src/{@building → building}/CreateEvent.ts +10 -10
  10. package/src/{@building → building}/GetCleanedEvent.ts +2 -2
  11. package/src/{@building → building}/GetEventAttachments.ts +12 -10
  12. package/src/building/GetEventDirection.ts +28 -0
  13. package/src/{@building → building}/GetEventEnhancedName.ts +5 -6
  14. package/src/{@building → building}/GetEventGeometry.ts +19 -13
  15. package/src/{@building → building}/GetEventHeader.ts +4 -4
  16. package/src/{@building → building}/GetEventNodes.ts +16 -14
  17. package/src/{@building → building}/GetEventOffice.ts +5 -5
  18. package/src/building/GetEventPopulation.ts +58 -0
  19. package/src/{@building → building}/GetEventProperties.ts +23 -18
  20. package/src/{@building → building}/GetEventSignature.ts +8 -8
  21. package/src/{@building → building}/GetEventTags.ts +3 -3
  22. package/src/{@core/CreateListener.ts → building/GetEventTheme.ts} +8 -6
  23. package/src/{@building → building}/GetEventTracking.ts +6 -6
  24. package/src/{@modules/@eas/GenerateEASMessage.ts → components/audio/GenerateAudioMessage.ts} +32 -33
  25. package/src/{@modules/@eas → components/audio/components}/GetCleanDescription.ts +2 -2
  26. package/src/{@modules/@eas → components/audio/components}/GetFloatPCM16.ts +2 -2
  27. package/src/{@modules/@eas → components/audio/components}/GetMergedPCM16.ts +2 -2
  28. package/src/{@modules/@eas → components/audio/components}/GetPCM16.ts +2 -2
  29. package/src/{@modules/@eas → components/audio/components}/GetPCMToFloat.ts +2 -2
  30. package/src/{@modules/@eas → components/audio/components}/GetSampledPCM16.ts +2 -2
  31. package/src/{@modules/@eas → components/audio/components}/GetTTS.ts +5 -3
  32. package/src/{@modules/@eas → components/audio/components}/GetWavPCM16.ts +2 -2
  33. package/src/{@modules/@eas → components/audio/components}/SetAFSK.ts +2 -2
  34. package/src/{@modules/@eas → components/audio/components}/SetAsciiToBits.ts +2 -2
  35. package/src/{@modules/@eas → components/audio/components}/SetAttentionTone.ts +2 -2
  36. package/src/{@modules/@eas → components/audio/components}/SetNoise.ts +4 -4
  37. package/src/{@modules/@eas → components/audio/components}/SetRadioEffect.ts +4 -4
  38. package/src/{@modules/@eas → components/audio/components}/SetSameHeader.ts +5 -5
  39. package/src/{@modules/@utilities/SetWarning.ts → components/database/CreateQuery.ts} +18 -13
  40. package/src/{@modules/@database → components/database}/GetCachedEvents.ts +14 -9
  41. package/src/components/database/ImportBoundaries.ts +168 -0
  42. package/src/{@modules/@database → components/database}/ImportBroadcastify.ts +8 -17
  43. package/src/components/database/ImportCities.ts +87 -0
  44. package/src/{@modules/@database → components/database}/ImportShapefiles.ts +14 -16
  45. package/src/{@modules/@database → components/database}/ImportStanza.ts +13 -17
  46. package/src/components/database/InitializeDatabase.ts +71 -0
  47. package/src/components/images/GenerateGraphic.ts +242 -0
  48. package/src/components/images/components/CreateRectangle.ts +22 -0
  49. package/src/components/images/components/CreateText.ts +22 -0
  50. package/src/components/images/modules/CreateSVG.ts +37 -0
  51. package/src/components/images/modules/GetGeographicalBoundaries.ts +72 -0
  52. package/src/components/images/modules/GetGeographicalCities.ts +58 -0
  53. package/src/components/images/modules/GetGeographicalEvents.ts +48 -0
  54. package/src/components/images/modules/GetGeometryBounds.ts +82 -0
  55. package/src/components/images/modules/GetParsedBoundary.ts +58 -0
  56. package/src/components/images/modules/GetSVGPath.ts +53 -0
  57. package/src/components/images/modules/NormalizePolygon.ts +57 -0
  58. package/src/{@modules/@stanza → components/stanza}/GetAwipsType.ts +4 -4
  59. package/src/{@modules/@stanza → components/stanza}/ValidateStanza.ts +6 -6
  60. package/src/{@modules/@utilities → components/utilities}/CreateHttp.ts +2 -2
  61. package/src/{@parsers/@text → components/utilities}/GetEmbededText.ts +6 -4
  62. package/src/{@modules/@utilities → components/utilities}/GetFormattedTime.ts +2 -2
  63. package/src/{@modules/@utilities → components/utilities}/GetLatestIssuance.ts +2 -2
  64. package/src/{@modules/@utilities → components/utilities}/GetMatched.ts +2 -2
  65. package/src/{@modules/@utilities → components/utilities}/GetShapeNearestPoint.ts +2 -2
  66. package/src/{@parsers/@text → components/utilities}/GetStringText.ts +7 -7
  67. package/src/components/utilities/GetUnionPolygon.ts +36 -0
  68. package/src/{@modules/@utilities → components/utilities}/QueueManager.ts +2 -2
  69. package/src/{@modules/@utilities → components/utilities}/SetCronSchedule.ts +37 -25
  70. package/src/{@modules/@utilities → components/utilities}/SetDebug.ts +4 -4
  71. package/src/{@modules/@utilities → components/utilities}/SetEventEmit.ts +8 -7
  72. package/src/{@modules/@utilities → components/utilities}/SetSettings.ts +4 -4
  73. package/src/{@modules/@utilities → components/utilities}/SetSleep.ts +2 -2
  74. package/src/{@modules/@utilities → components/utilities}/SetTimeoutAction.ts +3 -3
  75. package/src/components/utilities/SetWarning.ts +47 -0
  76. package/src/{@modules/@xmpp → components/xmpp}/DeployXMPP.ts +12 -12
  77. package/src/{@modules/@xmpp → components/xmpp}/ErrorXMPP.ts +3 -3
  78. package/src/{@modules/@xmpp → components/xmpp}/OfflineXMPP.ts +4 -4
  79. package/src/{@modules/@xmpp → components/xmpp}/OnlineXMPP.ts +5 -5
  80. package/src/{@modules/@xmpp → components/xmpp}/ReconnectXMPP.ts +6 -6
  81. package/src/{@modules/@xmpp → components/xmpp}/StanzaXMPP.ts +8 -8
  82. package/src/{@core → core}/ClearEvents.ts +4 -4
  83. package/src/{@core → core}/GetEvents.ts +3 -3
  84. package/src/{@core → core}/GetNodes.ts +3 -3
  85. package/src/{@core → core}/GetRandomEvent.ts +3 -3
  86. package/src/{@core → core}/GetVersion.ts +3 -3
  87. package/src/{@core → core}/ManualEvent.ts +6 -6
  88. package/src/{@core → core}/QueryStanza.ts +9 -8
  89. package/src/{@core → core}/SetNode.ts +5 -5
  90. package/src/{@core → core}/StartService.ts +13 -12
  91. package/src/{@core → core}/StopService.ts +3 -3
  92. package/src/{@enums → enums}/AWIPS.ts +2 -2
  93. package/src/{@enums → enums}/Actions.ts +2 -2
  94. package/src/{@enums → enums}/Cancellation.ts +2 -2
  95. package/src/{@enums → enums}/Causes.ts +2 -2
  96. package/src/{@enums → enums}/Correlations.ts +2 -2
  97. package/src/{@enums → enums}/Enhanced.ts +4 -3
  98. package/src/{@enums → enums}/Events.ts +2 -2
  99. package/src/{@enums → enums}/Expressions.ts +2 -2
  100. package/src/{@enums → enums}/GlobalFilter.ts +2 -2
  101. package/src/{@enums → enums}/Hail.ts +2 -2
  102. package/src/{@enums → enums}/ICAO.ts +2 -2
  103. package/src/{@enums → enums}/Matches.ts +8 -3
  104. package/src/{@enums → enums}/Products.ts +2 -2
  105. package/src/{@enums → enums}/Records.ts +2 -2
  106. package/src/{@enums → enums}/Severity.ts +2 -2
  107. package/src/{@enums → enums}/Shapefiles.ts +2 -2
  108. package/src/{@enums → enums}/States.ts +68 -4
  109. package/src/{@enums → enums}/Status.ts +2 -2
  110. package/src/{@enums → enums}/Strings.ts +2 -2
  111. package/src/{@enums → enums}/Tags.ts +8 -3
  112. package/src/{@enums → enums}/Testing.ts +2 -2
  113. package/src/enums/Themes.ts +70 -0
  114. package/src/{@events → events}/ParseAPI.ts +28 -17
  115. package/src/{@events → events}/ParseText.ts +13 -11
  116. package/src/{@events → events}/ParseUGC.ts +15 -14
  117. package/src/{@events → events}/ParseVTEC.ts +18 -16
  118. package/src/index.ts +49 -32
  119. package/src/{@manager → manager}/MakeEvents.ts +16 -28
  120. package/src/{@manager → manager}/RemoveEvent.ts +9 -9
  121. package/src/{@manager → manager}/SetHash.ts +5 -5
  122. package/src/{@manager → manager}/UpdateEvents.ts +6 -6
  123. package/src/{@manager → manager}/UpdateNode.ts +6 -6
  124. package/src/{@manager → manager}/ValidateEvents.ts +31 -20
  125. package/src/{@parsers/@hvtec → parsers/hvtec}/HVExtract.ts +7 -7
  126. package/src/{@parsers/@text → parsers/text}/GetDescriptionFromProduct.ts +3 -3
  127. package/src/parsers/text/GetPolygonFromProduct.ts +71 -0
  128. package/src/{@parsers/@text → parsers/text}/GetTextFromProduct.ts +2 -2
  129. package/src/{@parsers/@ugc → parsers/ugc}/GetCache.ts +4 -4
  130. package/src/{@parsers/@ugc → parsers/ugc}/GetExpiry.ts +2 -2
  131. package/src/{@parsers/@ugc → parsers/ugc}/GetHeader.ts +3 -3
  132. package/src/{@parsers/@ugc → parsers/ugc}/GetLocations.ts +9 -9
  133. package/src/parsers/ugc/GetZonePolygon.ts +73 -0
  134. package/src/{@parsers/@ugc → parsers/ugc}/GetZones.ts +2 -2
  135. package/src/{@parsers/@ugc → parsers/ugc}/SetCache.ts +4 -4
  136. package/src/{@parsers/@ugc → parsers/ugc}/UGCExtract.ts +9 -9
  137. package/src/{@parsers/@vtec → parsers/vtec}/GetExpiry.ts +2 -2
  138. package/src/{@parsers/@vtec → parsers/vtec}/VTECExtract.ts +9 -9
  139. package/src/{@types-lower → static}/Attributes.ts +2 -3
  140. package/src/{@types-lower → static}/Event.ts +7 -6
  141. package/src/{@types-lower → static}/Properties.ts +17 -4
  142. package/src/{@types-lower → static}/Stanza.ts +3 -3
  143. package/src/{@tasks → tasks}/CreateTasks.ts +40 -34
  144. package/src/{@tasks → tasks}/TaskGenerateJSON.ts +2 -2
  145. package/src/{@tasks → tasks}/TaskGenerateText.ts +2 -2
  146. package/src/{@tasks → tasks}/TaskSendNTFY.ts +29 -25
  147. package/src/{@tasks → tasks}/TaskSendWebhook.ts +22 -15
  148. package/src/{@types → types}/Actions.ts +3 -3
  149. package/src/{@types → types}/HVTEC.ts +2 -2
  150. package/src/{@types → types}/Hash.ts +2 -2
  151. package/src/types/Nodes.ts +29 -0
  152. package/src/{@types → types}/Settings.ts +17 -8
  153. package/src/{@types → types}/StanzaCompiled.ts +3 -3
  154. package/src/{@types → types}/UGC.ts +2 -2
  155. package/src/{@types → types}/VTEC.ts +2 -2
  156. package/tools/build.js +2 -0
  157. package/tsconfig.json +25 -18
  158. package/src/@modules/@database/InitializeDatabase.ts +0 -59
  159. package/src/@modules/@utilities/GetSettings.ts +0 -25
  160. package/src/@modules/@utilities/SetListener.ts +0 -30
  161. package/src/@parsers/@text/GetPolygonFromProduct.ts +0 -53
  162. package/src/@parsers/@text/GetXML.ts +0 -61
  163. package/src/@parsers/@ugc/GetZonePolygon.ts +0 -111
  164. package/src/@tasks/TaskGenerateAudio.ts +0 -34
@@ -0,0 +1,168 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { EnumStateFIPS } from "@Enums/States"
21
+ import { Bootstrap } from "@Bootstrap"
22
+ import { CreateHttp } from "@Utilities/CreateHttp"
23
+ import { CreateQuery } from "@Database/CreateQuery"
24
+ import { SetWarning } from "@Utilities/SetWarning"
25
+ import { feature } from "topojson-client"
26
+
27
+ type BoundaryRow = {
28
+ id: string
29
+ type: `state` | `county`
30
+ state: string
31
+ name: string
32
+ geometry: string
33
+ }
34
+
35
+ export const ImportBoundaries = async (): Promise<void> => {
36
+ try {
37
+ const existing = CreateQuery({ Query: `SELECT type, COUNT(*) AS count FROM boundaries GROUP BY type`}) as { type: string, count: number }[]
38
+ const existingStates = existing.find(row => row.type === `state`)?.count ?? 0
39
+ const existingCounties = existing.find(row => row.type === `county`)?.count ?? 0
40
+
41
+ if (existingStates > 0 || existingCounties > 0) {
42
+ SetWarning({ Message: `Boundary database already contains ${existingStates} states and ${existingCounties} counties, skipping import` })
43
+ return
44
+ }
45
+
46
+ const boundaries = await CreateHttp({
47
+ URL: Bootstrap.Settings.BoundarySettings.BoundaryDatabase,
48
+ Timeout: 5000
49
+ })
50
+
51
+ if (boundaries.error || !boundaries.message) {
52
+ SetWarning({ Message: `Failed to download boundary database` })
53
+ return
54
+ }
55
+
56
+ let database: any
57
+
58
+ try {
59
+ database = JSON.parse(boundaries.message)
60
+ } catch {
61
+ SetWarning({ Message: `Failed to parse boundary database` })
62
+ return
63
+ }
64
+
65
+ if (database?.type !== `Topology` || !database?.objects?.states || !database?.objects?.counties) {
66
+ SetWarning({ Message: `Boundary database is missing states or counties` })
67
+ return
68
+ }
69
+
70
+ let states: any
71
+ let counties: any
72
+
73
+ try {
74
+ states = feature(database, database.objects.states)
75
+ counties = feature(database, database.objects.counties)
76
+ } catch (error: unknown) {
77
+ const message = error instanceof Error ? error.message : String(error)
78
+ SetWarning({ Message: `Failed to convert boundary database: ${message}` })
79
+ return
80
+ }
81
+
82
+ if (!Array.isArray(states?.features) || !Array.isArray(counties?.features)) {
83
+ SetWarning({ Message: `Boundary database contains invalid state or county data` })
84
+ return
85
+ }
86
+
87
+ const insert = `INSERT OR REPLACE INTO boundaries (id, type, state, name, geometry) VALUES (?, ?, ?, ?, ?)`
88
+ const stateRows: BoundaryRow[] = []
89
+ const countyRows: BoundaryRow[] = []
90
+ let skippedStates = 0
91
+ let skippedCounties = 0
92
+
93
+ for (const state of states.features) {
94
+ if (!state?.geometry || state.id === undefined || state.id === null) {
95
+ skippedStates++
96
+ continue
97
+ }
98
+
99
+ const fips = String(state.id).padStart(2, `0`)
100
+ const abbreviation = EnumStateFIPS[fips]
101
+
102
+ if (!abbreviation) {
103
+ skippedStates++
104
+ continue
105
+ }
106
+
107
+ stateRows.push({
108
+ id: fips,
109
+ type: `state`,
110
+ state: abbreviation,
111
+ name: state.properties?.name ?? abbreviation,
112
+ geometry: JSON.stringify(state.geometry)
113
+ })
114
+ }
115
+
116
+ for (const county of counties.features) {
117
+ if (!county?.geometry || county.id === undefined || county.id === null) {
118
+ skippedCounties++
119
+ continue
120
+ }
121
+
122
+ const fips = String(county.id).padStart(5, `0`)
123
+ const stateFIPS = fips.slice(0, 2)
124
+ const abbreviation = EnumStateFIPS[stateFIPS]
125
+
126
+ if (!abbreviation) {
127
+ skippedCounties++
128
+ continue
129
+ }
130
+
131
+ countyRows.push({
132
+ id: fips,
133
+ type: `county`,
134
+ state: abbreviation,
135
+ name: county.properties?.name ?? fips,
136
+ geometry: JSON.stringify(county.geometry)
137
+ })
138
+ }
139
+
140
+ SetWarning({ Message: `Importing ${stateRows.length} states and ${countyRows.length} counties` })
141
+
142
+ const transaction = Bootstrap.Database.transaction((rows: BoundaryRow[]) => {
143
+ for (const row of rows) {
144
+ CreateQuery({
145
+ Query: insert,
146
+ Parameters: [row.id, row.type, row.state, row.name, row.geometry]
147
+ })
148
+ }
149
+ })
150
+
151
+ transaction(stateRows)
152
+ transaction(countyRows)
153
+
154
+ const imported = CreateQuery({ Query: `SELECT type, COUNT(*) AS count FROM boundaries GROUP BY type`}) as { type: string, count: number }[]
155
+ const importedStates = imported.find(row => row.type === `state`)?.count ?? 0
156
+ const importedCounties = imported.find(row => row.type === `county`)?.count ?? 0
157
+
158
+ if (importedStates !== stateRows.length || importedCounties !== countyRows.length) {
159
+ SetWarning({ Message: `Boundary import verification failed: ${importedStates} states and ${importedCounties} counties` })
160
+ return
161
+ }
162
+
163
+ SetWarning({ Message: `Imported ${importedStates} states and ${importedCounties} counties` })
164
+ } catch (error: unknown) {
165
+ const message = error instanceof Error ? error.message : String(error)
166
+ SetWarning({ Message: `An error occurred while importing boundaries: ${message}` })
167
+ }
168
+ }
@@ -11,38 +11,29 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { Bootstrap } from "@bootstrap"
21
- import { CreateHttp } from "@utilities/CreateHttp"
22
- import { SetWarning } from "@utilities/SetWarning"
20
+ import { Bootstrap } from "@Bootstrap"
21
+ import { CreateHttp } from "@Utilities/CreateHttp"
22
+ import { SetWarning } from "@Utilities/SetWarning"
23
+ import { CreateQuery } from "@Database/CreateQuery";
23
24
 
24
25
  export const ImportBroadcastify = async (): Promise<void> => {
25
26
  const settings = Bootstrap.Settings;
26
-
27
- const isBroadcastifyImported = Bootstrap.Database
28
- .prepare(`SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';`)
29
- .get();
30
-
31
- if (!settings.BroadcastifySettings.BroadcastifyAttachments) { return }
32
- if (isBroadcastifyImported) { return }
33
-
34
27
  const broadcastify = await CreateHttp({
35
28
  URL: settings.BroadcastifySettings.BroadcastifyDatabase,
36
29
  Timeout: 5000,
37
30
  });
38
31
  if (!broadcastify.error) {
39
- Bootstrap.Database.prepare(`CREATE TABLE broadcastify ( state TEXT, county TEXT, feed TEXT, type TEXT, link TEXT);`)
40
- .run();
41
32
  const states = JSON.parse(broadcastify.message);
42
- const insert = Bootstrap.Database.prepare(`INSERT INTO broadcastify (state, county, feed, type, link) VALUES (?, ?, ?, ?, ?)`);
33
+ const insert = `INSERT INTO broadcastify (state, county, feed, type, link) VALUES (?, ?, ?, ?, ?)`;
43
34
  const transaction = Bootstrap.Database.transaction((rows: any[]) => {
44
35
  for (const row of rows) {
45
- insert.run(row);
36
+ CreateQuery({ Query: insert, Parameters: row });
46
37
  }
47
38
  });
48
39
  const batch: any[] = [];
@@ -0,0 +1,87 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+ import { EnumStates } from "@Enums/States"
20
+ import { Bootstrap } from "@Bootstrap"
21
+ import { CreateHttp } from "@Utilities/CreateHttp"
22
+ import { CreateQuery } from "@Database/CreateQuery"
23
+ import { SetWarning } from "@Utilities/SetWarning"
24
+
25
+ interface CityRow {
26
+ id: string
27
+ name: string
28
+ state: string
29
+ county: string
30
+ population: number | string
31
+ lat: number | string
32
+ lon: number | string
33
+ }
34
+
35
+ export const ImportCities = async (): Promise<void> => {
36
+ const cities = await CreateHttp({
37
+ URL: Bootstrap.Settings.BoundarySettings.CityDatabase,
38
+ Timeout: 5000
39
+ })
40
+
41
+ if (cities.error || !cities.message) {
42
+ SetWarning({ Message: `Failed to download city database` })
43
+ return
44
+ }
45
+
46
+ let database: unknown
47
+
48
+ try {
49
+ database = JSON.parse(cities.message)
50
+ } catch {
51
+ SetWarning({ Message: `Failed to parse city database` })
52
+ return
53
+ }
54
+
55
+ if (!Array.isArray(database)) {
56
+ SetWarning({ Message: `Failed to parse city database` })
57
+ return
58
+ }
59
+
60
+ const StateCodes: Record<string, string> = Object.fromEntries(
61
+ Object.entries(EnumStates).map(([code, name]) => [name, code])
62
+ );
63
+ const insert = `INSERT INTO cities (id, name, state, county, population, lat, lon) VALUES (?, ?, ?, ?, ?, ?, ?)`
64
+ const cityRows: CityRow[] = []
65
+ for (const city of database) {
66
+ if (city.country != `US`) continue
67
+ cityRows.push({
68
+ id: city.id,
69
+ name: city.name,
70
+ state: StateCodes[city.admin1] ?? null,
71
+ county: city.admin2,
72
+ population: city.pop ?? null,
73
+ lat: city.lat,
74
+ lon: city.lon
75
+ })
76
+ }
77
+ SetWarning({ Message: `Importing ${cityRows.length} cities` })
78
+ const transaction = Bootstrap.Database.transaction((rows: CityRow[]) => {
79
+ for (const row of rows) {
80
+ CreateQuery({
81
+ Query: insert,
82
+ Parameters: [row.id, row.name, row.state, row.county, row.population, row.lat, row.lon]
83
+ })
84
+ }
85
+ })
86
+ transaction(cityRows)
87
+ }
@@ -11,17 +11,17 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { TypeSettings } from "types/Settings"
21
- import { EnumShapefiles } from "@enums/Shapefiles"
22
- import { Bootstrap } from "@bootstrap"
23
- import { SetSleep } from "@utilities/SetSleep"
24
- import { SetWarning } from "@utilities/SetWarning"
20
+ import { EnumShapefiles } from "@Enums/Shapefiles"
21
+ import { Bootstrap } from "@Bootstrap"
22
+ import { SetSleep } from "@Utilities/SetSleep"
23
+ import { SetWarning } from "@Utilities/SetWarning"
24
+ import { CreateQuery } from "@Database/CreateQuery"
25
25
  import { existsSync, mkdirSync, writeFileSync, unlinkSync, rm } from "fs"
26
26
  import { resolve, extname} from "path"
27
27
  import { loadAsync } from "jszip"
@@ -29,10 +29,8 @@ import { read } from "shapefile"
29
29
 
30
30
  export const ImportShapefiles = async (): Promise<void> => {
31
31
  try {
32
- const tShapefiles = Bootstrap.Database
33
- .prepare(`SELECT COUNT(*) AS count FROM shapefiles`)
34
- .get().count;
35
- if (tShapefiles === 0) {
32
+ const tShapefiles = CreateQuery({ Query: `SELECT COUNT(*) AS count FROM shapefiles` })[0] as { count: number };
33
+ if (tShapefiles.count === 0) {
36
34
  await SetSleep({Timeout: 1e3});
37
35
  for (const shapefile of EnumShapefiles) {
38
36
  const response = await fetch(shapefile.link);
@@ -55,8 +53,7 @@ export const ImportShapefiles = async (): Promise<void> => {
55
53
  filepath,
56
54
  );
57
55
  SetWarning({ Message: `Importing ${features.length} features from ${shapefile.name}_${shapefile.id} for Shapefiles` })
58
- const insert = Bootstrap.Database
59
- .prepare(`INSERT OR REPLACE INTO shapefiles (id, location, geometry) VALUES (?, ?, ?)`)
56
+ const insert = `INSERT INTO shapefiles (id, location, source, geometry) VALUES (?, ?, ?, ?)`;
60
57
  const transaction = Bootstrap.Database.transaction((entries: any[]) => {
61
58
  for (const entry of entries) {
62
59
  const { properties, geometry } = entry;
@@ -77,7 +74,7 @@ export const ImportShapefiles = async (): Promise<void> => {
77
74
  final = properties.ID ?? properties.WFO
78
75
  location = properties.NAME;
79
76
  }
80
- insert.run(final, location, JSON.stringify(geometry));
77
+ CreateQuery({ Query: insert, Parameters: [final, location, `${shapefile.name}_${shapefile.id}`, JSON.stringify(geometry)] })
81
78
  }
82
79
  })
83
80
  unlinkSync(`${filepath}.shp`)
@@ -86,7 +83,8 @@ export const ImportShapefiles = async (): Promise<void> => {
86
83
  }
87
84
  rm(resolve(__dirname, 'shapefiles'), { recursive: true, force: true }, () => {});
88
85
  }
89
- } catch (error) {
90
- SetWarning( {Message: `An error occurred while compiling shapefiles: ${error.message}` })
86
+ } catch (error: unknown) {
87
+ const message = error instanceof Error ? error.message : String(error);
88
+ SetWarning( {Message: `An error occurred while compiling shapefiles: ${message}` })
91
89
  }
92
90
  }
@@ -11,37 +11,33 @@
11
11
  Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
12
  Discord: https://atmosphericx-discord.scriptkitty.cafe
13
13
  Ko-Fi: https://ko-fi.com/k3yomi
14
- Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
15
 
16
- Internal Package: @atmosx/event-product-parser
16
+ Independent Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
19
 
20
- import { TypeSettings } from "types/Settings"
21
- import { TypeStanzaCompiled } from "types/StanzaCompiled"
22
- import { Bootstrap } from "@bootstrap"
23
- import { SetWarning } from "@utilities/SetWarning"
20
+ import { TypeSettings } from "Types/Settings"
21
+ import { TypeStanzaCompiled } from "Types/StanzaCompiled"
22
+ import { Bootstrap } from "@Bootstrap"
23
+ import { SetWarning } from "@Utilities/SetWarning"
24
+ import { CreateQuery } from "@Database/CreateQuery"
24
25
 
25
26
  export const ImportStanza = async (Stanza: TypeStanzaCompiled): Promise<void> => {
26
27
  const settings = Bootstrap.Settings as TypeSettings;
27
28
  try {
28
29
  if (!settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) { return }
29
- Bootstrap.Database
30
- .prepare(`INSERT OR IGNORE INTO stanzas (type, stanza, issued) VALUES (?, ?, ?)`)
31
- .run(Stanza.Type.Type, JSON.stringify(Stanza), Stanza.Attributes.issue)
32
- const count = Bootstrap.Database
33
- .prepare(`SELECT COUNT(*) as total FROM stanzas`)
34
- .get() as { total: number }
30
+ CreateQuery({ Query: `INSERT OR IGNORE INTO stanzas (type, stanza, issued) VALUES (?, ?, ?)`, Parameters: [Stanza.Type.Type, JSON.stringify(Stanza), Stanza.Attributes.issue] })
31
+ const count = CreateQuery({ Query: `SELECT COUNT(*) as total FROM stanzas` }) as { total: number };
35
32
  const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxDatabaseHistory;
36
33
  if (count.total > max) {
37
34
  const toDelete = count.total - max;
38
35
  if (toDelete > 0) {
39
- Bootstrap.Database
40
- .prepare(`DELETE FROM stanzas WHERE id IN (SELECT id FROM stanzas ORDER BY issued ASC LIMIT ?)`)
41
- .run(toDelete);
36
+ CreateQuery({ Query: `DELETE FROM stanzas WHERE id IN (SELECT id FROM stanzas ORDER BY issued ASC LIMIT ?)`, Parameters: [toDelete] })
42
37
  }
43
38
  }
44
- } catch (error) {
45
- SetWarning({ Message: `An error occurred while importing stanza: ${error.message}` })
39
+ } catch (error: unknown) {
40
+ const message = error instanceof Error ? error.message : String(error);
41
+ SetWarning({ Message: `An error occurred while importing stanza: ${message}` })
46
42
  }
47
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, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Independent Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeSettings } from "Types/Settings"
21
+ import { Bootstrap } from "@Bootstrap"
22
+ import { SetWarning } from "@Utilities/SetWarning"
23
+ import { ImportShapefiles } from "@Database/ImportShapefiles"
24
+ import { ImportBroadcastify } from "@Database/ImportBroadcastify"
25
+ import { ImportBoundaries } from "@Database/ImportBoundaries"
26
+ import { ImportCities } from "@Database/ImportCities"
27
+ import { CreateQuery } from "@Database/CreateQuery"
28
+ import { existsSync, writeFileSync } from "fs"
29
+ import sqlite3 from "better-sqlite3"
30
+
31
+
32
+ export const InitializeDatabase = async (): Promise<void> => {
33
+ const settings = Bootstrap.Settings as TypeSettings;
34
+ try {
35
+ if (!existsSync(settings.Database)) {
36
+ writeFileSync(settings.Database, '')
37
+ SetWarning({ Message: `Creating new database at ${settings.Database}` })
38
+ }
39
+ Bootstrap.Database = new sqlite3(settings.Database);
40
+ CreateQuery({ Query: `CREATE TABLE IF NOT EXISTS stanzas ( id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, issued TEXT, stanza TEXT )` })
41
+ const isNeedingShapefiles = CreateQuery({ Query: `SELECT name FROM sqlite_master WHERE type='table' AND name='shapefiles';` }) as { name: string }[];
42
+ const isNeedingBroadcastify = CreateQuery({ Query: `SELECT name FROM sqlite_master WHERE type='table' AND name='broadcastify';` }) as { name: string }[];
43
+ const isNeedingBoundaries = CreateQuery({ Query: `SELECT name FROM sqlite_master WHERE type='table' AND name='boundaries';` }) as { name: string }[];
44
+ const isNeedingCities = CreateQuery({ Query: `SELECT name FROM sqlite_master WHERE type='table' AND name='cities';` }) as { name: string }[];
45
+
46
+ if (isNeedingShapefiles.length === 0 || isNeedingBroadcastify.length === 0 || isNeedingBoundaries.length === 0 || isNeedingCities.length === 0) {
47
+ CreateQuery({ Query: `CREATE TABLE IF NOT EXISTS broadcastify ( state TEXT, county TEXT, feed TEXT, type TEXT, link TEXT)` })
48
+ CreateQuery({ Query: `CREATE TABLE IF NOT EXISTS shapefiles ( id, location TEXT, source TEXT, geometry TEXT )` })
49
+ CreateQuery({ Query: `CREATE INDEX IF NOT EXISTS idx_shapefiles_id ON shapefiles (id)` })
50
+ CreateQuery({ Query: `CREATE TABLE IF NOT EXISTS boundaries (id TEXT PRIMARY KEY, type TEXT NOT NULL, state TEXT, name TEXT, geometry TEXT NOT NULL );` })
51
+ CreateQuery({ Query: `CREATE TABLE IF NOT EXISTS cities ( id TEXT PRIMARY KEY, name TEXT, state TEXT, county TEXT, population TEXT, lat REAL NOT NULL, lon REAL NOT NULL);`});
52
+ SetWarning({Message: `Required database tables are currently building, please ${Bootstrap.Colors.Red}DO NOT${Bootstrap.Colors.Reset} close your terminal. The building will not finish and will remain incomplete. If you do mess up, you will need to delete ${settings.Database} and restart the application.` })
53
+ if (isNeedingCities.length === 0) {
54
+ await ImportCities();
55
+ }
56
+ if (isNeedingBroadcastify.length === 0) {
57
+ await ImportBroadcastify();
58
+ }
59
+ if (isNeedingBoundaries.length === 0) {
60
+ await ImportBoundaries();
61
+ }
62
+ if (isNeedingShapefiles.length === 0) {
63
+ await ImportShapefiles();
64
+ }
65
+ SetWarning({ Message: `Database initialization complete. You may now close your terminal or continue using the application.` })
66
+ }
67
+ } catch (error: unknown) {
68
+ const message = error instanceof Error ? error.message : String(error);
69
+ SetWarning({ Message: `An error occurred while initializing the database: ${message}` })
70
+ }
71
+ }