rocket-launch-live-client 1.0.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. package/README.md +105 -61
  2. package/lib/{esm/types/Client.d.ts → Client.d.ts} +6 -8
  3. package/lib/Client.js +61 -0
  4. package/lib/fetcher.d.ts +5 -0
  5. package/lib/fetcher.js +146 -0
  6. package/lib/{cjs/types/index.d.ts → index.d.ts} +0 -1
  7. package/lib/index.js +4 -0
  8. package/lib/{cjs/types/types → types}/application.d.ts +41 -27
  9. package/lib/types/application.js +41 -0
  10. package/lib/types/standards.d.ts +8 -0
  11. package/lib/types/standards.js +314 -0
  12. package/lib/{cjs/types/utils.d.ts → utils.d.ts} +1 -4
  13. package/lib/{esm/utils.js → utils.js} +18 -4
  14. package/lib/{cjs/types → watcher}/Watcher.d.ts +16 -12
  15. package/lib/watcher/Watcher.js +145 -0
  16. package/lib/watcher/index.d.ts +25 -0
  17. package/lib/watcher/index.js +3 -0
  18. package/package.json +30 -26
  19. package/lib/cjs/Client.js +0 -233
  20. package/lib/cjs/Watcher.js +0 -172
  21. package/lib/cjs/fetcher.js +0 -61
  22. package/lib/cjs/index.js +0 -30
  23. package/lib/cjs/package.json +0 -3
  24. package/lib/cjs/types/Client.d.ts +0 -189
  25. package/lib/cjs/types/application.js +0 -46
  26. package/lib/cjs/types/fetcher.d.ts +0 -2
  27. package/lib/cjs/types/standards.js +0 -321
  28. package/lib/cjs/types/types/standards.d.ts +0 -316
  29. package/lib/cjs/utils.js +0 -266
  30. package/lib/esm/Client.js +0 -229
  31. package/lib/esm/Watcher.js +0 -168
  32. package/lib/esm/fetcher.js +0 -54
  33. package/lib/esm/index.mjs +0 -22
  34. package/lib/esm/package.json +0 -3
  35. package/lib/esm/types/Watcher.d.ts +0 -81
  36. package/lib/esm/types/application.js +0 -43
  37. package/lib/esm/types/fetcher.d.ts +0 -2
  38. package/lib/esm/types/index.d.ts +0 -24
  39. package/lib/esm/types/standards.js +0 -316
  40. package/lib/esm/types/types/application.d.ts +0 -206
  41. package/lib/esm/types/types/standards.d.ts +0 -316
  42. package/lib/esm/types/utils.d.ts +0 -12
