@atmosx/event-product-parser 3.0.47 → 3.0.51

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 (59) hide show
  1. package/README.md +48 -21
  2. package/dist/cjs/index.cjs +5841 -15199
  3. package/dist/esm/index.mjs +5827 -15185
  4. package/package.json +5 -6
  5. package/src/@building/building.attachments.ts +6 -6
  6. package/src/@building/building.create.ts +19 -5
  7. package/src/@building/building.enhance.ts +1 -1
  8. package/src/@building/building.geometry.ts +1 -1
  9. package/src/@building/building.polygon.ts +1 -2
  10. package/src/@building/building.signature.ts +0 -1
  11. package/src/@building/building.tracking.ts +4 -4
  12. package/src/@building/building.validate.ts +11 -6
  13. package/src/@core/core.clearEvents.ts +0 -1
  14. package/src/@core/core.createEvent.ts +0 -1
  15. package/src/@core/core.getEvents.ts +0 -1
  16. package/src/@core/core.getNodes.ts +0 -1
  17. package/src/@core/core.getRandomEvent.ts +0 -1
  18. package/src/@core/core.getVersion.ts +0 -1
  19. package/src/@dictionaries/dictionaries.awips.ts +3 -3
  20. package/src/@events/events.api.ts +7 -9
  21. package/src/@events/events.text.ts +5 -6
  22. package/src/@events/events.ugc.ts +5 -5
  23. package/src/@events/events.vtec.ts +4 -5
  24. package/src/@manager/manager.mkEvent.ts +17 -12
  25. package/src/@manager/manager.rmEvent.ts +5 -3
  26. package/src/@manager/manager.setHash.ts +0 -1
  27. package/src/@manager/manager.updateEvents.ts +1 -3
  28. package/src/@manager/manager.updateListener.ts +23 -31
  29. package/src/@manager/manager.updateNodes.ts +2 -3
  30. package/src/@modules/@database/database.cache.ts +6 -4
  31. package/src/@modules/@database/database.init.ts +5 -4
  32. package/src/@modules/@database/database.shapefiles.ts +11 -11
  33. package/src/@modules/@database/database.stanza.ts +2 -3
  34. package/src/@modules/@eas/eas.setAFSK.ts +0 -1
  35. package/src/@modules/@eas/eas.setAsciiToBits.ts +0 -1
  36. package/src/@modules/@eas/eas.setEasTone.ts +6 -2
  37. package/src/@modules/@eas/eas.setNoise.ts +1 -0
  38. package/src/@modules/@eas/eas.setRadioEffect.ts +1 -0
  39. package/src/@modules/@eas/eas.setSameHeader.ts +0 -1
  40. package/src/@modules/@utilities/utilities.createHttp.ts +40 -64
  41. package/src/@modules/@utilities/utilities.getMatched.ts +33 -0
  42. package/src/@modules/@utilities/utilities.setCronSchedule.ts +1 -1
  43. package/src/@modules/@utilities/utilities.setDebug.ts +38 -0
  44. package/src/@modules/@utilities/utilities.setTimeoutAction.ts +5 -1
  45. package/src/@modules/@xmpp/xmpp.xDeploy.ts +1 -2
  46. package/src/@modules/@xmpp/xmpp.xError.ts +0 -2
  47. package/src/@modules/@xmpp/xmpp.xOffline.ts +0 -1
  48. package/src/@modules/@xmpp/xmpp.xOnline.ts +2 -2
  49. package/src/@parsers/@text/text.getEmbed.ts +0 -2
  50. package/src/@parsers/@ugc/ugc.coordinates.ts +2 -1
  51. package/src/@parsers/@ugc/ugc.getCache.ts +24 -0
  52. package/src/@parsers/@ugc/ugc.locations.ts +35 -7
  53. package/src/@parsers/@ugc/ugc.setCache.ts +28 -0
  54. package/src/@types/type.settings.ts +1 -0
  55. package/src/bootstrap.ts +4 -1
  56. package/test.js +15 -21
  57. package/tsup.config.ts +1 -1
  58. package/dist/index.d.mts +0 -299
  59. package/dist/index.d.ts +0 -299
@@ -17,7 +17,6 @@
17
17
 
