eve-esi-types 2.2.0 → 2.2.1
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/minimal-rq.d.mts +26 -0
- package/minimal-rq.mjs +78 -0
- package/package.json +7 -4
- package/rq-util.d.mts +33 -3
- package/rq-util.mjs +158 -3
- package/tsconfig.json +3 -2
- package/v2/index.d.ts +25 -1
- package/v2.mjs +26 -88
package/minimal-rq.d.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
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
|
+
import * as util from "./rq-util.mjs";
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import("./v2").TESIResponseOKMap} TESIResponseOKMap
|
|
11
|
+
* @typedef {import("./rq-util.mjs").ESIRequestOptions} ESIRequestOptions
|
|
12
|
+
*/
|
|
13
|
+
/** #### Sample of `TESIRequestFunctionSignature`
|
|
14
|
+
*
|
|
15
|
+
* + This is a minimal implementation using `TESIRequestFunctionSignature`.
|
|
16
|
+
* If the response contains "page", only the first page can be retrieved.
|
|
17
|
+
*
|
|
18
|
+
* @type {TESIRequestFunctionSignature<ESIRequestOptions>}
|
|
19
|
+
* @param method - The HTTP method to use for the request
|
|
20
|
+
* @param endpoint - The Path of the ESI endpoint to send the request to
|
|
21
|
+
* @param pathParams - An object of parameters to include in the request
|
|
22
|
+
* @param options - An object of options to include in the request
|
|
23
|
+
* @returns A Promise object containing the response data
|
|
24
|
+
* @throws {ESIRequesError}
|
|
25
|
+
*/
|
|
26
|
+
export declare const request: TESIRequestFunctionSignature<util.ESIRequestOptions>;
|
package/minimal-rq.mjs
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
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
|
+
/// <reference types="./v2"/>
|
|
9
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
10
|
+
// imports
|
|
11
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
12
|
+
import * as util from "./rq-util.mjs";
|
|
13
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
14
|
+
// constants, types
|
|
15
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
16
|
+
// shorthands
|
|
17
|
+
const log = console.log;
|
|
18
|
+
const DEBUG = util.isDebug();
|
|
19
|
+
/**
|
|
20
|
+
* @typedef {import("./v2").TESIResponseOKMap} TESIResponseOKMap
|
|
21
|
+
* @typedef {import("./rq-util.mjs").ESIRequestOptions} ESIRequestOptions
|
|
22
|
+
*/
|
|
23
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
24
|
+
// main functions
|
|
25
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
26
|
+
// node scripts/minimal-rq.mjs
|
|
27
|
+
/** #### Sample of `TESIRequestFunctionSignature`
|
|
28
|
+
*
|
|
29
|
+
* + This is a minimal implementation using `TESIRequestFunctionSignature`.
|
|
30
|
+
* If the response contains "page", only the first page can be retrieved.
|
|
31
|
+
*
|
|
32
|
+
* @type {TESIRequestFunctionSignature<ESIRequestOptions>}
|
|
33
|
+
* @param method - The HTTP method to use for the request
|
|
34
|
+
* @param endpoint - The Path of the ESI endpoint to send the request to
|
|
35
|
+
* @param pathParams - An object of parameters to include in the request
|
|
36
|
+
* @param options - An object of options to include in the request
|
|
37
|
+
* @returns A Promise object containing the response data
|
|
38
|
+
* @throws {ESIRequesError}
|
|
39
|
+
*/
|
|
40
|
+
export const request = (method, endpoint, pathParams, opt) => {
|
|
41
|
+
if (typeof pathParams === "number") {
|
|
42
|
+
// @ts-ignore
|
|
43
|
+
pathParams = [pathParams];
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(pathParams)) {
|
|
46
|
+
// @ts-ignore actualy endp is string
|
|
47
|
+
endpoint = util.replaceCbt(endpoint, pathParams);
|
|
48
|
+
}
|
|
49
|
+
// When only options are provided
|
|
50
|
+
// @ts-ignore
|
|
51
|
+
const actualOpt = /** @type {ESIRequestOptions} */ (opt || pathParams || {});
|
|
52
|
+
const { rqopt, qss } = util.initOptions(method, actualOpt);
|
|
53
|
+
// @ts-ignore actualy endp is string
|
|
54
|
+
const endpointUrl = util.curl(endpoint);
|
|
55
|
+
const url = `${endpointUrl}?${new URLSearchParams(qss) + ""}`;
|
|
56
|
+
DEBUG && log(url);
|
|
57
|
+
return fetch(url, rqopt).then(res => res.json()).catch(reason => {
|
|
58
|
+
throw new util.ESIRequesError(reason.message ? reason.message : reason);
|
|
59
|
+
});
|
|
60
|
+
};
|
|
61
|
+
// It should complete correctly.
|
|
62
|
+
/**
|
|
63
|
+
* @param {TESIRequestFunctionSignature<ESIRequestOptions>} fn
|
|
64
|
+
*/
|
|
65
|
+
async function getEVEStatus(fn) {
|
|
66
|
+
const sdeVersion = await util.getSDEVersion();
|
|
67
|
+
log(`sdeVersion: ${sdeVersion}`.blue);
|
|
68
|
+
await util.fireRequestsDoesNotRequireAuth(fn);
|
|
69
|
+
return fn("get", "/status/");
|
|
70
|
+
}
|
|
71
|
+
// type following and run
|
|
72
|
+
// node minimal-rq.mjs
|
|
73
|
+
getEVEStatus(request).then(eveStatus => log(eveStatus));
|
|
74
|
+
// {
|
|
75
|
+
// "players": 16503,
|
|
76
|
+
// "server_version": "2794925",
|
|
77
|
+
// "start_time": "2025-01-21T11:02:34Z"
|
|
78
|
+
// }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eve-esi-types",
|
|
3
|
-
"version": "2.2.
|
|
3
|
+
"version": "2.2.1",
|
|
4
4
|
"description": "Extracted the main type of ESI. use for ESI request response types (version 2 only)",
|
|
5
5
|
"main": "v2/index.d.ts",
|
|
6
6
|
"scripts": {
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
},
|
|
13
13
|
"files": [
|
|
14
14
|
"v2",
|
|
15
|
+
"*.d.mts",
|
|
15
16
|
"v2.mjs",
|
|
16
|
-
"v2.d.mts",
|
|
17
17
|
"rq-util.mjs",
|
|
18
|
-
"rq
|
|
18
|
+
"minimal-rq.mjs",
|
|
19
19
|
"LICENSE",
|
|
20
20
|
"*.md",
|
|
21
21
|
"package.json",
|
|
@@ -35,5 +35,8 @@
|
|
|
35
35
|
"bugs": {
|
|
36
36
|
"url": "https://github.com/jeffy-g/eve-esi-types/issues"
|
|
37
37
|
},
|
|
38
|
-
"homepage": "https://github.com/jeffy-g/eve-esi-types#readme"
|
|
38
|
+
"homepage": "https://github.com/jeffy-g/eve-esi-types#readme",
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"colors": "^1.4.0"
|
|
41
|
+
}
|
|
39
42
|
}
|
package/rq-util.d.mts
CHANGED
|
@@ -5,9 +5,7 @@
|
|
|
5
5
|
// https://opensource.org/licenses/mit-license.php
|
|
6
6
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
* @file rq-util.d.mts
|
|
10
|
-
*/
|
|
8
|
+
import "colors";
|
|
11
9
|
/**
|
|
12
10
|
* this always `https://esi.evetech.net`
|
|
13
11
|
*/
|
|
@@ -38,6 +36,13 @@ export type ESIRequestOptions = {
|
|
|
38
36
|
* Can be an empty object if no authentication is required.description
|
|
39
37
|
*/
|
|
40
38
|
token?: TAcccessToken;
|
|
39
|
+
/**
|
|
40
|
+
* whether an authorization header is required
|
|
41
|
+
*
|
|
42
|
+
* + When using the `Web Fetch API`, avoid extra `OPTIONS` requests and reduce extra http requests
|
|
43
|
+
*
|
|
44
|
+
* @date 2020/1/23
|
|
45
|
+
*/
|
|
41
46
|
auth?: true;
|
|
42
47
|
};
|
|
43
48
|
/**
|
|
@@ -52,6 +57,19 @@ export declare class ESIErrorLimitReachedError extends ESIRequesError {
|
|
|
52
57
|
constructor();
|
|
53
58
|
valueOf(): number;
|
|
54
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* @typedef {import("./rq-util.mjs").ESIRequestOptions} ESIRequestOptions
|
|
62
|
+
*/
|
|
63
|
+
export declare const isDebug: () => boolean;
|
|
64
|
+
/**
|
|
65
|
+
* @param method
|
|
66
|
+
* @param opt
|
|
67
|
+
* @returns
|
|
68
|
+
*/
|
|
69
|
+
export declare const initOptions: (method: string, opt: ESIRequestOptions) => {
|
|
70
|
+
rqopt: RequestInit;
|
|
71
|
+
qss: Record<string, string>;
|
|
72
|
+
};
|
|
55
73
|
/**
|
|
56
74
|
* fetch the extra pages
|
|
57
75
|
*
|
|
@@ -82,3 +100,15 @@ export declare const replaceCbt: (endpoint: string, ids: number[]) => string;
|
|
|
82
100
|
* + The version parameter can be omitted by using `<version>/<endpoint>`
|
|
83
101
|
*/
|
|
84
102
|
export declare const curl: (endp: string) => string;
|
|
103
|
+
/**
|
|
104
|
+
* @date 2020/03/31
|
|
105
|
+
* @version 2.0 fix version date string problem (v1.0
|
|
106
|
+
* @type {() => Promise<string>}
|
|
107
|
+
*/
|
|
108
|
+
export declare function getSDEVersion(): Promise<string>;
|
|
109
|
+
/**
|
|
110
|
+
* #### Fire a request that does not require authentication.
|
|
111
|
+
*
|
|
112
|
+
* @param {TESIRequestFunctionSignature<ESIRequestOptions>} fn
|
|
113
|
+
*/
|
|
114
|
+
export declare function fireRequestsDoesNotRequireAuth(fn: TESIRequestFunctionSignature<ESIRequestOptions>): Promise<void>;
|
package/rq-util.mjs
CHANGED
|
@@ -5,9 +5,10 @@
|
|
|
5
5
|
// https://opensource.org/licenses/mit-license.php
|
|
6
6
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
8
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
9
|
+
// imports
|
|
10
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
11
|
+
import "colors";
|
|
11
12
|
// - - - - - - - - - - - - - - - - - - - -
|
|
12
13
|
// constants, types
|
|
13
14
|
// - - - - - - - - - - - - - - - - - - - -
|
|
@@ -38,6 +39,49 @@ export class ESIErrorLimitReachedError extends ESIRequesError {
|
|
|
38
39
|
return 420;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* @typedef {import("./rq-util.mjs").ESIRequestOptions} ESIRequestOptions
|
|
44
|
+
*/
|
|
45
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
46
|
+
// utility functions
|
|
47
|
+
// - - - - - - - - - - - - - - - - - - - -
|
|
48
|
+
export const isDebug = () => {
|
|
49
|
+
return process.argv.includes("-debug");
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* @param method
|
|
53
|
+
* @param opt
|
|
54
|
+
* @returns
|
|
55
|
+
*/
|
|
56
|
+
export const initOptions = (method, opt) => {
|
|
57
|
+
/** @type {RequestInit} */
|
|
58
|
+
const rqopt = {
|
|
59
|
+
method,
|
|
60
|
+
mode: "cors",
|
|
61
|
+
cache: "no-cache",
|
|
62
|
+
// @ts-ignore
|
|
63
|
+
signal: opt.cancelable?.signal,
|
|
64
|
+
headers: {}
|
|
65
|
+
};
|
|
66
|
+
const qss = {
|
|
67
|
+
language: "en",
|
|
68
|
+
};
|
|
69
|
+
if (opt.query) {
|
|
70
|
+
// Object.assign(query, options.query); Object.assign is too slow
|
|
71
|
+
const oqs = opt.query;
|
|
72
|
+
Object.keys(oqs).forEach(k => qss[k] = oqs[k]);
|
|
73
|
+
}
|
|
74
|
+
if (opt.auth) {
|
|
75
|
+
// @ts-ignore The header is indeed an object
|
|
76
|
+
rqopt.headers.authorization = `Bearer ${opt.token}`;
|
|
77
|
+
}
|
|
78
|
+
if (opt.body) { // means "POST" method etc
|
|
79
|
+
// @ts-ignore The header is indeed an object
|
|
80
|
+
rqopt.headers["content-type"] = "application/json";
|
|
81
|
+
rqopt.body = JSON.stringify(opt.body);
|
|
82
|
+
}
|
|
83
|
+
return { rqopt, qss };
|
|
84
|
+
};
|
|
41
85
|
/**
|
|
42
86
|
* fetch the extra pages
|
|
43
87
|
*
|
|
@@ -105,3 +149,114 @@ export const curl = (endp) => {
|
|
|
105
149
|
endp = endp.replace(/^\/+|\/+$/g, "");
|
|
106
150
|
return `${BASE}/latest/${endp}/`;
|
|
107
151
|
};
|
|
152
|
+
/**
|
|
153
|
+
* @date 2020/03/31
|
|
154
|
+
* @version 2.0 fix version date string problem (v1.0
|
|
155
|
+
* @type {() => Promise<string>}
|
|
156
|
+
*/
|
|
157
|
+
export async function getSDEVersion() {
|
|
158
|
+
const sdeZipUrl = "https://eve-static-data-export.s3-eu-west-1.amazonaws.com/tranquility/sde.zip";
|
|
159
|
+
const date = await fetch(sdeZipUrl, { method: "head", mode: "cors" }).then((/** @type {Response} */ res) => res.headers.get("last-modified")).catch(reason => {
|
|
160
|
+
console.log(reason);
|
|
161
|
+
return new Date();
|
|
162
|
+
});
|
|
163
|
+
if (date) {
|
|
164
|
+
const YMD = new Date(date).toLocaleString(void 0, {
|
|
165
|
+
year: "numeric",
|
|
166
|
+
month: "2-digit",
|
|
167
|
+
day: "2-digit",
|
|
168
|
+
// DEVNOTE: 191215 - "-" character appeared in node v13.3.0 (maybe
|
|
169
|
+
}).replace(/(-|\/|:| )/g, (match, $1) => {
|
|
170
|
+
switch ($1) {
|
|
171
|
+
case "-":
|
|
172
|
+
case "/":
|
|
173
|
+
case ":": return "";
|
|
174
|
+
case " ": return "@";
|
|
175
|
+
}
|
|
176
|
+
return match;
|
|
177
|
+
});
|
|
178
|
+
return `sde-${YMD}-TRANQUILITY`;
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
return "sde-202Xxxxx-TRANQUILITY";
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
// It should complete correctly.
|
|
185
|
+
/**
|
|
186
|
+
* #### Fire a request that does not require authentication.
|
|
187
|
+
*
|
|
188
|
+
* @param {TESIRequestFunctionSignature<ESIRequestOptions>} fn
|
|
189
|
+
*/
|
|
190
|
+
export async function fireRequestsDoesNotRequireAuth(fn) {
|
|
191
|
+
const clog = console.log.bind(console, '- - -> Get the character data of "CCP Zoetrope"'.magenta);
|
|
192
|
+
const rlog = console.log.bind(console, '- - -> Run ESI request'.cyan);
|
|
193
|
+
try {
|
|
194
|
+
// - - - - - - - - - - - -
|
|
195
|
+
// Character
|
|
196
|
+
// - - - - - - - - - - - -
|
|
197
|
+
// Here, I borrow data from "CCP Zoetrope".
|
|
198
|
+
clog();
|
|
199
|
+
await fn("get", "/characters/{character_id}/", 2112625428).then(log);
|
|
200
|
+
clog('(portrait)');
|
|
201
|
+
await fn("get", "/characters/{character_id}/portrait/", 2112625428).then(log);
|
|
202
|
+
clog('(affiliation)');
|
|
203
|
+
const affiliation = await fn("post", "/characters/affiliation/", { body: [2112625428] });
|
|
204
|
+
log(affiliation);
|
|
205
|
+
clog('(corporation)');
|
|
206
|
+
await fn("get", "/corporations/{corporation_id}/", affiliation[0].corporation_id).then(log);
|
|
207
|
+
rlog("get:/incursions/".green);
|
|
208
|
+
await fn("get", "/incursions/").then(log);
|
|
209
|
+
// - - - - - - - - - - - -
|
|
210
|
+
// Miscellaneous
|
|
211
|
+
// - - - - - - - - - - - -
|
|
212
|
+
rlog("post:/universe/ids/".green);
|
|
213
|
+
const ids = await fn("post", "/universe/ids/", { body: ["the forge", "plex"] });
|
|
214
|
+
log(ids);
|
|
215
|
+
rlog(`get:/markets/${ids?.regions?.[0].id}/orders/?type_id=${ids?.inventory_types?.[0].id}, item PLEX`.green);
|
|
216
|
+
const orders = await fn("get", "/markets/{region_id}/orders/", ids?.regions?.[0].id, {
|
|
217
|
+
query: {
|
|
218
|
+
// page: 1,
|
|
219
|
+
order_type: "sell",
|
|
220
|
+
type_id: ids?.inventory_types?.[0].id
|
|
221
|
+
}
|
|
222
|
+
});
|
|
223
|
+
log(orders.sort((a, b) => a.price - b.price).slice(0, 5));
|
|
224
|
+
rlog("get:/universe/structures/?filter=market".green);
|
|
225
|
+
// query patameter `filter` is optional
|
|
226
|
+
const structures = await fn("get", "/universe/structures/", {
|
|
227
|
+
query: {
|
|
228
|
+
filter: "market"
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
log(`/universe/structures/[0]=${structures[0]}, length=${structures.length}`);
|
|
232
|
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
233
|
+
// The following is code to observe the behavior of completion by generics.
|
|
234
|
+
// Authentication is required, so an error will occur.
|
|
235
|
+
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
236
|
+
let ok = await fn("get", "/characters/{character_id}/ship/", 994562, {
|
|
237
|
+
auth: true,
|
|
238
|
+
ignoreError: true,
|
|
239
|
+
token: "token.token.token"
|
|
240
|
+
});
|
|
241
|
+
// in this case, "categories" and "search" is required
|
|
242
|
+
await fn("get", "/characters/{character_id}/search/", 994562, {
|
|
243
|
+
query: {
|
|
244
|
+
categories: ["agent"],
|
|
245
|
+
search: "ok"
|
|
246
|
+
},
|
|
247
|
+
auth: true
|
|
248
|
+
});
|
|
249
|
+
// in this case, "order_type" is required
|
|
250
|
+
await fn("get", "/markets/{region_id}/orders/", 994562, {
|
|
251
|
+
query: {
|
|
252
|
+
order_type: "all"
|
|
253
|
+
},
|
|
254
|
+
});
|
|
255
|
+
// TODO: want TypeScript semantics to throw an error because there is a required query parameter, but it's not possible
|
|
256
|
+
await fn("get", "/characters/{character_id}/search/");
|
|
257
|
+
log(ok);
|
|
258
|
+
}
|
|
259
|
+
catch (e) {
|
|
260
|
+
console.error("Failed to request -", e);
|
|
261
|
+
}
|
|
262
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
"skipDefaultLibCheck": true,
|
|
5
5
|
"skipLibCheck": true,
|
|
6
6
|
"declaration": true,
|
|
7
|
+
// "declarationDir": "./dts",
|
|
7
8
|
"outDir": ".",
|
|
8
9
|
"target": "esnext",
|
|
9
10
|
"module": "esnext",
|
|
@@ -13,11 +14,11 @@
|
|
|
13
14
|
"strict": true,
|
|
14
15
|
"moduleResolution": "node",
|
|
15
16
|
"rootDirs": [
|
|
16
|
-
"./"
|
|
17
|
+
"./scripts"
|
|
17
18
|
]
|
|
18
19
|
},
|
|
19
20
|
"include": [
|
|
20
|
-
"
|
|
21
|
+
"./scripts/*.mts"
|
|
21
22
|
],
|
|
22
23
|
"exclude": []
|
|
23
24
|
}
|
package/v2/index.d.ts
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* THIS TSD IS AUTO GENERATED, DO NOT EDIT
|
|
10
10
|
*
|
|
11
11
|
* @file eve-esi-types/v2/index.d.ts
|
|
12
|
-
* @summary This file is auto-generated and defines version 2.2.
|
|
12
|
+
* @summary This file is auto-generated and defines version 2.2.1 of the EVE Online ESI response types.
|
|
13
13
|
*/
|
|
14
14
|
import "./get_alliances_ok.d.ts";
|
|
15
15
|
import "./get_alliances_alliance_id_ok.d.ts";
|
|
@@ -205,6 +205,30 @@ type RequireThese<T, K extends keyof T> = T & Required<Pick<T, K>>;
|
|
|
205
205
|
|
|
206
206
|
declare global {
|
|
207
207
|
|
|
208
|
+
/**
|
|
209
|
+
* ### ESI request function all in one signature
|
|
210
|
+
*
|
|
211
|
+
* TESIRequestFunctionSignature is a type that defines the signature of an ESI request function.
|
|
212
|
+
*
|
|
213
|
+
* This function sends a request to a specified endpoint and returns a response.
|
|
214
|
+
*
|
|
215
|
+
* @template ActualOpt - The actual type of the option.
|
|
216
|
+
* Required parameters inferred by typescript are merged.
|
|
217
|
+
* @template M - The HTTP method to use for the request
|
|
218
|
+
* @template EP - The Path of the ESI endpoint to send the request to
|
|
219
|
+
* @template P2 - Parameters to include in the request
|
|
220
|
+
* @template Opt - Options to include in the request
|
|
221
|
+
* If there is a required parameter, its type will be merged with `ActualOpt`
|
|
222
|
+
* @template R - The response type
|
|
223
|
+
*/
|
|
224
|
+
type TESIRequestFunctionSignature<ActualOpt> = <
|
|
225
|
+
M extends TESIEntryMethod,
|
|
226
|
+
EP extends keyof TESIResponseOKMap[M],
|
|
227
|
+
P2 extends IsParameterizedPath<EP, number | number[], Opt>,
|
|
228
|
+
Opt extends IdentifyParameters<TESIResponseOKMap[M][EP], ActualOpt>,
|
|
229
|
+
R extends InferESIResponseResult<M, EP>
|
|
230
|
+
>(method: M, endpoint: EP, pathParams?: P2, options?: Opt) => Promise<R>;
|
|
231
|
+
|
|
208
232
|
/**
|
|
209
233
|
* is parameterized path
|
|
210
234
|
*/
|
package/v2.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// import type { TESIResponseOKMap } from "eve-esi-types";
|
|
2
|
-
import { curl, replaceCbt,
|
|
2
|
+
import { curl, fetchP, replaceCbt, getSDEVersion, ESIRequesError, initOptions, isDebug, ESIErrorLimitReachedError, fireRequestsDoesNotRequireAuth } from "./rq-util.mjs";
|
|
3
3
|
// - - - - - - - - - - - - - - - - - - - -
|
|
4
4
|
// constants, types
|
|
5
5
|
// - - - - - - - - - - - - - - - - - - - -
|
|
@@ -9,19 +9,10 @@ const isArray = Array.isArray;
|
|
|
9
9
|
/**
|
|
10
10
|
* enable/disable console.log
|
|
11
11
|
*/
|
|
12
|
-
let LOG =
|
|
12
|
+
let LOG = isDebug();
|
|
13
13
|
/**
|
|
14
14
|
* @typedef {import("./v2").TESIResponseOKMap} TESIResponseOKMap
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* @typedef {`${string}.${string}.${string}`} TAcccessToken __{Header}.{Payload}.{Signature}__
|
|
18
|
-
* @typedef ESIRequestOptions
|
|
19
|
-
* @prop {Record<string, any>} [query] query params for ESI request.
|
|
20
|
-
* @prop {any} [body] will need it for `POST` request etc.
|
|
21
|
-
* @prop {true=} [auth] Can be an empty object if no authentication is required.description
|
|
22
|
-
* @prop {TAcccessToken} [token] Can be an empty object if no authentication is required.description
|
|
23
|
-
* @prop {boolean} [ignoreError] if want response data with ignore error then can be set to `true`.
|
|
24
|
-
* @prop {AbortController} [cancelable] cancel request immediately
|
|
15
|
+
* @typedef {import("./rq-util.mjs").ESIRequestOptions} ESIRequestOptions
|
|
25
16
|
*/
|
|
26
17
|
// - - - - - - - - - - - - - - - - - - - -
|
|
27
18
|
// module vars, functions
|
|
@@ -34,39 +25,6 @@ const incrementAx = (minus) => minus ? ax-- : ax++;
|
|
|
34
25
|
// - - - - - - - - - - - - - - - - - - - -
|
|
35
26
|
// main functions
|
|
36
27
|
// - - - - - - - - - - - - - - - - - - - -
|
|
37
|
-
// It should complete correctly.
|
|
38
|
-
async function getEVEStatus() {
|
|
39
|
-
try {
|
|
40
|
-
const ok = await fire("get", "/characters/{character_id}/ship/", 994562, { auth: true });
|
|
41
|
-
// query patameter `filter` is optional
|
|
42
|
-
await fire("get", "/universe/structures/", {
|
|
43
|
-
query: {
|
|
44
|
-
// filter: "market"
|
|
45
|
-
}
|
|
46
|
-
});
|
|
47
|
-
// in this case, "categories" and "search" is required
|
|
48
|
-
await fire("get", "/characters/{character_id}/search/", 994562, {
|
|
49
|
-
query: {
|
|
50
|
-
categories: ["agent"],
|
|
51
|
-
search: "ok"
|
|
52
|
-
},
|
|
53
|
-
auth: true
|
|
54
|
-
});
|
|
55
|
-
// in this case, "order_type" is required
|
|
56
|
-
await fire("get", "/markets/{region_id}/orders/", 994562, {
|
|
57
|
-
query: {
|
|
58
|
-
order_type: "all"
|
|
59
|
-
},
|
|
60
|
-
});
|
|
61
|
-
// TODO: want TypeScript semantics to throw an error because there is a required query parameter, but it's not possible
|
|
62
|
-
await fire("get", "/characters/{character_id}/search/");
|
|
63
|
-
console.log(ok);
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
console.error("Failed to get character ship -", error);
|
|
67
|
-
}
|
|
68
|
-
return fire("get", "/status/");
|
|
69
|
-
}
|
|
70
28
|
/**
|
|
71
29
|
* fire ESI request
|
|
72
30
|
* @template {TESIEntryMethod} M
|
|
@@ -95,63 +53,32 @@ export async function fire(mthd, endp, pathParams, opt) {
|
|
|
95
53
|
// When only options are provided
|
|
96
54
|
/** @type {Opt} */
|
|
97
55
|
// @ts-ignore
|
|
98
|
-
const actualOpt =
|
|
99
|
-
|
|
100
|
-
const rqopt = {
|
|
101
|
-
method: mthd,
|
|
102
|
-
mode: "cors",
|
|
103
|
-
cache: "no-cache",
|
|
104
|
-
// @ts-ignore
|
|
105
|
-
signal: actualOpt.cancelable?.signal,
|
|
106
|
-
headers: {}
|
|
107
|
-
};
|
|
108
|
-
const qss = {
|
|
109
|
-
language: "en",
|
|
110
|
-
};
|
|
111
|
-
if (actualOpt.query) {
|
|
112
|
-
// Object.assign(queries, options.queries); Object.assign is too slow
|
|
113
|
-
const oqs = actualOpt.query;
|
|
114
|
-
for (const k of Object.keys(oqs)) {
|
|
115
|
-
qss[k] = oqs[k];
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
// DEVNOTE: when datasource is not empty string. (e.g - "singularity"
|
|
119
|
-
// in this case must specify datasource.
|
|
120
|
-
// disabled since `REMOVING DATASOURCE SINGULARITY`
|
|
121
|
-
// if (actualOpt.datasource === "singularity") {
|
|
122
|
-
// actualOpt.datasource = "tranquility";
|
|
123
|
-
// }
|
|
124
|
-
if (actualOpt.auth) {
|
|
125
|
-
// @ts-ignore The header is indeed an object
|
|
126
|
-
rqopt.headers.authorization = `Bearer ${actualOpt.token}`;
|
|
127
|
-
}
|
|
128
|
-
if (actualOpt.body) { // means "POST" method etc
|
|
129
|
-
// @ts-ignore The header is indeed an object
|
|
130
|
-
rqopt.headers["content-type"] = "application/json";
|
|
131
|
-
rqopt.body = JSON.stringify(actualOpt.body);
|
|
132
|
-
}
|
|
56
|
+
const actualOpt = opt || pathParams || {};
|
|
57
|
+
const { rqopt, qss } = initOptions(mthd, actualOpt);
|
|
133
58
|
// @ts-ignore actualy endp is string
|
|
134
59
|
const endpointUrl = curl(endp);
|
|
60
|
+
const url = `${endpointUrl}?${new URLSearchParams(qss) + ""}`;
|
|
61
|
+
LOG && log(url);
|
|
135
62
|
ax++;
|
|
136
63
|
try {
|
|
137
64
|
// @ts-ignore A silly type error will appear, but ignore it.
|
|
138
|
-
const res = await fetch(
|
|
139
|
-
const
|
|
65
|
+
const res = await fetch(url, rqopt).finally(() => ax--);
|
|
66
|
+
const { status } = res;
|
|
140
67
|
if (!res.ok && !actualOpt.ignoreError) {
|
|
141
|
-
if (
|
|
68
|
+
if (status === 420) {
|
|
142
69
|
actualOpt.cancelable && actualOpt.cancelable.abort();
|
|
143
70
|
throw new ESIErrorLimitReachedError();
|
|
144
71
|
}
|
|
145
72
|
else {
|
|
146
73
|
// console.log(res);
|
|
147
|
-
throw new ESIRequesError(`${res.statusText} (status=${
|
|
74
|
+
throw new ESIRequesError(`${res.statusText} (status=${status})`);
|
|
148
75
|
}
|
|
149
76
|
}
|
|
150
77
|
else {
|
|
151
78
|
// DEVNOTE: - 204 No Content
|
|
152
|
-
if (
|
|
79
|
+
if (status === 204) {
|
|
153
80
|
// this result is empty, decided to return status code.
|
|
154
|
-
return /** @type {R} */ ({ status
|
|
81
|
+
return /** @type {R} */ ({ status });
|
|
155
82
|
}
|
|
156
83
|
/** @type {R} */
|
|
157
84
|
const data = await res.json();
|
|
@@ -185,10 +112,21 @@ export async function fire(mthd, endp, pathParams, opt) {
|
|
|
185
112
|
throw new ESIRequesError(`message: ${e.message}, endpoint=${endp}`);
|
|
186
113
|
}
|
|
187
114
|
}
|
|
115
|
+
// It should complete correctly.
|
|
116
|
+
/**
|
|
117
|
+
* @param {TESIRequestFunctionSignature<ESIRequestOptions>} fn
|
|
118
|
+
*/
|
|
119
|
+
async function getEVEStatus(fn) {
|
|
120
|
+
const sdeVersion = await getSDEVersion();
|
|
121
|
+
log(`sdeVersion: ${sdeVersion}`.blue);
|
|
122
|
+
await fireRequestsDoesNotRequireAuth(fn);
|
|
123
|
+
return fn("get", "/status/");
|
|
124
|
+
}
|
|
188
125
|
// type following and run
|
|
126
|
+
// bun scripts/v2.mts
|
|
189
127
|
// node v2.mjs
|
|
190
|
-
// or yarn test
|
|
191
|
-
getEVEStatus().then(eveStatus => console.log(eveStatus));
|
|
128
|
+
// or yarn test
|
|
129
|
+
getEVEStatus(fire).then(eveStatus => console.log(eveStatus));
|
|
192
130
|
// {
|
|
193
131
|
// "players": 16503,
|
|
194
132
|
// "server_version": "2794925",
|