@@ -0,0 +1,145 @@
1
+ import { EventEmitter } from "node:events";
2
+ import { RLLEndPoint, } from "../types/application.js";
3
+ import { error, warn, queryOptionsValidator, formatToRLLISODate, } from "../utils.js";
4
+ const DEFAULT_INTERVAL_IN_MINS = 5;
5
+ const MS_IN_MIN = 60000;
6
+ const INIT_PAGE_CONCURRENCY = 3;
7
+ const intervalValidator = (interval) => {
8
+ if (typeof interval !== "number" && typeof interval !== "string") {
9
+ error("RLLWatcher interval must be a number.");
10
+ return DEFAULT_INTERVAL_IN_MINS;
11
+ }
12
+ if (typeof interval === "string" &&
13
+ (isNaN(Number(interval)) || interval === "")) {
14
+ error("RLLWatcher interval must be a number.", "type");
15
+ return DEFAULT_INTERVAL_IN_MINS;
16
+ }
17
+ const typedInterval = Number(interval);
18
+ if (typedInterval <= 0) {
19
+ error("RLLWatcher interval cannot be a negative number or zero. Watcher intervals should be greater than or equal to 1 minute.");
20
+ return DEFAULT_INTERVAL_IN_MINS;
21
+ }
22
+ if (typedInterval < 1) {
23
+ warn("RLLWatcher does not accept intervals less than 1. Your watcher will default to 5 minute intervals unless corrected.");
24
+ return DEFAULT_INTERVAL_IN_MINS;
25
+ }
26
+ return typedInterval;
27
+ };
28
+ export class RLLWatcher extends EventEmitter {
29
+ _untypedOn;
30
+ _untypedEmit;
31
+ last_call;
32
+ launches = new Map();
33
+ interval;
34
+ params;
35
+ timer;
36
+ running = false;
37
+ queryInFlight = false;
38
+ fetcher;
39
+ constructor(fetcher, interval = DEFAULT_INTERVAL_IN_MINS, options) {
40
+ super();
41
+ this._untypedOn = this.on;
42
+ this._untypedEmit = this.emit;
43
+ this.on = (event, listener) => this._untypedOn(event, listener);
44
+ this.emit = (event, ...args) => this._untypedEmit(event, ...args);
45
+ this.last_call = new Date();
46
+ this.fetcher = fetcher;
47
+ this.interval = intervalValidator(interval);
48
+ this.params = queryOptionsValidator(RLLEndPoint.LAUNCHES, options);
49
+ this.params.delete("limit");
50
+ this.params.delete("page");
51
+ }
52
+ fetchPage = (baseParams, page) => {
53
+ const params = new URLSearchParams(baseParams);
54
+ params.delete("page");
55
+ if (page > 1) {
56
+ params.set("page", page.toString());
57
+ }
58
+ this.emit("call", params);
59
+ return this.fetcher(params);
60
+ };
61
+ fetchAllPages = async (baseParams, callback, concurrency) => {
62
+ const first = await this.fetchPage(baseParams, 1);
63
+ callback(first);
64
+ const lastPage = first.last_page;
65
+ if (lastPage <= 1) {
66
+ return;
67
+ }
68
+ let nextPage = 2;
69
+ const workerCount = Math.min(Math.max(concurrency, 1), lastPage - 1);
70
+ const workers = Array.from({ length: workerCount }, async () => {
71
+ while (nextPage <= lastPage) {
72
+ const page = nextPage;
73
+ nextPage += 1;
74
+ const results = await this.fetchPage(baseParams, page);
75
+ callback(results);
76
+ }
77
+ });
78
+ await Promise.all(workers);
79
+ };
80
+ query() {
81
+ if (this.queryInFlight) {
82
+ return;
83
+ }
84
+ this.queryInFlight = true;
85
+ const pollStartedAt = new Date();
86
+ const notify = (response) => {
87
+ for (const changedLaunch of response.result) {
88
+ const { id } = changedLaunch;
89
+ const oldLaunch = this.launches.get(id);
90
+ if (oldLaunch) {
91
+ this.emit("change", oldLaunch, changedLaunch);
92
+ }
93
+ else {
94
+ this.emit("new", changedLaunch);
95
+ }
96
+ this.launches.set(changedLaunch.id, changedLaunch);
97
+ }
98
+ };
99
+ this.params.set("modified_since", formatToRLLISODate(this.last_call));
100
+ this.fetchAllPages(new URLSearchParams(this.params), notify, 1)
101
+ .then(() => {
102
+ this.last_call = pollStartedAt;
103
+ })
104
+ .catch((err) => {
105
+ this.emit("error", err);
106
+ })
107
+ .finally(() => {
108
+ this.queryInFlight = false;
109
+ });
110
+ }
111
+ start() {
112
+ if (this.running) {
113
+ return;
114
+ }
115
+ this.running = true;
116
+ const cacheStartedAt = new Date();
117
+ const buildCache = (response) => {
118
+ for (const launch of response.result) {
119
+ this.launches.set(launch.id, launch);
120
+ }
121
+ };
122
+ this.fetchAllPages(new URLSearchParams(this.params), buildCache, INIT_PAGE_CONCURRENCY)
123
+ .then(() => {
124
+ if (!this.running) {
125
+ return;
126
+ }
127
+ this.emit("ready", this.launches);
128
+ this.last_call = cacheStartedAt;
129
+ this.timer = setInterval(() => {
130
+ this.query();
131
+ }, this.interval * MS_IN_MIN);
132
+ })
133
+ .catch((err) => {
134
+ this.running = false;
135
+ this.emit("init_error", err);
136
+ });
137
+ }
138
+ stop() {
139
+ this.running = false;
140
+ if (this.timer) {
141
+ clearInterval(this.timer);
142
+ this.timer = undefined;
143
+ }
144
+ }
145
+ }
@@ -0,0 +1,25 @@
1
+ import { RLLClient } from "../Client.js";
2
+ import { RLLQueryConfig } from "../types/application.js";
3
+ import { RLLWatcher } from "./Watcher.js";
4
+ export { RLLWatcher } from "./Watcher.js";
5
+ /**
6
+ * Create a Watcher that polls the launches endpoint for changes.
7
+ *
8
+ * Import this from `rocket-launch-live-client/watcher` so applications that only
9
+ * need the REST client do not load Watcher code.
10
+ *
11
+ * @param {RLLClient} client - An RLL client created with `rllc()`
12
+ * @param {number | string} [interval] - Poll interval in minutes (default 5, minimum 1)
13
+ * @param {RLLQueryConfig.Launches} [options] - Launch query options (same as `client.launches`)
14
+ *
15
+ * @returns {RLLWatcher}
16
+ *
17
+ * @example
18
+ * import { rllc } from "rocket-launch-live-client";
19
+ * import { watch } from "rocket-launch-live-client/watcher";
20
+ *
21
+ * const client = rllc(process.env.ROCKETLAUNCH_LIVE_API_KEY);
22
+ * const watcher = watch(client, 5, { country_code: "US" });
23
+ * watcher.start();
24
+ */
25
+ export declare const watch: (client: RLLClient, interval?: number | string, options?: RLLQueryConfig.Launches) => RLLWatcher;
@@ -0,0 +1,3 @@
1
+ import { RLLWatcher } from "./Watcher.js";
2
+ export { RLLWatcher } from "./Watcher.js";
3
+ export const watch = (client, interval, options) => new RLLWatcher((params) => client.queryLaunches(params), interval, options);
package/package.json CHANGED
@@ -1,18 +1,20 @@
1
1
  {
2
2
  "name": "rocket-launch-live-client",
3
- "version": "1.0.3",
3
+ "version": "2.0.0",
4
4
  "description": "A Node.JS client for interacting with the RocketLaunch.Live API",
5
- "types": "./lib/cjs/types/index.d.ts",
6
- "main": "./lib/cjs/index.js",
7
- "module": "./lib/mjs/index.js",
5
+ "type": "module",
6
+ "types": "./lib/index.d.ts",
7
+ "main": "./lib/index.js",
8
8
  "scripts": {
9
9
  "clear": "rm -rf ./lib",
10
- "build": "npm run clear && npm run build:esm && npm run build:cjs && ./build-fixup",
11
- "build:esm": "tsc -p ./configs/tsconfig.esm.json && mv lib/esm/index.js lib/esm/index.mjs",
12
- "build:cjs": "tsc -p ./configs/tsconfig.cjs.json",
13
- "prepublish": "npm run build",
10
+ "build": "npm run clear && npm run build:esm && npm run build:types",
11
+ "build:esm": "tsc -p ./configs/tsconfig.esm.json",
12
+ "build:types": "tsc -p ./configs/tsconfig.types.json",
13
+ "prepack": "npm run build",
14
+ "typecheck": "tsc -p ./configs/tsconfig.testing.json",
14
15
  "test": "vitest",
15
- "reset": "rm -rf lib && rm rocket-launch-live-client-*.tgz && npm run build && npm pack"
16
+ "verify:package": "./scripts/verify-package.sh",
17
+ "reset": "rm -rf lib rocket-launch-live-client-*.tgz && npm pack"
16
18
  },
17
19
  "repository": {
18
20
  "type": "git",
@@ -31,31 +33,33 @@
31
33
  },
32
34
  "homepage": "https://github.com/mendahu/rocket-launch-live-client#readme",
33
35
  "devDependencies": {
34
- "@types/node": "^20.9.4",
35
- "@types/sinon": "^17.0.2",
36
- "dotenv": "^16.3.1",
37
- "nock": "^13.3.8",
38
- "sinon": "^17.0.1",
39
- "ts-node": "^10.9.1",
40
- "typescript": "^5.3.2",
41
- "vitest": "^0.34.6"
36
+ "@arethetypeswrong/cli": "^0.18.5",
37
+ "@types/node": "^26.1.1",
38
+ "@types/sinon": "^22.0.0",
39
+ "nock": "^14.0.16",
40
+ "publint": "^0.3.21",
41
+ "sinon": "^22.0.0",
42
+ "typescript": "^7.0.2",
43
+ "vitest": "^4.1.10"
42
44
  },
43
45
  "files": [
44
46
  "lib/**/*"
45
47
  ],
46
48
  "engines": {
47
- "node": ">=14.17.0"
49
+ "node": ">=20.19.0"
48
50
  },
49
51
  "exports": {
50
52
  ".": {
51
- "import": {
52
- "types": "./lib/esm/types/index.d.ts",
53
- "default": "./lib/esm/index.mjs"
54
- },
55
- "require": {
56
- "types": "./lib/cjs/types/index.d.ts",
57
- "default": "./lib/cjs/index.js"
58
- }
53
+ "types": "./lib/index.d.ts",
54
+ "import": "./lib/index.js",
55
+ "require": "./lib/index.js",
56
+ "default": "./lib/index.js"
57
+ },
58
+ "./watcher": {
59
+ "types": "./lib/watcher/index.d.ts",
60
+ "import": "./lib/watcher/index.js",
61
+ "require": "./lib/watcher/index.js",
62
+ "default": "./lib/watcher/index.js"
59
63
  }
60
64
  }
61
65
  }