18
18
  */
19
19
 
20
-
21
20
  import { TypeEvent } from "../@types/type.event";
22
21
  import { TypeListener } from "../@types/type.listener";
23
22
  import { bootstrap } from "../bootstrap"
@@ -26,18 +25,19 @@ import { setTimeoutAction } from "../@modules/@utilities/utilities.setTimeoutAct
26
25
  import { getEmebed } from "../@parsers/@text/text.getEmbed";
27
26
  import { getCleanedEvent } from "../@building/building.clean"
28
27
  import { createHttp } from "../@modules/@utilities/utilities.createHttp";
28
+ import { setDebug } from "../@modules/@utilities/utilities.setDebug";
29
+ import { getMatched } from "../@modules/@utilities/utilities.getMatched";
29
30
  import { existsSync, mkdirSync, writeFileSync, readFileSync, appendFileSync } from "fs";
30
- import FormData from "form-data";
31
-
32
-
33
31
 
34
32
  export const updateListener = async (event: TypeEvent): Promise<void> => {
33
+ const tick = performance.now()
35
34
  const settings = bootstrap.settings;
36
35
  const listeners = settings.ListenerSettings as TypeListener[];
37
36
  const properties = event.properties;
38
37
  const metadata = {
39
38
  file: null,
40
39
  eas: null,
40
+ json: null,
41
41
  name: properties.event,
42
42
  status: properties.status,
43
43
  description: properties.description,
@@ -52,16 +52,7 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
52
52
  const events = listener?.events;
53
53
  const webhook = listener?.webhook;
54
54
  const uploads = listener?.uploads
55
- const isMatched = events.some(pattern => {
56
- if (!pattern) return false;
57
- if (pattern === "*" || pattern === metadata.name) return true;
58
- if (pattern.includes("*")) {
59
- const regex = "^" +
60
- pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$";
61
- return new RegExp(regex).test(metadata.name);
62
- }
63
- return false;
64
- });
55
+ const isMatched = getMatched(events ?? [], metadata.name)
65
56
 
66
57
  if (events?.length == 0 || isMatched) {
67
58
  if (uploads?.eas) {
@@ -75,11 +66,12 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
75
66
  if (uploads?.file) {
76
67
  const fDestination = settings.GlobalSettings.ArchiveSettings.TextDirectory;
77
68
  if (fDestination) {
69
+ const file = (`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
78
70
  if (!existsSync(fDestination)) { mkdirSync(fDestination, { recursive: true }); }
79
- if (existsSync(`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`)) {
80
- appendFileSync(`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`, metadata.raw);
71
+ if (existsSync(file)) {
72
+ appendFileSync(file, metadata.raw);
81
73
  } else {
82
- writeFileSync(`${fDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.txt`, metadata.raw);
74
+ writeFileSync(file, metadata.raw);
83
75
  }
84
76
  }
85
77
  metadata.file = metadata.raw;
@@ -88,13 +80,15 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
88
80
  if (uploads?.event) {
89
81
  const eDestination = settings.GlobalSettings.ArchiveSettings.EventDirectory;
90
82
  if (eDestination) {
83
+ const file = (`${eDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.json`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
91
84
  if (!existsSync(eDestination)) { mkdirSync(eDestination, { recursive: true }); }
92
- writeFileSync(`${eDestination}/${metadata.name}_${metadata.status}_${metadata.tracking}.json`, JSON.stringify(getCleanedEvent(event), null, 2));
85
+ writeFileSync(file, JSON.stringify(getCleanedEvent(event), null, 2));
93
86
  }
87
+ metadata.json = JSON.stringify(getCleanedEvent(event), null, 2);
94
88
  }
95
89
 
96
- if (webhook.enabled && webhook.destination) {
97
- const ratelimit = setTimeoutAction({ identifier: webhook.destination, interval: webhook.ratelimit, max: webhook.ratelimit, addTime: true })
90
+ if (webhook?.enabled && webhook?.destination) {
91
+ const isRatelimited = setTimeoutAction({ identifier: webhook.destination, interval: (webhook.ratelimit ?? 2) * 2, max: (webhook.ratelimit ?? 2), addTime: true })
98
92
  const form = new FormData();
99
93
  const embed = {
100
94
  title: `${metadata.name} (${metadata.status})`,
@@ -105,7 +99,7 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
105
99
  footer: { text: webhook.title ?? `AtmosphericX` }
106
100
  };
107
101
 
108
- if (ratelimit.limited) { return }
102
+ if (isRatelimited.limited) { return }
109
103
 
110
104
 
111
105
  if (metadata.description && !metadata.expired) {
@@ -128,19 +122,17 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
128
122
  }
129
123
 
130
124
  if (uploads?.file) {
131
- form.append("fUpload", Buffer.from(metadata.file), {
132
- filename: `${properties.event}_${properties.status}_${properties.metadata.tracking}.txt`,
133
- contentType: "application/text"
134
- });
125
+ form.append("fUpload", new Blob([Buffer.from(metadata.file)], {type: "application/text"}), `${properties.event}_${properties.status}_${properties.metadata.tracking}.txt`)
126
+ }
127
+
128
+ if (uploads?.event) {
129
+ form.append("fUpload2", new Blob([Buffer.from(metadata.json)], {type: "application/json"}), `${properties.event}_${properties.status}_${properties.metadata.tracking}.json`)
135
130
  }
136
131
 
137
132
  if (uploads?.eas) {
138
133
  if (metadata.eas) {
139
134
  const file = readFileSync(metadata.eas)
140
- form.append("fEas", Buffer.from(file), {
141
- filename: `${properties.event}_${properties.status}_${properties.metadata.tracking}_eas.mp3`,
142
- contentType: "audio/mpeg"
143
- });
135
+ form.append("fEas", new Blob([Buffer.from(file)], { type: "audio/mpeg" }), `${properties.event}_${properties.status}_${properties.metadata.tracking}_eas.mp3`)
144
136
  }
145
137
  }
146
138
 
@@ -152,12 +144,12 @@ export const updateListener = async (event: TypeEvent): Promise<void> => {
152
144
 
153
145
  await createHttp({
154
146
  url: webhook.destination,
155
- timeout: 5000,
147
+ timeout: 15e3,
156
148
  method: `POST`,
157
- headers: form.getHeaders(),
158
149
  body: form
159
150
  })
160
151
  }
161
152
  }
162
153
  }
154
+ setDebug({ title: `@manager.updateListener`, message: `Listener took ${performance.now() - tick} ms` })
163
155
  }
@@ -17,11 +17,10 @@
17
17
 
18
18
  */
19
19
 
20
- import { getEventNodes } from "../@building/building.polygon";
21
- import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
22
20
  import { TypeEvent } from "../@types/type.event";
23
21
  import { bootstrap } from "../bootstrap"
24
-
22
+ import { getEventNodes } from "../@building/building.polygon";
23
+ import { setEventEmit } from "../@modules/@utilities/utilities.setEventEmit";
25
24
 
26
25
  export const updateNode = async (selectedEvent?: TypeEvent): Promise<void> => {
27
26
  const events = bootstrap.cache.events.features;
@@ -21,6 +21,7 @@ import { TypeSettings } from "../../@types/type.settings"
21
21
  import { bootstrap } from '../../bootstrap'
22
22
  import { setWarning } from '../@utilities/utilities.setWarning';
23
23
  import { createEvent } from '../../@building/building.create';
24
+ import { validateEvents } from "../../@building/building.validate";
24
25
 
25
26
  export const getCachedEvents = async (): Promise<void> => {
26
27
  try {
@@ -29,7 +30,7 @@ export const getCachedEvents = async (): Promise<void> => {
29
30
  if (settings.NOAAWeatherWireServiceSettings.CacheSettings.Enabled) {
30
31
  const max = settings.NOAAWeatherWireServiceSettings.CacheSettings.MaxRetentionHistory ?? 500;
31
32
  const get = await bootstrap.database.prepare(`SELECT * FROM stanzas ORDER BY rowid DESC LIMIT ?`).all(max) as { rowid: number; stanza: string }[];
32
- setWarning({ message: `Fetched ${get.length} cached events from the database in ${Math.floor(performance.now() - tick)} ms` })
33
+ setWarning({ message: `Fetched ${get.length} cached stanzas from the database in ${Math.floor(performance.now() - tick)} ms` })
33
34
  let events = get.map((row) => JSON.parse(row.stanza))
34
35
  .filter(stanza => {
35
36
  if (!stanza) { return }
@@ -39,10 +40,11 @@ export const getCachedEvents = async (): Promise<void> => {
39
40
  return !isSkippable
40
41
  });
41
42
  events = events.sort((a, b) => b.issued - a.issued)
42
- await Promise.all(events.map(event => createEvent(event)))
43
- setWarning({ message: `Processed ${events.length} cached events in ${Math.floor(performance.now() - tick)} ms` })
43
+ await Promise.all(events.map(event => createEvent(event, true)))
44
+ setWarning({ message: `Processed ${events.length} cached stanzas in ${Math.floor(performance.now() - tick)} ms` })
45
+ validateEvents(bootstrap.cache.processed)
44
46
  }
45
47
  } catch (error) {
46
- setWarning({ message: `An error occurred while fetching cached events: ${error.message} -> ${error.stack}` })
48
+ setWarning({ message: `An error occurred while fetching cached stanzas: ${error.message} -> ${error.stack}` })
47
49
  }
48
50
  }
@@ -17,19 +17,20 @@
17
17
 
18
18
  */
19
19
 
20
- import fs from 'fs'
21
- import sqlite3 from 'better-sqlite3'
20
+
22
21
  import { TypeSettings } from "../../@types/type.settings"
23
22
  import { bootstrap } from "../../bootstrap"
24
23
  import { setWarning } from '../@utilities/utilities.setWarning'
25
24
  import { importShapefiles } from './database.shapefiles'
26
25
  import { importBroadcastify } from "./database.broadcastify"
26
+ import { existsSync, writeFileSync } from "fs"
27
+ import sqlite3 from 'better-sqlite3'
27
28
 
28
29
  export const initializeDatabase = async (): Promise<void> => {
29
30
  const settings = bootstrap.settings as TypeSettings;
30
31
  try {
31
- if (!fs.existsSync(settings.Database)) {
32
- fs.writeFileSync(settings.Database, '')
32
+ if (!existsSync(settings.Database)) {
33
+ writeFileSync(settings.Database, '')
33
34
  setWarning({ message: `Creating new database at ${settings.Database}` })
34
35
  }
35
36
  bootstrap.database = new sqlite3(settings.Database);
@@ -17,15 +17,15 @@
17
17
 
18
18
  */
19
19
 
20
- import fs from 'fs'
21
- import { resolve, extname} from 'path'
22
- import { loadAsync } from 'jszip'
23
- import { read } from 'shapefile'
24
20
  import { TypeSettings } from "../../@types/type.settings"
21
+ import { dict_shapefiles } from '../../@dictionaries/dictionaries.shapefiles'
25
22
  import { bootstrap } from "../../bootstrap"
26
23
  import { setSleep } from '../@utilities/utilities.setSleep'
27
24
  import { setWarning } from '../@utilities/utilities.setWarning'
28
- import { dict_shapefiles } from '../../@dictionaries/dictionaries.shapefiles'
25
+ import { existsSync, mkdirSync, writeFileSync, unlinkSync, rm } from "fs"
26
+ import { resolve, extname} from 'path'
27
+ import { loadAsync } from 'jszip'
28
+ import { read } from 'shapefile'
29
29
 
30
30
  export const importShapefiles = async (): Promise<void> => {
31
31
  const settings = bootstrap.settings as TypeSettings;
@@ -40,14 +40,14 @@ export const importShapefiles = async (): Promise<void> => {
40
40
  const arrayBuff = await response.arrayBuffer();
41
41
  const content = await loadAsync(arrayBuff);
42
42
  const directory = resolve(__dirname, `../../shapefiles`);
43
- if (!fs.existsSync(directory)) {
44
- fs.mkdirSync(directory, { recursive: true });
43
+ if (!existsSync(directory)) {
44
+ mkdirSync(directory, { recursive: true });
45
45
  }
46
46
  for (const file of Object.keys(content.files)) {
47
47
  if (file.endsWith('.shp') || file.endsWith('.dbf')) {
48
48
  const data = await content.files[file].async(`nodebuffer`)
49
49
  const output = resolve(directory, `${shapefile?.name ?? ``}_${shapefile?.id ?? ``}${extname(file)}`)
50
- fs.writeFileSync(output, data)
50
+ writeFileSync(output, data)
51
51
  }
52
52
  }
53
53
  const filepath = resolve(__dirname, '../../shapefiles', shapefile.name + '_' + shapefile.id)
@@ -81,11 +81,11 @@ export const importShapefiles = async (): Promise<void> => {
81
81
  insert.run(final, location, JSON.stringify(geometry));
82
82
  }
83
83
  })
84
- fs.unlinkSync(`${filepath}.shp`)
85
- fs.unlinkSync(`${filepath}.dbf`)
84
+ unlinkSync(`${filepath}.shp`)
85
+ unlinkSync(`${filepath}.dbf`)
86
86
  transaction(features)
87
87
  }
88
- fs.rm(resolve(__dirname, '../../shapefiles'), { recursive: true, force: true }, () => {});
88
+ rm(resolve(__dirname, '../../shapefiles'), { recursive: true, force: true }, () => {});
89
89
  }
90
90
  } catch (error) {
91
91
  setWarning( {message: `An error occurred while compiling shapefiles: ${error.message}` })
@@ -17,11 +17,10 @@
17
17
 
18
18
  */
19
19
 
20
-
21
- import { bootstrap } from '../../bootstrap'
22
- import { setWarning } from '../@utilities/utilities.setWarning';
23
20
  import { TypeSettings } from "../../@types/type.settings"
24
21
  import { TypeStanzaCompiled } from '../../@types/type.compiled';
22
+ import { bootstrap } from '../../bootstrap'
23
+ import { setWarning } from '../@utilities/utilities.setWarning';
25
24
 
26
25
  export const importStanza = async (stanza: TypeStanzaCompiled): Promise<void> => {
27
26
  const settings = bootstrap.settings as TypeSettings;
@@ -18,7 +18,6 @@
18
18
 
19
19
  */
20
20
 
21
-
22
21
  export const setAFSK = (bits: number[], sampleRate: number): Int16Array => {
23
22
  const baud = 520.83;
24
23
  const markFreq = 2083.3;
@@ -18,7 +18,6 @@
18
18
 
19
19
  */
20
20
 
21
-
22
21
  export const setAsciiToBits = (str: string): number[] => {
23
22
  const bits = [];
24
23
  for (let i = 0; i < str.length; i++) {
@@ -30,11 +30,13 @@ import { setNoise } from "./eas.setNoise";
30
30
  import { getPCM16 } from "./eas.getPCM16";
31
31
  import { getTTS } from "./eas.getTTS";
32
32
  import { getCleanDescription } from "./eas.getCleanDescription";
33
+ import { setDebug } from "../@utilities/utilities.setDebug";
33
34
  import { join } from 'path'
34
35
  import { existsSync, mkdirSync, readFileSync, writeFileSync, unlinkSync } from 'fs'
35
36
  import { execSync } from 'child_process'
36
37
  import { platform } from 'os'
37
38
 
39
+
38
40
  interface GenerateEASOptions {
39
41
  message: string
40
42
  header: string
@@ -42,12 +44,13 @@ interface GenerateEASOptions {
42
44
  }
43
45
 
44
46
  export const setEasTone = async (options: GenerateEASOptions): Promise<string> => {
47
+ const tick = performance.now()
45
48
  const settings = bootstrap.settings as TypeSettings;
46
49
  const directory = settings.GlobalSettings.ArchiveSettings.EasDirectory;
47
50
  const prefix = settings.GlobalSettings.ArchiveSettings.EasToneout;
48
51
  let message = options.message;
49
52
  let header = options.header;
50
- let title = options.title ?? `${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, '')}`;
53
+ let title = (options.title ?? `${Math.random().toString(36).substring(2, 15)}-${header.replace(/[^a-zA-Z0-9]/g, '')}`).replace(/[\\:*?"<>|]/g, "_").replace(/\s+/g, " ").trim();
51
54
  if (!message || !header) {
52
55
  setWarning({
53
56
  title: `EAS`,
@@ -68,7 +71,7 @@ export const setEasTone = async (options: GenerateEASOptions): Promise<string> =
68
71
  if (!existsSync(join(directory, `/encoded`))) {
69
72
  mkdirSync(join(directory, `/encoded`), { recursive: true });
70
73
  }
71
-
74
+
72
75
  const tmpTTS = join(directory, `/tts/${title}.wav`)
73
76
  const outTTS = join(directory, `/encoded/${title}.wav`)
74
77
  const vPlatform = platform();
@@ -141,6 +144,7 @@ export const setEasTone = async (options: GenerateEASOptions): Promise<string> =
141
144
  const aBuffer = getPCM16(Array.from(aFinal).map(v => ({ value: v })), 8000);
142
145
  writeFileSync(outTTS, aBuffer)
143
146
  try{ unlinkSync(tmpTTS) } catch {}
147
+ setDebug({ title: `@eas.setEasTone`, message: `EAS tone generation took ${performance.now() - tick} ms` })
144
148
  return outTTS;
145
149
  }
146
150
 
@@ -17,6 +17,7 @@
17
17
 
18
18
 
19
19
  */
20
+
20
21
  import { getPCMToFloat } from "./eas.getPCMToFloat";
21
22
  import { getFloatPCM16 } from "./eas.getFloatPCM16";
22
23
 
@@ -17,6 +17,7 @@
17
17
 
18
18
 
19
19
  */
20
+
20
21
  import { getPCMToFloat } from "./eas.getPCMToFloat";
21
22
  import { getFloatPCM16 } from "./eas.getFloatPCM16";
22
23
 
@@ -18,7 +18,6 @@
18
18
 
19
19
  */
20
20
 
21
-
22
21
  import { setAFSK } from "./eas.setAFSK";
23
22
  import { setAsciiToBits } from "./eas.setAsciiToBits";
24
23
  import { getMergedPCM16 } from "./eas.getMergedPCM16";
@@ -17,10 +17,7 @@
17
17
 
18
18
  */
19
19
 
20
- import request from 'request'
21
-
22
20
  interface CreateHttpOptions {
23
- proxy?: string
24
21
  url: string
25
22
  headers?: any
26
23
  timeout?: number
@@ -30,65 +27,44 @@ interface CreateHttpOptions {
30
27
  }
31
28
 
32
29
  export const createHttp = async (options: CreateHttpOptions): Promise<any> => {
33
- return new Promise((resolve, reject) => {
34
- try {
35
- const requestOptions = {
36
- url: options.url ?? `https://api.weather.gov/alerts/active`,
37
- headers: options.headers ?? {
38
- "User-Agent": "AtmosphericX",
39
- "Accept": "application/geo+json, text/plain, */*; q=0.9",
40
- "Accept-Language": "en-US,en;q=0.9"
41
- },
42
- method: options.method ?? `GET`,
43
- timeout: options.timeout ?? 10e3,
44
- proxy: options.proxy ?? null,
45
- maxRedirects: 1,
46
- };
47
- if (options.formData) {
48
- requestOptions['formData'] = options.formData;
49
- } else if (options.body) {
50
- requestOptions['body'] = options.body;
51
- }
52
-
53
- request(requestOptions, (error, response, body) => {
54
- if (error) {
55
- return resolve({
56
- error: true,
57
- options: requestOptions,
58
- status: -1,
59
- message: error.message ?? `Unknown Error`
60
- })
61
- }
62
- if (response.statusCode < 200 || response.statusCode >= 300) {
63
- return resolve({
64
- error: true,
65
- options: requestOptions,
66
- status: response.statusCode ?? -1,
67
- message: `HTTP Status Code ${response.statusCode ?? `Unknown Status Code`} (${body})`
68
- })
69
- }
70
- if (body == undefined || body == null) {
71
- return resolve({
72
- error: true,
73
- options: requestOptions,
74
- status: response.statusCode ?? -1,
75
- message: `Empty Response Body`
76
- })
77
- }
78
- resolve({
79
- error: false,
80
- options: requestOptions,
81
- status: response.statusCode ?? -1,
82
- message: body
83
- })
84
- })
85
- } catch (error) {
86
- return resolve({
87
- error: true,
88
- options: {},
89
- status: -1,
90
- message: error.message ?? `Unknown Error`
91
- })
92
- }
93
- })
30
+ const requestOptions: RequestInit = {
31
+ method: options.method ?? "GET",
32
+ headers: options.headers ?? {
33
+ "User-Agent": "AtmosphericX",
34
+ "Accept": "application/geo+json, text/plain, */*; q=0.9",
35
+ "Accept-Language": "en-US,en;q=0.9",
36
+ },
37
+ signal: AbortSignal.timeout(options.timeout ?? 10_000),
38
+ redirect: "follow"
39
+ };
40
+
41
+
42
+ const returnHttp = function(error: boolean,status: number, message: string) {
43
+ return { error: error, options: requestOptions, status, message };
44
+ }
45
+
46
+ if (options?.formData) {
47
+ requestOptions.body = options.formData;
48
+ } else if (options?.body != undefined) {
49
+ requestOptions.body =
50
+ options.body instanceof FormData
51
+ ? options.body
52
+ : typeof options.body === "string"
53
+ ? options.body
54
+ : JSON.stringify(options.body);
55
+ }
56
+
57
+ try {
58
+ const response = await fetch(
59
+ options?.url ?? `https://api.weather.gov/alerts/active`,
60
+ requestOptions
61
+ )
62
+ const body = await response.text();
63
+ if (!response.ok) {
64
+ return returnHttp(true, response.status, `HTTP Status Code ${response.status} (${response.statusText})`)
65
+ }
66
+ return returnHttp(false, response.status, body)
67
+ } catch (error) {
68
+ return returnHttp(true, 500, `Internal Server Error: ${error}`)
69
+ }
94
70
  }
@@ -0,0 +1,33 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ export const getMatched = (strings: string[], string: string): boolean => {
21
+ const isMatched = strings.some(pattern => {
22
+ if (!pattern) return false;
23
+ const lowerP = pattern.toLowerCase();
24
+ const lowerS = string.toLowerCase()
25
+ if (lowerP === "*" || lowerP === lowerS) return true;
26
+ if (lowerP.includes("*")) {
27
+ const regex = "^" + lowerP.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") + "$";
28
+ return new RegExp(regex).test(lowerS);
29
+ }
30
+ return false;
31
+ });
32
+ return isMatched;
33
+ }
@@ -68,7 +68,7 @@ export const setCronSchedule = async (): Promise<void> => {
68
68
  }
69
69
  })
70
70
  if (response.error) {
71
- return setEventEmit({
71
+ return setEventEmit({
72
72
  event: `onServiceStatus`,
73
73
  metadata: {
74
74
  type: "fetch-api",
@@ -0,0 +1,38 @@
1
+ /*
2
+ _ _ _ __ __
3
+ /\ | | | | (_) \ \ / /
4
+ / \ | |_ _ __ ___ ___ ___ _ __ | |__ ___ _ __ _ ___ \ V /
5
+ / /\ \| __| '_ ` _ \ / _ \/ __| '_ \| '_ \ / _ \ '__| |/ __| > <
6
+ / ____ \ |_| | | | | | (_) \__ \ |_) | | | | __/ | | | (__ / . \
7
+ /_/ \_\__|_| |_| |_|\___/|___/ .__/|_| |_|\___|_| |_|\___/_/ \_\
8
+ | |
9
+ |_|
10
+
11
+ Created with ♥ by the AtmosphericX Team (KiyoWx, StarflightWx, & CJ Ziegler)
12
+ Discord: https://atmosphericx-discord.scriptkitty.cafe
13
+ Ko-Fi: https://ko-fi.com/k3yomi
14
+ Documentation: http://localhost/documentation | https://atmosphericx.scriptkitty.cafe/documentation
15
+
16
+ Internal Package: @atmosx/event-product-parser
17
+
18
+ */
19
+
20
+ import { TypeSettings } from "../../@types/type.settings";
21
+ import { bootstrap } from "../../bootstrap"
22
+
23
+ interface SetDebugOptions {
24
+ title?: string
25
+ message: string
26
+ }
27
+
28
+ export const setDebug = (options: SetDebugOptions): void => {
29
+ const settings = bootstrap.settings as TypeSettings;
30
+ bootstrap.listener.emit(`debug`, {
31
+ message: options.message,
32
+ parent: options?.title?.split(`.`)[0]?.replace(`@`, ``),
33
+ function: options?.title?.split(`.`)[1]
34
+ })
35
+ if (settings.EnableDebugging) {
36
+ console.log(`[${bootstrap.ansi_colors.BLUE}${options.title ?? `debug`}${bootstrap.ansi_colors.RESET}] ${options.message}`)
37
+ }
38
+ }
@@ -23,7 +23,8 @@ interface SetTimeoutActionOptions {
23
23
  identifier: string
24
24
  addTime?: boolean
25
25
  max?: number
26
- interval: number
26
+ interval?: number
27
+ expire?: boolean
27
28
  }
28
29
 
29
30
  type SetTimeoutActionResponse = {
@@ -38,6 +39,9 @@ export const setTimeoutAction = (options: SetTimeoutActionOptions): SetTimeoutAc
38
39
  bootstrap.ratelimits[options?.identifier] = [];
39
40
  target = bootstrap.ratelimits[options?.identifier];
40
41
  }
42
+ if (options?.expire) {
43
+ delete bootstrap.ratelimits[options?.identifier];
44
+ }
41
45
  if (target?.length > 0) {
42
46
  bootstrap.ratelimits[options?.identifier] = target.filter((ts: number) => Date.now() - ts < options?.interval * 1000);
43
47
  target = bootstrap.ratelimits[options?.identifier];
@@ -17,15 +17,14 @@
17
17
 
18
18
  */
19
19
 
20
- import { client } from '@xmpp/client';
21
20
  import { TypeSettings } from "../../@types/type.settings";
22
21
  import { bootstrap } from "../../bootstrap"
23
- import { setWarning } from "../@utilities/utilities.setWarning";
24
22
  import { xOnline } from "./xmpp.xOnline";
25
23
  import { xOffline } from "./xmpp.xOffline";
26
24
  import { xError } from "./xmpp.xError";
27
25
  import { xStanza } from "./xmpp.xStanza";
28
26
  import { setEventEmit } from '../@utilities/utilities.setEventEmit';
27
+ import { client } from '@xmpp/client';
29
28
 
30
29
  export const xDeploy = async (): Promise<void> => {
31
30
  let session;
@@ -18,8 +18,6 @@
18
18
  */
19
19
 
20
20
  import { bootstrap } from "../../bootstrap";
21
- import { setEventEmit } from "../@utilities/utilities.setEventEmit";
22
- import { setWarning } from "../@utilities/utilities.setWarning";
23
21
 
24
22
  export const xError = () => {
25
23
  bootstrap.session_xmpp.on(`error`, async (error: Error) => {
@@ -19,7 +19,6 @@
19
19
 
20
20
  import { bootstrap } from "../../bootstrap";
21
21
  import { setEventEmit } from "../@utilities/utilities.setEventEmit";
22
- import { setWarning } from "../@utilities/utilities.setWarning";
23
22
 
24
23
  export const xOffline = () => {
25
24
  bootstrap.session_xmpp.on(`offline`, async () => {
@@ -16,10 +16,10 @@
16
16
  Internal Package: @atmosx/event-product-parser
17
17
 
18
18
  */
19
- import { xml } from '@xmpp/client'
19
+
20
20
  import { bootstrap } from "../../bootstrap";
21
- import { setSleep } from "../@utilities/utilities.setSleep";
22
21
  import { setEventEmit } from '../@utilities/utilities.setEventEmit';
22
+ import { xml } from '@xmpp/client'
23
23
 
24
24
  export const xOnline = () => {
25
25
  const settings = bootstrap.settings;
@@ -19,8 +19,6 @@
19
19
 
20
20
  import { TypeEvent } from "../../@types/type.event"
21
21
 
22
-
23
-
24
22
  export const getEmebed = (event: TypeEvent): string => {
25
23
  const line = (label: string, value: unknown, condition = true) => condition && value ? `${label} ${value}` : null;
26
24
  const isStatement = event.properties.status_metadata.is_statement;