eve-esi-types 2.0.4-beta → 2.0.5-beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve-esi-types",
3
- "version": "2.0.4-beta",
3
+ "version": "2.0.5-beta",
4
4
  "description": "Extracted the main type of ESI. use for ESI request response types",
5
5
  "main": "src/index.d.ts",
6
6
  "scripts": {
@@ -13,6 +13,16 @@
13
13
  "type": "git",
14
14
  "url": "git+ssh://git@github.com/jeffy-g/eve-esi-types.git"
15
15
  },
16
+ "files": [
17
+ "v2",
18
+ "src",
19
+ "v2.mjs",
20
+ "LICENSE",
21
+ "README.md",
22
+ "package.json",
23
+ "tsconfig.json",
24
+ "esi-request.mjs"
25
+ ],
16
26
  "keywords": [
17
27
  "eve",
18
28
  "esi",
@@ -1,220 +1,86 @@
1
1
  /*!
2
2
  * ESI endpoint: /universe/ids/
3
3
  */
4
- /**
5
- * agents array
6
- *
7
- * @maxItems 500
8
- */
9
- type PostUniverseIdsAgents = PostUniverseIdsAgent[];
10
- /**
11
- * alliances array
12
- *
13
- * @maxItems 500
14
- */
15
- type PostUniverseIdsAlliances = PostUniverseIdsAlliance[];
16
- /**
17
- * characters array
18
- *
19
- * @maxItems 500
20
- */
21
- type PostUniverseIdsCharacters = PostUniverseIdsCharacter[];
22
- /**
23
- * constellations array
24
- *
25
- * @maxItems 500
26
- */
27
- type PostUniverseIdsConstellations = PostUniverseIdsConstellation[];
28
- /**
29
- * corporations array
30
- *
31
- * @maxItems 500
32
- */
33
- type PostUniverseIdsCorporations = PostUniverseIdsCorporation[];
34
- /**
35
- * factions array
36
- *
37
- * @maxItems 500
38
- */
39
- type PostUniverseIdsFactions = PostUniverseIdsFaction[];
40
- /**
41
- * inventory_types array
42
- *
43
- * @maxItems 500
44
- */
45
- type PostUniverseIdsInventoryTypes = PostUniverseIdsInventoryType[];
46
- /**
47
- * regions array
48
- *
49
- * @maxItems 500
50
- */
51
- type PostUniverseIdsRegions = PostUniverseIdsRegion[];
52
- /**
53
- * stations array
54
- *
55
- * @maxItems 500
56
- */
57
- type PostUniverseIdsStations = PostUniverseIdsStation[];
58
- /**
59
- * systems array
60
- *
61
- * @maxItems 500
62
- */
63
- type PostUniverseIdsSystems = PostUniverseIdsSystem[];
64
4
 
65
5
  /**
66
- * 200 ok object
67
- */
68
- interface PostUniverseIdsOk {
69
- agents?: PostUniverseIdsAgents;
70
- alliances?: PostUniverseIdsAlliances;
71
- characters?: PostUniverseIdsCharacters;
72
- constellations?: PostUniverseIdsConstellations;
73
- corporations?: PostUniverseIdsCorporations;
74
- factions?: PostUniverseIdsFactions;
75
- inventory_types?: PostUniverseIdsInventoryTypes;
76
- regions?: PostUniverseIdsRegions;
77
- stations?: PostUniverseIdsStations;
78
- systems?: PostUniverseIdsSystems;
79
- [k: string]: unknown | undefined;
80
- }
81
- /**
82
- * agent object
83
- */
84
- interface PostUniverseIdsAgent {
85
- /**
86
- * id integer
87
- */
88
- id?: number;
89
- /**
90
- * name string
91
- */
92
- name?: string;
93
- [k: string]: unknown | undefined;
94
- }
95
- /**
96
- * alliance object
97
- */
98
- interface PostUniverseIdsAlliance {
99
- /**
100
- * id integer
101
- */
102
- id?: number;
103
- /**
104
- * name string
105
- */
106
- name?: string;
107
- [k: string]: unknown | undefined;
108
- }
109
- /**
110
- * character object
111
- */
112
- interface PostUniverseIdsCharacter {
113
- /**
114
- * id integer
115
- */
116
- id?: number;
117
- /**
118
- * name string
119
- */
120
- name?: string;
121
- [k: string]: unknown | undefined;
122
- }
123
- /**
124
- * constellation object
125
- */
126
- interface PostUniverseIdsConstellation {
127
- /**
128
- * id integer
129
- */
130
- id?: number;
131
- /**
132
- * name string
133
- */
134
- name?: string;
135
- [k: string]: unknown | undefined;
136
- }
137
- /**
138
- * corporation object
139
- */
140
- interface PostUniverseIdsCorporation {
141
- /**
142
- * id integer
143
- */
144
- id?: number;
145
- /**
146
- * name string
147
- */
148
- name?: string;
149
- [k: string]: unknown | undefined;
150
- }
151
- /**
152
- * faction object
153
- */
154
- interface PostUniverseIdsFaction {
155
- /**
156
- * id integer
157
- */
158
- id?: number;
159
- /**
160
- * name string
161
- */
162
- name?: string;
163
- [k: string]: unknown | undefined;
164
- }
165
- /**
166
- * inventory_type object
167
- */
168
- interface PostUniverseIdsInventoryType {
169
- /**
170
- * id integer
171
- */
172
- id?: number;
173
- /**
174
- * name string
175
- */
176
- name?: string;
177
- [k: string]: unknown | undefined;
178
- }
179
- /**
180
- * region object
181
- */
182
- interface PostUniverseIdsRegion {
183
- /**
184
- * id integer
185
- */
186
- id?: number;
187
- /**
188
- * name string
189
- */
190
- name?: string;
191
- [k: string]: unknown | undefined;
192
- }
193
- /**
194
- * station object
195
- */
196
- interface PostUniverseIdsStation {
197
- /**
198
- * id integer
199
- */
200
- id?: number;
201
- /**
202
- * name string
203
- */
204
- name?: string;
205
- [k: string]: unknown | undefined;
206
- }
207
- /**
208
- * system object
209
- */
210
- interface PostUniverseIdsSystem {
211
- /**
212
- * id integer
213
- */
214
- id?: number;
215
- /**
216
- * name string
217
- */
218
- name?: string;
219
- [k: string]: unknown | undefined;
220
- }
6
+ * shared interface
7
+ */
8
+ interface PostUniverseIdsEntity {
9
+ /**
10
+ * id integer
11
+ */
12
+ id?: number;
13
+ /**
14
+ * name string
15
+ */
16
+ name?: string;
17
+ [k: string]: unknown | undefined;
18
+ }
19
+
20
+ /**
21
+ * 200 ok object
22
+ */
23
+ interface PostUniverseIdsOk {
24
+ /**
25
+ * agents array
26
+ *
27
+ * @maxItems 500
28
+ */
29
+ agents?: PostUniverseIdsEntity[];
30
+ /**
31
+ * alliances array
32
+ *
33
+ * @maxItems 500
34
+ */
35
+ alliances?: PostUniverseIdsEntity[];
36
+ /**
37
+ * characters array
38
+ *
39
+ * @maxItems 500
40
+ */
41
+ characters?: PostUniverseIdsEntity[];
42
+ /**
43
+ * constellations array
44
+ *
45
+ * @maxItems 500
46
+ */
47
+ constellations?: PostUniverseIdsEntity[];
48
+ /**
49
+ * corporations array
50
+ *
51
+ * @maxItems 500
52
+ */
53
+ corporations?: PostUniverseIdsEntity[];
54
+ /**
55
+ * factions array
56
+ *
57
+ * @maxItems 500
58
+ */
59
+ factions?: PostUniverseIdsEntity[];
60
+ /**
61
+ * inventory_types array
62
+ *
63
+ * @maxItems 500
64
+ */
65
+ inventory_types?: PostUniverseIdsEntity[];
66
+ /**
67
+ * regions array
68
+ *
69
+ * @maxItems 500
70
+ */
71
+ regions?: PostUniverseIdsEntity[];
72
+ /**
73
+ * stations array
74
+ *
75
+ * @maxItems 500
76
+ */
77
+ stations?: PostUniverseIdsEntity[];
78
+ /**
79
+ * systems array
80
+ *
81
+ * @maxItems 500
82
+ */
83
+ systems?: PostUniverseIdsEntity[];
84
+ [k: string]: unknown | undefined;
85
+ }
86
+
package/esi-request.mts DELETED
@@ -1,309 +0,0 @@
1
- /*!
2
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3
- Copyright (C) 2025 jeffy-g <hirotom1107@gmail.com>
4
- Released under the MIT license
5
- https://opensource.org/licenses/mit-license.php
6
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
- */
8
- // - - - - - - - - - - - - - - - - - - - -
9
- // imports
10
- // - - - - - - - - - - - - - - - - - - - -
11
- import type { TESIResponseOKMap } from "./src";
12
- // import type { TESIResponseOKMap } from "eve-esi-types";
13
-
14
-
15
- // - - - - - - - - - - - - - - - - - - - -
16
- // constants, types
17
- // - - - - - - - - - - - - - - - - - - - -
18
- // shorthands
19
- const log = console.log;
20
- const isArray = Array.isArray;
21
- /**
22
- * enable/disable console.log
23
- */
24
- let LOG = false;
25
- /**
26
- * this always `https://esi.evetech.net`
27
- */
28
- const BASE = "https://esi.evetech.net";
29
-
30
-
31
- type TRequestMethod = "get" | "post" | "put" | "delete";
32
- type ESIRequestOptions = {
33
- /**
34
- * query params for ESI request.
35
- */
36
- queries?: Record<string, any>;
37
- /**
38
- * will need it for `POST` request etc.
39
- */
40
- body?: any;
41
- /**
42
- * if want response data with ignore error then can be set to `true`.
43
- */
44
- ignoreError?: boolean;
45
- /**
46
- * cancel request immediately
47
- */
48
- cancelable?: AbortController;
49
-
50
- /**
51
- * Can be an empty object if no authentication is required.description
52
- */
53
- token?: string;
54
- };
55
- /**
56
- * @typedef {import("./src").TESIResponseOKMap} TESIResponseOKMap
57
- */
58
- /**
59
- * @typedef ESIRequestOptions
60
- * @prop {Record<string, any>} [queries] query params for ESI request.
61
- * @prop {any} [body] will need it for `POST` request etc.
62
- * @prop {boolean} [ignoreError] if want response data with ignore error then can be set to `true`.
63
- * @prop {AbortController} [cancelable] cancel request immediately
64
- * @prop {string} [token] Can be an empty object if no authentication is required.description
65
- */
66
-
67
-
68
- // - - - - - - - - - - - - - - - - - - - -
69
- // module vars, functions
70
- // - - - - - - - - - - - - - - - - - - - -
71
- /**
72
- * Get the number of currently executing ESI requests
73
- */
74
- let ax: number = 0;
75
- /**
76
- * simple named error class.
77
- */
78
- class ESIRequesError extends Error {}
79
- /**
80
- * throws when x-esi-error-limit-remain header value is "0". (http status: 420)
81
- */
82
- class ESIErrorLimitReachedError extends Error {
83
- constructor() {
84
- super("Cannot continue ESI request because 'x-esi-error-limit-remain' is zero!");
85
- }
86
- valueOf(): number {
87
- return 420;
88
- }
89
- }
90
- /**
91
- * fetch the extra pages
92
- *
93
- * + if the `x-pages` header property ware more than 1
94
- *
95
- * @param {string} endpointUrl
96
- * @param {RequestInit} rqopt request options
97
- * @param {Record<string, any>} qs queries
98
- * @param {number} pc pageCount
99
- */
100
- const fetchP = async <T extends any>(endpointUrl: string, rqopt: RequestInit, qs: Record<string, any>, pc: number) => {
101
- const rqs: Promise<T>[] = [];
102
- const rqp = new URLSearchParams(qs);
103
- for (let i = 2; i <= pc; ) {
104
- rqp.set("page", (i++) + "");
105
- ax++;
106
- rqs.push(
107
- fetch(`${endpointUrl}?${rqp + ""}`, rqopt).then(
108
- res => res.json()
109
- ).catch(reason => {
110
- console.warn(reason);
111
- return [] as T;
112
- }).finally(() => {
113
- ax--;
114
- })
115
- );
116
- }
117
- return Promise.all(rqs).then(jsons => {
118
- // DEVNOTE: let check the page 2, type is array?
119
- if (isArray(jsons[0])) {
120
- let combined: any[] = [];
121
- for (let i = 0, end = jsons.length; i < end;) {
122
- combined = combined.concat(jsons[i++]);
123
- }
124
- return combined as T;
125
- }
126
-
127
- LOG && log("> > > pages result are object < < < --", jsons);
128
- return null;
129
- });
130
- };
131
-
132
- /** ### replace (C)urly (B)races (T)oken
133
- *
134
- * @example
135
- * "/characters/{character_id}/skills"
136
- * // ->
137
- * "/characters/<char.character_id>/skills"
138
- *
139
- * @param {string} endpoint e.g - "/characters/{character_id}/"
140
- * @param {number[]} ids
141
- * @returns fragment of qualified endpoint uri or null.
142
- */
143
- const replaceCbt = (endpoint: string, ids: number[]) => {
144
- const re = /{([\w]+)}/g;
145
- /** @type {RegExpExecArray?} */
146
- let m: RegExpExecArray | null;
147
- let idx = 0
148
- while (m = re.exec(endpoint)) {
149
- endpoint = endpoint.replace(m[0], ids[idx++] + "");
150
- }
151
- return endpoint;
152
- };
153
- /**
154
- *
155
- * @param {string} endp this means endpoint url fragment like `/characters/{character_id}/` or `/characters/{character_id}/agents_research/`
156
- * + The version parameter can be omitted by using `<version>/<endpoint>`
157
- */
158
- const curl = (endp: string) => {
159
- endp = endp.replace(/^\/+|\/+$/g, "");
160
- return `${BASE}/latest/${endp}/`;
161
- };
162
-
163
-
164
- // - - - - - - - - - - - - - - - - - - - -
165
- // main functions
166
- // - - - - - - - - - - - - - - - - - - - -
167
- /**
168
- * fire ESI request
169
- * @template {"get" | "post" | "put" | "delete"} M
170
- * @template {keyof TESIResponseOKMap[M]} EP
171
- * @template {TESIResponseOKMap[M][EP]} R
172
- *
173
- * @param {M} mthd
174
- * @param {EP} endp - The endpoint to request.
175
- * @param {number | number[] | ESIRequestOptions} [pathParams] - Optional path parameters.
176
- * @param {ESIRequestOptions} [opt] - default is empty object {}. `body` is json string
177
- * @returns {Promise<R>} - The response from the endpoint.
178
- * @throws
179
- * @async
180
- */
181
- export async function fire<
182
- M extends TRequestMethod,
183
- EP extends keyof TESIResponseOKMap[M],
184
- R extends TESIResponseOKMap[M][EP]
185
- >(
186
- mthd: M, endp: EP, pathParams?: number | number[] | ESIRequestOptions,
187
- opt: ESIRequestOptions = {}
188
- ): Promise<R> {
189
-
190
- if (typeof pathParams === "number") {
191
- pathParams = /** @type {number[]} */([pathParams]);
192
- }
193
- if (isArray(pathParams)) {
194
- // @ts-ignore actualy endp is string
195
- endp = replaceCbt(endp, pathParams) as EP;
196
- } else {
197
- // When only options are provided
198
- opt = /** @type {ESIRequestOptions} */(pathParams) as ESIRequestOptions || opt;
199
- }
200
-
201
- /** @type {RequestInit} */
202
- const rqopt: RequestInit = {
203
- method: mthd,
204
- mode: "cors",
205
- cache: "no-cache",
206
- signal: opt.cancelable?.signal,
207
- headers: {}
208
- };
209
- const qss: Record<string, string> = {
210
- // language: "en",
211
- };
212
-
213
- if (opt.queries) {
214
- // Object.assign(queries, options.queries); Object.assign is too slow
215
- const oqs = opt.queries;
216
- for (const k of Object.keys(oqs)) {
217
- qss[k] = oqs[k] as string;
218
- }
219
- }
220
- // DEVNOTE: when datasource is not empty string. (e.g - "singularity"
221
- // in this case must specify datasource.
222
- // disabled since `REMOVING DATASOURCE SINGULARITY`
223
- // if (opt.datasource === "singularity") {
224
- // opt.datasource = "tranquility";
225
- // }
226
- if (opt.token) {
227
- // @ts-ignore The header is indeed an object
228
- (rqopt.headers as any).authorization = `Bearer ${opt.token}`;
229
- }
230
- if (opt.body) { // means "POST" method etc
231
- // @ts-ignore The header is indeed an object
232
- (rqopt.headers as any)["content-type"] = "application/json";
233
- rqopt.body = JSON.stringify(opt.body);
234
- }
235
-
236
- // @ts-ignore actualy endp is string
237
- const endpointUrl = curl(endp);
238
- ax++;
239
- try {
240
- // @ts-ignore A silly type error will appear, but ignore it.
241
- const res = await fetch(
242
- `${endpointUrl}?${new URLSearchParams(qss) + ""}`, rqopt
243
- ).finally(() => {
244
- ax--;
245
- });
246
-
247
- const stat = res.status;
248
- if (!res.ok && !opt.ignoreError) {
249
- if (stat === 420) {
250
- opt.cancelable && opt.cancelable.abort();
251
- throw new ESIErrorLimitReachedError();
252
- } else {
253
- // @ts-ignore actualy endp is string
254
- throw new ESIRequesError(`maybe network disconneted or otherwise request data are invalid. (endpoint=${endp}, http status=${stat})`);
255
- }
256
- } else {
257
- // DEVNOTE: - 204 No Content
258
- if (stat === 204) {
259
- // this result is empty, decided to return status code.
260
- return /** @type {R} */({ status: stat }) as unknown as R;
261
- }
262
-
263
- /** @type {R} */
264
- const data: R = await res.json();
265
- if (opt.ignoreError) {
266
- // meaning `forceJson`?
267
- return data;
268
- }
269
- // - - - - x-pages response.
270
- // +undefined is NaN
271
- // @ts-ignore becouse +null is 0
272
- const pc = +res.headers.get("x-pages")!;
273
- // has remaining pages? NaN > 1 === false !isNaN(pageCount)
274
- if (pc > 1) {
275
- LOG && log('found "x-pages" header, pages: %d', pc);
276
- const remData = await fetchP<R>(endpointUrl, rqopt, qss, pc);
277
- // finally, decide product data.
278
- if (isArray(data) && isArray(remData)) {
279
- // DEVNOTE: 2019/7/23 15:01:48 - types
280
- return /** @type {R} */(data.concat(remData)) as unknown as R;
281
- } else {
282
- // @ts-ignore TODO: fix type
283
- remData && Object.assign(data, remData);
284
- }
285
- }
286
-
287
- return data;
288
- }
289
-
290
- } catch (e) {
291
- // @ts-ignore actualy endp is string
292
- throw new ESIRequesError(`unknown error occurred, message: ${(e as Error).message}, endpoint=${endp}`);
293
- }
294
- }
295
-
296
- // It should complete correctly.
297
- async function getEVEStatus() {
298
- return fire("get", "/status/");
299
- }
300
-
301
- // type following and run
302
- // node esi-request.mjs
303
- // or yarn test
304
- getEVEStatus().then(eveStatus => console.log(eveStatus));
305
- // {
306
- // "players": 16503,
307
- // "server_version": "2794925",
308
- // "start_time": "2025-01-21T11:02:34Z"
309
- // }
package/snippet.ts DELETED
@@ -1,49 +0,0 @@
1
-
2
- import type { TESIResponseOKMap } from "./v2";
3
-
4
- type ESIRequestOptions = {
5
- /**
6
- * query params for ESI request.
7
- */
8
- queries?: Record<string, any>;
9
- /**
10
- * will need it for `POST` request etc.
11
- */
12
- body?: any;
13
- /**
14
- * if want response data with ignore error then can be set to `true`.
15
- */
16
- ignoreError?: boolean;
17
- /**
18
- * cancel request immediately
19
- */
20
- cancelable?: AbortController;
21
-
22
- /**
23
- * Can be an empty object if no authentication is required.description
24
- */
25
- token?: string;
26
-
27
- auth?: true;
28
- };
29
- // type ESIRequestSig<
30
- // POpt extends Record<string, any>,
31
- // M extends TESIEntryMethod = TESIEntryMethod,
32
- // EP extends keyof TESIResponseOKMap[M] = keyof TESIResponseOKMap[M],
33
- // Opt extends IdentifyParameters<TESIResponseOKMap[M][EP], POpt> = IdentifyParameters<TESIResponseOKMap[M][EP], POpt>,
34
- // R extends InferESIResponseResult<M, EP> = InferESIResponseResult<M, EP>
35
- // > = {
36
- // method: M;
37
- // endpoint: EP;
38
- // option: Opt;
39
- // result: R;
40
- // };
41
- export type ESIRequestSig = <
42
- M extends TESIEntryMethod,
43
- EP extends keyof TESIResponseOKMap[M],
44
- Opt extends IdentifyParameters<TESIResponseOKMap[M][EP], ESIRequestOptions>,
45
- R extends InferESIResponseResult<M, EP>
46
- >(
47
- method: M, endpoint: EP, pathParams?: number | number[] | Opt,
48
- option?: Opt
49
- ) => Promise<R>;
package/v2.mts DELETED
@@ -1,320 +0,0 @@
1
- /*!
2
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
3
- Copyright (C) 2025 jeffy-g <hirotom1107@gmail.com>
4
- Released under the MIT license
5
- https://opensource.org/licenses/mit-license.php
6
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
- */
8
- // - - - - - - - - - - - - - - - - - - - -
9
- // imports
10
- // - - - - - - - - - - - - - - - - - - - -
11
- import type { TESIResponseOKMap } from "./v2";
12
- // import type { TESIResponseOKMap } from "eve-esi-types";
13
-
14
-
15
- // - - - - - - - - - - - - - - - - - - - -
16
- // constants, types
17
- // - - - - - - - - - - - - - - - - - - - -
18
- // shorthands
19
- const log = console.log;
20
- const isArray = Array.isArray;
21
- /**
22
- * enable/disable console.log
23
- */
24
- let LOG = false;
25
- /**
26
- * this always `https://esi.evetech.net`
27
- */
28
- const BASE = "https://esi.evetech.net";
29
-
30
-
31
- type ESIRequestOptions = {
32
- /**
33
- * query params for ESI request.
34
- */
35
- queries?: Record<string, any>;
36
- /**
37
- * will need it for `POST` request etc.
38
- */
39
- body?: any;
40
- /**
41
- * if want response data with ignore error then can be set to `true`.
42
- */
43
- ignoreError?: boolean;
44
- /**
45
- * cancel request immediately
46
- */
47
- cancelable?: AbortController;
48
-
49
- /**
50
- * Can be an empty object if no authentication is required.description
51
- */
52
- token?: string;
53
-
54
- auth?: true;
55
- };
56
- /**
57
- * @typedef {import("./v2").TESIResponseOKMap} TESIResponseOKMap
58
- */
59
- /**
60
- * @typedef ESIRequestOptions
61
- * @prop {Record<string, any>} [queries] query params for ESI request.
62
- * @prop {any} [body] will need it for `POST` request etc.
63
- * @prop {boolean} [ignoreError] if want response data with ignore error then can be set to `true`.
64
- * @prop {AbortController} [cancelable] cancel request immediately
65
- * @prop {string} [token] Can be an empty object if no authentication is required.description
66
- * @prop {true=} [auth] Can be an empty object if no authentication is required.description
67
- */
68
-
69
-
70
- // - - - - - - - - - - - - - - - - - - - -
71
- // module vars, functions
72
- // - - - - - - - - - - - - - - - - - - - -
73
- /**
74
- * Get the number of currently executing ESI requests
75
- */
76
- let ax: number = 0;
77
- /**
78
- * simple named error class.
79
- */
80
- class ESIRequesError extends Error {}
81
- /**
82
- * throws when x-esi-error-limit-remain header value is "0". (http status: 420)
83
- */
84
- class ESIErrorLimitReachedError extends Error {
85
- constructor() {
86
- super("Cannot continue ESI request because 'x-esi-error-limit-remain' is zero!");
87
- }
88
- valueOf(): number {
89
- return 420;
90
- }
91
- }
92
- /**
93
- * fetch the extra pages
94
- *
95
- * + if the `x-pages` header property ware more than 1
96
- *
97
- * @param {string} endpointUrl
98
- * @param {RequestInit} rqopt request options
99
- * @param {Record<string, any>} qs queries
100
- * @param {number} pc pageCount
101
- */
102
- const fetchP = async <T extends any>(endpointUrl: string, rqopt: RequestInit, qs: Record<string, any>, pc: number) => {
103
- const rqs: Promise<T>[] = [];
104
- const rqp = new URLSearchParams(qs);
105
- for (let i = 2; i <= pc; ) {
106
- rqp.set("page", (i++) + "");
107
- ax++;
108
- rqs.push(
109
- fetch(`${endpointUrl}?${rqp + ""}`, rqopt).then(
110
- res => res.json()
111
- ).catch(reason => {
112
- console.warn(reason);
113
- return [] as T;
114
- }).finally(() => {
115
- ax--;
116
- })
117
- );
118
- }
119
- return Promise.all(rqs).then(jsons => {
120
- // DEVNOTE: let check the page 2, type is array?
121
- if (isArray(jsons[0])) {
122
- let combined: any[] = [];
123
- for (let i = 0, end = jsons.length; i < end;) {
124
- combined = combined.concat(jsons[i++]);
125
- }
126
- return combined as T;
127
- }
128
-
129
- LOG && log("> > > pages result are object < < < --", jsons);
130
- return null;
131
- });
132
- };
133
-
134
- /** ### replace (C)urly (B)races (T)oken
135
- *
136
- * @example
137
- * "/characters/{character_id}/skills"
138
- * // ->
139
- * "/characters/<char.character_id>/skills"
140
- *
141
- * @param {string} endpoint e.g - "/characters/{character_id}/"
142
- * @param {number[]} ids
143
- * @returns fragment of qualified endpoint uri or null.
144
- */
145
- const replaceCbt = (endpoint: string, ids: number[]) => {
146
- const re = /{([\w]+)}/g;
147
- /** @type {RegExpExecArray?} */
148
- let m: RegExpExecArray | null;
149
- let idx = 0
150
- while (m = re.exec(endpoint)) {
151
- endpoint = endpoint.replace(m[0], ids[idx++] + "");
152
- }
153
- return endpoint;
154
- };
155
- /**
156
- *
157
- * @param {string} endp this means endpoint url fragment like `/characters/{character_id}/` or `/characters/{character_id}/agents_research/`
158
- * + The version parameter can be omitted by using `<version>/<endpoint>`
159
- */
160
- const curl = (endp: string) => {
161
- endp = endp.replace(/^\/+|\/+$/g, "");
162
- return `${BASE}/latest/${endp}/`;
163
- };
164
-
165
-
166
- // - - - - - - - - - - - - - - - - - - - -
167
- // main functions
168
- // - - - - - - - - - - - - - - - - - - - -
169
- // It should complete correctly.
170
- async function getEVEStatus() {
171
- try {
172
- const ok = await fire("get", "/characters/{character_id}/ship/", 994562, { auth: true, token: "<accessToken of 994562>" });
173
- console.log(ok);
174
- } catch (error) {
175
- console.error("Failed to get character ship -", error);
176
- }
177
- return fire("get", "/status/");
178
- }
179
-
180
- /**
181
- * fire ESI request
182
- * @template {TESIEntryMethod} M
183
- * @template {keyof TESIResponseOKMap[M]} EP
184
- * @template {IdentifyParameters<TESIResponseOKMap[M][EP], ESIRequestOptions>} Opt
185
- * @template {InferESIResponseResult<M, EP>} R
186
- *
187
- * @param {M} mthd
188
- * @param {EP} endp - The endpoint to request.
189
- * @param {number | number[] | Opt} [pathParams] - Optional path parameters.
190
- * @param {Opt} [opt] - default is empty object {}. `body` is json string
191
- * @returns {Promise<R>} - The response from the endpoint.
192
- * @throws
193
- * @async
194
- */
195
- export async function fire<
196
- M extends TESIEntryMethod,
197
- EP extends keyof TESIResponseOKMap[M],
198
- Opt extends IdentifyParameters<TESIResponseOKMap[M][EP], ESIRequestOptions>,
199
- R extends InferESIResponseResult<M, EP>
200
- >(
201
- mthd: M, endp: EP, pathParams?: number | number[] | Opt,
202
- opt: Opt = {} as Opt
203
- ): Promise<R> {
204
-
205
- if (typeof pathParams === "number") {
206
- pathParams = /** @type {number[]} */([pathParams]);
207
- }
208
- if (isArray(pathParams)) {
209
- // @ts-ignore actualy endp is string
210
- endp = replaceCbt(endp as string, pathParams) as EP;
211
- }
212
- // When only options are provided
213
- // @ts- ignore
214
- opt = /** @type {Opt} */(pathParams) as Opt || opt || /** @type {Opt} */({}) as Opt;
215
-
216
- /** @type {RequestInit} */
217
- const rqopt: RequestInit = {
218
- method: mthd,
219
- mode: "cors",
220
- cache: "no-cache",
221
- // @ts-ignore
222
- signal: opt.cancelable?.signal,
223
- headers: {}
224
- };
225
- const qss: Record<string, string> = {
226
- language: "en",
227
- };
228
-
229
- if (opt.queries) {
230
- // Object.assign(queries, options.queries); Object.assign is too slow
231
- const oqs = opt.queries;
232
- for (const k of Object.keys(oqs)) {
233
- qss[k] = oqs[k] as string;
234
- }
235
- }
236
- // DEVNOTE: when datasource is not empty string. (e.g - "singularity"
237
- // in this case must specify datasource.
238
- // disabled since `REMOVING DATASOURCE SINGULARITY`
239
- // if (opt.datasource === "singularity") {
240
- // opt.datasource = "tranquility";
241
- // }
242
- if (opt.auth) {
243
- // @ts-ignore The header is indeed an object
244
- (rqopt.headers as any).authorization = `Bearer ${opt.token}`;
245
- }
246
- if (opt.body) { // means "POST" method etc
247
- // @ts-ignore The header is indeed an object
248
- (rqopt.headers as any)["content-type"] = "application/json";
249
- rqopt.body = JSON.stringify(opt.body);
250
- }
251
-
252
- // @ts-ignore actualy endp is string
253
- const endpointUrl = curl(endp);
254
- ax++;
255
- try {
256
- // @ts-ignore A silly type error will appear, but ignore it.
257
- const res = await fetch(
258
- `${endpointUrl}?${new URLSearchParams(qss) + ""}`, rqopt
259
- ).finally(() => {
260
- ax--;
261
- });
262
-
263
- const stat = res.status;
264
- if (!res.ok && !opt.ignoreError) {
265
- if (stat === 420) {
266
- opt.cancelable && opt.cancelable.abort();
267
- throw new ESIErrorLimitReachedError();
268
- } else {
269
- // console.log(res);
270
- throw new ESIRequesError(`${res.statusText} (status=${stat})`);
271
- }
272
- } else {
273
- // DEVNOTE: - 204 No Content
274
- if (stat === 204) {
275
- // this result is empty, decided to return status code.
276
- return /** @type {R} */({ status: stat }) as unknown as R;
277
- }
278
-
279
- /** @type {R} */
280
- const data: R = await res.json();
281
- if (opt.ignoreError) {
282
- // meaning `forceJson`?
283
- return data;
284
- }
285
- // - - - - x-pages response.
286
- // +undefined is NaN
287
- // @ts-ignore becouse +null is 0
288
- const pc = +res.headers.get("x-pages")!;
289
- // has remaining pages? NaN > 1 === false !isNaN(pageCount)
290
- if (pc > 1) {
291
- LOG && log('found "x-pages" header, pages: %d', pc);
292
- const remData = await fetchP<R>(endpointUrl, rqopt, qss, pc);
293
- // finally, decide product data.
294
- if (isArray(data) && isArray(remData)) {
295
- // DEVNOTE: 2019/7/23 15:01:48 - types
296
- return /** @type {R} */(data.concat(remData)) as unknown as R;
297
- } else {
298
- // @ts-ignore TODO: fix type
299
- remData && Object.assign(data, remData);
300
- }
301
- }
302
-
303
- return data;
304
- }
305
-
306
- } catch (e) {
307
- // @ts-ignore actualy endp is string
308
- throw new ESIRequesError(`message: ${(e as Error).message}, endpoint=${endp}`);
309
- }
310
- }
311
-
312
- // type following and run
313
- // node v2.mjs
314
- // or yarn test:v2
315
- getEVEStatus().then(eveStatus => console.log(eveStatus));
316
- // {
317
- // "players": 16503,
318
- // "server_version": "2794925",
319
- // "start_time": "2025-01-21T11:02:34Z"
320
- // }