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 +11 -1
- package/v2/post_universe_ids_ok.d.ts +81 -215
- package/esi-request.mts +0 -309
- package/snippet.ts +0 -49
- package/v2.mts +0 -320
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eve-esi-types",
|
|
3
|
-
"version": "2.0.
|
|
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
|
-
*
|
|
67
|
-
*/
|
|
68
|
-
interface
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
// }
|