package/lib/cjs/Client.js DELETED
@@ -1,233 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RLLClient = void 0;
4
- const application_js_1 = require("./types/application.js");
5
- const fetcher_js_1 = require("./fetcher.js");
6
- const utils_js_1 = require("./utils.js");
7
- const Watcher_js_1 = require("./Watcher.js");
8
- /**
9
- * Class representing a RocketLaunch.Live client
10
- * @class
11
- */
12
- class RLLClient {
13
- /**
14
- * Create a new RocketLaunch.live Client
15
- *
16
- * @param {string} apiKey - Your RocketLaunch.Live API Key
17
- * @param {Object} [options] - Optional Client Configuration options
18
- * @param {boolean} options.keyInQueryParams - Set to true to send your API Key via Query parameters instead of Authorization Header (not recommended)
19
- *
20
- */
21
- constructor(apiKey, options) {
22
- this.config = {
23
- keyInQueryParams: false,
24
- };
25
- // Validate API Key is a valid UUID format
26
- // Constructor throws if not
27
- this.apiKey = (0, utils_js_1.apiKeyValidator)(apiKey);
28
- if (!options) {
29
- return;
30
- }
31
- // Validate Options with warnings or throws
32
- (0, utils_js_1.optionsValidator)(options);
33
- if (options.keyInQueryParams) {
34
- this.config.keyInQueryParams = options.keyInQueryParams;
35
- }
36
- }
37
- /**
38
- * Used internally to make API query
39
- *
40
- * @private
41
- *
42
- * @template T
43
- *
44
- * @param {string} endpoint - API endpoint (ie. "/launches")
45
- * @param {URLSearchParams} params - API Search Params
46
- *
47
- * @returns {Promise<T>}
48
- */
49
- query(endpoint, params) {
50
- return (0, fetcher_js_1.fetcher)(this.apiKey, endpoint, params, this.config.keyInQueryParams);
51
- }
52
- /**
53
- * Instantiate a new RLL Watcher which will continually query the API for changes to the launches endpoint
54
- *
55
- * @public
56
- *
57
- * @param {number} interval - Interval in minutes to query the API for changes. Defaults to 5 minutes, cannot be less than 1 minute
58
- * @param {RLLQueryConfig.Launches} options - Query options, same as calling the launches method
59
- *
60
- * @returns {RLLWatcher}
61
- */
62
- watch(interval, options) {
63
- return new Watcher_js_1.RLLWatcher((params) => this.query(application_js_1.RLLEndPoint.LAUNCHES, params), interval, options);
64
- }
65
- /**
66
- * Fetch launch companies
67
- *
68
- * @public
69
- * @function
70
- *
71
- * @param {Object} [options] - Launch Company Search Options
72
- * @param {number | string} options.id - Company id
73
- * @param {number | string} options.page - Page number of results
74
- * @param {number | string} options.name - Company name
75
- * @param {ISO3166Alpha2.CountryCode} options.country_code - ISO 3166 Alpha 2 Country Code
76
- * @param {boolean} options.inactive - Company inactive status
77
- *
78
- * @returns {Promise<RLLResponse<RLLEntity.Company[]>>} Array of companies wrapped in a standard RLL Response
79
- *
80
- * @example
81
- *
82
- * const response = await client.companies({ country_code: "US" })
83
- */
84
- companies(options) {
85
- const params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.COMPANIES, options);
86
- return this.query(application_js_1.RLLEndPoint.COMPANIES, params);
87
- }
88
- /**
89
- * Fetch launches
90
- *
91
- * @public
92
- * @function
93
- *
94
- * @param {Object} [options] - Launch Search Options
95
- * @param {number | string} options.id - Launch id
96
- * @param {number | string} options.page - Page number of results
97
- * @param {string} options.cospar_id - Launch COSPAR ID (ie. 2022-123)
98
- * @param {Date | string} options.before_date - Only return launches before this date
99
- * @param {Date | string} options.after_date - Only return launches after this date
100
- * @param {Date | string} options.modified_since - Only return launches with API changes after this date
101
- * @param {number | string} options.location_id - Launches from this Location
102
- * @param {number | string} options.pad_id - Launches from this Pad
103
- * @param {number | string} options.provider_id - Launches from this Company
104
- * @param {number | string} options.tag_id - Launches with this Tag
105
- * @param {number | string} options.vehicle_id - Launches on this Vehicle
106
- * @param {ISO3166Alpha2.StateCodeUS} options.state_abbr - ISO 3166 Alpha 2 US State Code
107
- * @param {ISO3166Alpha2.CountryCode} options.country_code - ISO 3166 Alpha 2 Country Code
108
- * @param {number | string} options.search - Launches matching this search string
109
- * @param {number | string} options.slug - Launches matching this unique slug
110
- * @param {number | string} options.limit - Limit results (default 25, max 25)
111
- * @param {'asc' | 'desc'} options.direction - Launches matching this unique slug
112
- *
113
- * @returns {Promise<RLLResponse<RLLEntity.Launch[]>>} Array of companies wrapped in a standard RLL Response
114
- *
115
- * @example
116
- *
117
- * const response = await client.launches({ after_date: new Date("2022-10-10") })
118
- */
119
- launches(options) {
120
- const params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.LAUNCHES, options);
121
- return this.query(application_js_1.RLLEndPoint.LAUNCHES, params);
122
- }
123
- /**
124
- * Fetch launch locations
125
- *
126
- * @public
127
- * @function
128
- *
129
- * @param {Object} [options] - Launch Location Search Options
130
- * @param {number | string} options.id - Location id
131
- * @param {number | string} options.page - Page number of results
132
- * @param {number | string} options.name - Location name
133
- * @param {ISO3166Alpha2.StateCodeUS} options.state_abbr - ISO 3166 Alpha 2 US State Code
134
- * @param {ISO3166Alpha2.CountryCode} options.country_code - ISO 3166 Alpha 2 Country Code
135
- *
136
- * @returns {Promise<RLLResponse<RLLEntity.Location[]>>} Array of companies wrapped in a standard RLL Response
137
- *
138
- * @example
139
- *
140
- * const response = await client.locations({ country_code: "US" })
141
- */
142
- locations(options) {
143
- const params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.LOCATIONS, options);
144
- return this.query(application_js_1.RLLEndPoint.LOCATIONS, params);
145
- }
146
- /**
147
- * Fetch launch Missions
148
- *
149
- * @public
150
- * @function
151
- *
152
- * @param {Object} [options] - Launch Mission Search Options
153
- * @param {number | string} options.id - Mission id
154
- * @param {number | string} options.page - Page number of results
155
- * @param {number | string} options.name - Mission name
156
- *
157
- * @returns {Promise<RLLResponse<RLLEntity.Mission[]>>} Array of companies wrapped in a standard RLL Response
158
- *
159
- * @example
160
- *
161
- * const response = await client.missions({ name: "Mars 2020" })
162
- */
163
- missions(options) {
164
- const params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.MISSIONS, options);
165
- return this.query(application_js_1.RLLEndPoint.MISSIONS, params);
166
- }
167
- /**
168
- * Fetch launch pads
169
- *
170
- * @public
171
- * @function
172
- *
173
- * @param {Object} [options] - Launch Pad Search Options
174
- * @param {number | string} options.id - Pad id
175
- * @param {number | string} options.page - Page number of results
176
- * @param {number | string} options.name - Pad name
177
- * @param {ISO3166Alpha2.StateCodeUS} options.state_abbr - ISO 3166 Alpha 2 US State Code
178
- * @param {ISO3166Alpha2.CountryCode} options.country_code - ISO 3166 Alpha 2 Country Code
179
- *
180
- * @returns {Promise<RLLResponse<RLLEntity.Pad[]>>} Array of companies wrapped in a standard RLL Response
181
- *
182
- * @example
183
- *
184
- * const response = await client.pads({ country_code: "US" })
185
- */
186
- pads(options) {
187
- const params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.PADS, options);
188
- return this.query(application_js_1.RLLEndPoint.PADS, params);
189
- }
190
- /**
191
- * Fetch launch tags
192
- *
193
- * @public
194
- * @function
195
- *
196
- * @param {Object} [options] - Launch Tag Search Options
197
- * @param {number | string} options.id - Tag id
198
- * @param {number | string} options.page - Page number of results
199
- * @param {number | string} options.text - Tag text
200
- *
201
- * @returns {Promise<RLLResponse<RLLEntity.Tag[]>>} Array of companies wrapped in a standard RLL Response
202
- *
203
- * @example
204
- *
205
- * const response = await client.tags({ text: "Crewed" })
206
- */
207
- tags(options) {
208
- const params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.TAGS, options);
209
- return this.query(application_js_1.RLLEndPoint.TAGS, params);
210
- }
211
- /**
212
- * Fetch launch Vehicles
213
- *
214
- * @public
215
- * @function
216
- *
217
- * @param {Object} [options] - Launch Vehicles Search Options
218
- * @param {number | string} options.id - Vehicle id
219
- * @param {number | string} options.page - Page number of results
220
- * @param {number | string} options.name - Vehicle name
221
- *
222
- * @returns {Promise<RLLResponse<RLLEntity.Vehicle[]>>} Array of companies wrapped in a standard RLL Response
223
- *
224
- * @example
225
- *
226
- * const response = await client.vehicles({ name: "Falcon 9" })
227
- */
228
- vehicles(options) {
229
- const params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.VEHICLES, options);
230
- return this.query(application_js_1.RLLEndPoint.VEHICLES, params);
231
- }
232
- }
233
- exports.RLLClient = RLLClient;
@@ -1,172 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.RLLWatcher = void 0;
4
- const events_1 = require("events");
5
- const application_js_1 = require("./types/application.js");
6
- const utils_js_1 = require("./utils.js");
7
- const DEFAULT_INTERVAL_IN_MINS = 5;
8
- const MS_IN_MIN = 60000;
9
- const intervalValidator = (interval) => {
10
- if (typeof interval !== "number" && typeof interval !== "string") {
11
- (0, utils_js_1.error)("RLLWatcher interval must be a number.");
12
- return DEFAULT_INTERVAL_IN_MINS;
13
- }
14
- if (typeof interval === "string" &&
15
- (isNaN(Number(interval)) || interval === "")) {
16
- (0, utils_js_1.error)("RLLWatcher interval must be a number.", "type");
17
- return DEFAULT_INTERVAL_IN_MINS;
18
- }
19
- const typedInterval = Number(interval);
20
- if (typedInterval <= 0) {
21
- (0, utils_js_1.error)("RLLWatcher interval cannot be a negative number or zero. Watcher intervals should be greater than or equal to 1 minute.");
22
- return DEFAULT_INTERVAL_IN_MINS;
23
- }
24
- if (typedInterval < 1) {
25
- (0, utils_js_1.warn)("RLLWatcher does not accept intervals less than 1. Your watcher will default to 5 minute intervals unless corrected.");
26
- return DEFAULT_INTERVAL_IN_MINS;
27
- }
28
- return typedInterval;
29
- };
30
- /**
31
- * Class representing a RocketLaunch.Live Client Watcher
32
- * @class
33
- */
34
- class RLLWatcher extends events_1.EventEmitter {
35
- /**
36
- * Create a new RocketLaunch.live Client Watcher
37
- *
38
- * @param {function(params: URLSearchParams): Promise<RLLResponse<RLLEntity.Launch[]>>} fetcher - fetcher function to make API calls
39
- * @param {number | string} [interval] - Optional Client Configuration options
40
- * @param {Object} [options] - Launch Search Options
41
- * @param {number | string} options.id - Launch id
42
- * @param {number | string} options.page - Page number of results
43
- * @param {string} options.cospar_id - Launch COSPAR ID (ie. 2022-123)
44
- * @param {Date | string} options.before_date - Only return launches before this date
45
- * @param {Date | string} options.after_date - Only return launches after this date
46
- * @param {Date | string} options.modified_since - Only return launches with API changes after this date
47
- * @param {number | string} options.location_id - Launches from this Location
48
- * @param {number | string} options.pad_id - Launches from this Pad
49
- * @param {number | string} options.provider_id - Launches from this Company
50
- * @param {number | string} options.tag_id - Launches with this Tag
51
- * @param {number | string} options.vehicle_id - Launches on this Vehicle
52
- * @param {ISO3166Alpha2.StateCodeUS} options.state_abbr - ISO 3166 Alpha 2 US State Code
53
- * @param {ISO3166Alpha2.CountryCode} options.country_code - ISO 3166 Alpha 2 Country Code
54
- * @param {number | string} options.search - Launches matching this search string
55
- * @param {number | string} options.slug - Launches matching this unique slug
56
- *
57
- */
58
- constructor(fetcher, interval = DEFAULT_INTERVAL_IN_MINS, options) {
59
- super();
60
- this.launches = new Map();
61
- /**
62
- * Recursive API Caller to iterate through pages
63
- *
64
- * @private
65
- * @function
66
- *
67
- * @param {URLSearchParams} params - Search parameters
68
- * @param {function(results: RLLResponse<RLLEntity.Launch[]>)} callback - To execute on each page
69
- *
70
- * @returns {Promise<void>}
71
- */
72
- this.recursivelyFetch = (params, callback) => {
73
- let page = 1;
74
- const recursiveFetcher = () => {
75
- this.emit("call", params);
76
- return this.fetcher(params).then((results) => {
77
- callback(results);
78
- if (results.last_page > page) {
79
- page++;
80
- params.set("page", page.toString());
81
- return recursiveFetcher();
82
- }
83
- return;
84
- });
85
- };
86
- return recursiveFetcher();
87
- };
88
- // Reassign default Event Emitter methods
89
- this._untypedOn = this.on;
90
- this._untypedEmit = this.emit;
91
- // Methord Overide for type safety
92
- this.on = (event, listener) => this._untypedOn(event, listener);
93
- this.emit = (event, ...args) => this._untypedEmit(event, ...args);
94
- this.last_call = new Date();
95
- this.fetcher = fetcher;
96
- this.interval = intervalValidator(interval);
97
- this.params = (0, utils_js_1.queryOptionsValidator)(application_js_1.RLLEndPoint.LAUNCHES, options);
98
- // ignore any limit params as these cause unnecessary API calls and do not serve the Watcher role
99
- this.params.delete("limit");
100
- }
101
- /**
102
- * Query wrapper to trigger events
103
- *
104
- * @private
105
- * @function
106
- *
107
- * @returns {void}
108
- */
109
- query() {
110
- const notify = (response) => {
111
- for (const changedLaunch of response.result) {
112
- const { id } = changedLaunch;
113
- const oldLaunch = this.launches.get(id);
114
- if (oldLaunch) {
115
- this.emit("change", oldLaunch, changedLaunch);
116
- }
117
- else {
118
- this.emit("new", changedLaunch);
119
- }
120
- this.launches.set(changedLaunch.id, changedLaunch);
121
- }
122
- };
123
- this.params.set("modified_since", (0, utils_js_1.formatToRLLISODate)(this.last_call));
124
- this.recursivelyFetch(new URLSearchParams(this.params), notify)
125
- .then(() => {
126
- this.last_call = new Date();
127
- })
128
- .catch((err) => {
129
- this.emit("error", err);
130
- });
131
- }
132
- /**
133
- * Begin monitoring API using the configured query parameters.
134
- *
135
- * @public
136
- * @function
137
- *
138
- * @returns {void}
139
- */
140
- start() {
141
- const buildCache = (response) => {
142
- for (const launch of response.result) {
143
- this.launches.set(launch.id, launch);
144
- }
145
- };
146
- this.recursivelyFetch(new URLSearchParams(this.params), buildCache)
147
- .then(() => {
148
- this.emit("ready", this.launches);
149
- this.last_call = new Date();
150
- this.timer = setInterval(() => {
151
- this.query();
152
- }, this.interval * MS_IN_MIN);
153
- })
154
- .catch((err) => {
155
- this.emit("init_error", err);
156
- });
157
- }
158
- /**
159
- * Stop monitoring API
160
- *
161
- * @public
162
- * @function
163
- *
164
- * @returns {void}
165
- */
166
- stop() {
167
- if (this.timer) {
168
- clearInterval(this.timer);
169
- }
170
- }
171
- }
172
- exports.RLLWatcher = RLLWatcher;