eve-esi-types 2.3.3 → 2.3.4

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.
@@ -0,0 +1,15 @@
1
+ declare global {
2
+ interface String {
3
+ red: string;
4
+ green: string;
5
+ yellow: string;
6
+ blue: string;
7
+ magenta: string;
8
+ cyan: string;
9
+ }
10
+ }
11
+ /**
12
+ * @param {boolean} enable
13
+ */
14
+ export declare function defineColors(enable: boolean): void;
15
+ export declare function getLogger(banner: string, logSelector?: string): (...args: any[]) => void;
@@ -0,0 +1,102 @@
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
+ * @file eve-esi-types/lib/console-util.mts
10
+ */
11
+ import { isNode } from "./constants.mjs";
12
+ let colorsDefined = false;
13
+ /**
14
+ * @param {boolean} enable
15
+ */
16
+ export function defineColors(enable) {
17
+ if (isNode)
18
+ return;
19
+ if (!colorsDefined) {
20
+ colorsDefined = true;
21
+ Object.defineProperties(String.prototype, {
22
+ red: {
23
+ get() { return enable ? `<span style="color: red">${this}</span>` : this; }
24
+ },
25
+ green: {
26
+ get() { return enable ? `<span style="color: green">${this}</span>` : this; }
27
+ },
28
+ yellow: {
29
+ get() { return enable ? `<span style="color: yellow">${this}</span>` : this; }
30
+ },
31
+ blue: {
32
+ get() { return enable ? `<span style="color: blue">${this}</span>` : this; }
33
+ },
34
+ magenta: {
35
+ get() { return enable ? `<span style="color: #FF00FF">${this}</span>` : this; }
36
+ },
37
+ cyan: {
38
+ get() { return enable ? `<span style="color: #00FFFF">${this}</span>` : this; }
39
+ },
40
+ });
41
+ }
42
+ }
43
+ /**
44
+ * @param {string} jsonString
45
+ */
46
+ const jsonBeautify = (jsonString) => {
47
+ const re = /("(?:[^"\\]|\\.)*"(?:\s*:)?)|(-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)|\b(true|false)\b|\b(null)\b/gm;
48
+ return jsonString.replace(re, (m, key_or_str, num, bool, nul) => {
49
+ if (key_or_str) { // key
50
+ let clz;
51
+ const last = m.length - 1;
52
+ if (m[last] === ":") {
53
+ m = m.substring(0, last);
54
+ clz = "key";
55
+ }
56
+ else {
57
+ clz = "string";
58
+ }
59
+ let tag = `<span class="${clz}">${m}</span>`;
60
+ clz === "key" && (tag += ":");
61
+ return tag;
62
+ }
63
+ if (num) { // number
64
+ return `<span class="number">${m}</span>`;
65
+ }
66
+ if (bool) { // boolean
67
+ return `<span class="bool">${m}</span>`;
68
+ }
69
+ if (nul) { // null
70
+ return `<span class="nul">${m}</span>`;
71
+ }
72
+ return m;
73
+ });
74
+ };
75
+ export function getLogger(banner, logSelector = ".log-frame") {
76
+ /** @type {Element=} */
77
+ const logElement = isNode ? void 0 : document.querySelector(logSelector) || void 0;
78
+ defineColors(!!logElement);
79
+ if (!logElement) {
80
+ return console.log.bind(console, banner);
81
+ }
82
+ else {
83
+ /** @type {function(...any): void} */
84
+ const log = (...data) => {
85
+ let text = banner;
86
+ for (const d of data) {
87
+ if (typeof d === "object") {
88
+ const json = JSON.stringify(d, null, 2);
89
+ text += jsonBeautify(json);
90
+ }
91
+ else {
92
+ text += " " + d;
93
+ }
94
+ }
95
+ requestAnimationFrame(() => {
96
+ logElement.innerHTML += text + "\n";
97
+ logElement.scrollTop = 999999;
98
+ });
99
+ };
100
+ return log;
101
+ }
102
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Dummy import
3
+ * @import * as cc from "colors.ts";
4
+ */
5
+ /**
6
+ * will almost certainly be able to detect if you are in a nodejs environment
7
+ *
8
+ * @date 2020/5/9
9
+ */
10
+ export declare const isNode: boolean;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Dummy import
3
+ * @import * as cc from "colors.ts";
4
+ */
5
+ /**
6
+ * will almost certainly be able to detect if you are in a nodejs environment
7
+ *
8
+ * @date 2020/5/9
9
+ */
10
+ export const isNode = await (async () => {
11
+ let returnValue;
12
+ if (typeof process === "object") {
13
+ returnValue = typeof process.versions === "object" && /\d+\.\d+\.\d+/.test(process.versions.node);
14
+ if (returnValue) {
15
+ await import("colors.ts");
16
+ }
17
+ }
18
+ else {
19
+ // modId = "https://cdn.jsdelivr.net/npm/colors.ts@1.0.20/+esm";
20
+ returnValue = false;
21
+ }
22
+ return returnValue;
23
+ })();
@@ -1,3 +1,14 @@
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
+ * @file eve-esi-types/lib/esi-error-types.d.ts
10
+ * @since 2.3.2
11
+ */
1
12
 
2
13
  type TEVEErrorBase = {
3
14
  /**
@@ -34,8 +45,9 @@ export type TESIErrorStatMap = {
34
45
  * const res = await fetch("<URL with ESI endpoint>");
35
46
  * const status = res.status;
36
47
  * if (status >= 400) {
48
+ * const esiError = await res.json() as TESIErrorStatMap[typeof status];
37
49
  * const errorType: TESIErrorWithStat<typeof status> = {
38
- * status, ...res.json()
50
+ * status, ...esiError
39
51
  * };
40
52
  * console.log(errorType);
41
53
  * throw new Error(`message="${res.statusText}", status=${status}`);
@@ -43,7 +55,6 @@ export type TESIErrorStatMap = {
43
55
  * ```
44
56
  *
45
57
  * @date 2025/3/3
46
- * @since 2.4.0
47
58
  */
48
59
  export type TESIErrorWithStat<Stat extends TClientErrorStats | TServerErrorStats> = {
49
60
  status: Stat;
@@ -14,7 +14,7 @@ import * as util from "./rq-util.mjs";
14
14
  // constants, types
15
15
  // - - - - - - - - - - - - - - - - - - - -
16
16
  // shorthands
17
- const log = console.log;
17
+ const log = util.getUniversalLogger("[request-api]: ");
18
18
  const DEBUG = util.isDebug();
19
19
  /**
20
20
  * @typedef {import("../v2").IESIRequestFunction<util.ESIRequestOptions>} IESIRequestFunction
@@ -36,11 +36,9 @@ const DEBUG = util.isDebug();
36
36
  * @returns A Promise object containing the response data
37
37
  * @throws {ESIRequesError}
38
38
  */
39
- // @ts-expect-error
40
- export const request = async (method, endpoint, pathParams, opt) => {
39
+ export const request = /** @type {IESIRequestFunction} */ (async (method, endpoint, pathParams, opt) => {
41
40
  if (typeof pathParams === "number") {
42
- // @ts-expect-error
43
- pathParams = [pathParams];
41
+ pathParams = /** @type {typeof pathParams} */ ([pathParams]);
44
42
  }
45
43
  if (Array.isArray(pathParams)) {
46
44
  endpoint = util.replaceCbt(endpoint, pathParams);
@@ -65,7 +63,7 @@ export const request = async (method, endpoint, pathParams, opt) => {
65
63
  catch (e) {
66
64
  log(e);
67
65
  }
68
- };
66
+ });
69
67
  //
70
68
  // implements rest methods of `request` (IESIRequestFunction)
71
69
  //
package/lib/rq-util.d.mts CHANGED
@@ -9,18 +9,16 @@
9
9
  // - - - - - - - - - - - - - - - - - - - -
10
10
  // imports
11
11
  // - - - - - - - - - - - - - - - - - - - -
12
+ /*!
13
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
14
+ // Copyright (C) 2025 jeffy-g <hirotom1107@gmail.com>
15
+ // Released under the MIT license
16
+ // https://opensource.org/licenses/mit-license.php
17
+ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
18
+ */
12
19
  import type { TESIRequestFunctionMethods } from "../v2";
13
20
  import type { TESIErrorStats } from "./esi-error-types";
14
- /**
15
- * Dummy import
16
- * @import * as cc from "colors.ts";
17
- */
18
- /**
19
- * will almost certainly be able to detect if you are in a nodejs environment
20
- *
21
- * @date 2020/5/9
22
- */
23
- export declare const isNode: boolean;
21
+ export { isNode } from "./constants.mjs";
24
22
  /**
25
23
  * this always `https://esi.evetech.net`
26
24
  */
@@ -99,7 +97,7 @@ export declare const handleSuccessResponse: (response: Response, endpointUrl: st
99
97
  *
100
98
  * @param {Response} res
101
99
  * @param {string} endpointUrl
102
- * @param {AbortController} abortable
100
+ * @param {AbortController=} abortable
103
101
  * @returns {Promise<void>}
104
102
  */
105
103
  export declare const handleESIError: (res: Response, endpointUrl: string, abortable?: AbortController) => Promise<void>;
@@ -123,13 +121,15 @@ export declare const isDebug: () => boolean;
123
121
  */
124
122
  export declare const is: (opt: string) => boolean;
125
123
  /**
124
+ * NOTE: In `initOptions`, if `auth=true`, then `token` can be set to a valid `accessToken` to successfully complete an authenticated request.
125
+ *
126
126
  * @param {string} method
127
127
  * @param {ESIRequestOptions} opt
128
- * @returns {{ rqopt: RequestInit, qss: Record<string, string> }}
128
+ * @returns {{ rqopt: RequestInit, qss: Record<string, any> }}
129
129
  */
130
130
  export declare const initOptions: (method: string, opt: ESIRequestOptions) => {
131
131
  rqopt: RequestInit;
132
- qss: Record<string, string>;
132
+ qss: Record<string, any>;
133
133
  };
134
134
  /**
135
135
  * fetch the extra pages
@@ -138,12 +138,12 @@ export declare const initOptions: (method: string, opt: ESIRequestOptions) => {
138
138
  * @template {any} T
139
139
  * @param {string} endpointUrl
140
140
  * @param {RequestInit} rqopt request options
141
- * @param {URLSearchParams} rqp queries
141
+ * @param {URLSearchParams} usp queries
142
142
  * @param {number} pc pageCount
143
143
  * @param {(minus?: number) => void=} increment
144
144
  * @returns {Promise<T | null>}
145
145
  */
146
- export declare const fetchP: <T extends unknown>(endpointUrl: string, rqopt: RequestInit, rqp: URLSearchParams, pc: number, increment?: (minus?: Truthy) => void) => Promise<T | null>;
146
+ export declare const fetchP: <T extends unknown>(endpointUrl: string, rqopt: RequestInit, usp: URLSearchParams, pc: number, increment?: (minus?: Truthy) => void) => Promise<T | null>;
147
147
  /** ### replace (C)urly (B)races (T)oken
148
148
  *
149
149
  * @example
@@ -158,7 +158,6 @@ export declare const fetchP: <T extends unknown>(endpointUrl: string, rqopt: Req
158
158
  */
159
159
  export declare const replaceCbt: <T extends unknown>(endpoint: T, ids: number[]) => T;
160
160
  /**
161
- *
162
161
  * @template {unknown} T
163
162
  * @param {T} endp this means endpoint url fragment like `/characters/{character_id}/` or `/characters/{character_id}/agents_research/`
164
163
  * + The version parameter is forced to apply `latest`
@@ -171,6 +170,7 @@ export declare const curl: <T extends unknown>(endp: T) => string;
171
170
  * @type {() => Promise<string>}
172
171
  */
173
172
  export declare function getSDEVersion(): Promise<string>;
173
+ export declare const getUniversalLogger: (banner: string, logSelector?: string) => (...args: any[]) => void;
174
174
  export declare function getLogger(): {
175
175
  clog: (...args: any[]) => void;
176
176
  rlog: (...args: any[]) => void;
package/lib/rq-util.mjs CHANGED
@@ -9,34 +9,14 @@
9
9
  // - - - - - - - - - - - - - - - - - - - -
10
10
  // imports
11
11
  // - - - - - - - - - - - - - - - - - - - -
12
- /**
13
- * Dummy import
14
- * @import * as cc from "colors.ts";
15
- */
16
- /**
17
- * will almost certainly be able to detect if you are in a nodejs environment
18
- *
19
- * @date 2020/5/9
20
- */
21
- export const isNode = await (async () => {
22
- let modId, returnValue;
23
- if (typeof process === "object") {
24
- modId = "colors.ts";
25
- // @ts-ignore
26
- returnValue = typeof process.versions === "object" && /\d+\.\d+\.\d+/.test(process.versions.node);
27
- }
28
- else {
29
- modId = "https://cdn.jsdelivr.net/npm/colors.ts@1.0.20/+esm";
30
- returnValue = false;
31
- }
32
- await import(modId);
33
- return returnValue;
34
- })();
12
+ import { isNode } from "./constants.mjs";
13
+ export { isNode } from "./constants.mjs";
14
+ import * as consoleUtil from "./console-util.mjs";
35
15
  // - - - - - - - - - - - - - - - - - - - -
36
16
  // constants, types
37
17
  // - - - - - - - - - - - - - - - - - - - -
38
18
  // shorthands
39
- const log = console.log;
19
+ const log = consoleUtil.getLogger("[request-util]:");
40
20
  const isArray = Array.isArray;
41
21
  /**
42
22
  * enable/disable console.log
@@ -120,7 +100,7 @@ export const handleSuccessResponse = async (response, endpointUrl, requestOpt, u
120
100
  *
121
101
  * @param {Response} res
122
102
  * @param {string} endpointUrl
123
- * @param {AbortController} abortable
103
+ * @param {AbortController=} abortable
124
104
  * @returns {Promise<void>}
125
105
  */
126
106
  export const handleESIError = async (res, endpointUrl, abortable) => {
@@ -132,13 +112,12 @@ export const handleESIError = async (res, endpointUrl, abortable) => {
132
112
  status, ...esiError
133
113
  };
134
114
  // log ESI Error details
135
- console.warn(errorType);
115
+ log(errorType);
136
116
  if (status === 420) {
137
117
  abortable && abortable.abort();
138
118
  throw new ESIErrorLimitReachedError();
139
119
  }
140
120
  else {
141
- // console.log(res);
142
121
  throw new ESIRequesError(`${res.statusText} (status=${status}, url=${endpointUrl})`);
143
122
  }
144
123
  };
@@ -182,7 +161,7 @@ export const isDebug = () => {
182
161
  * @returns {boolean}
183
162
  */
184
163
  export const is = (opt) => {
185
- if (typeof process === "object") {
164
+ if (isNode) {
186
165
  return process.argv.includes(`-${opt}`);
187
166
  }
188
167
  else {
@@ -206,9 +185,11 @@ export const is = (opt) => {
206
185
  return false;
207
186
  };
208
187
  /**
188
+ * NOTE: In `initOptions`, if `auth=true`, then `token` can be set to a valid `accessToken` to successfully complete an authenticated request.
189
+ *
209
190
  * @param {string} method
210
191
  * @param {ESIRequestOptions} opt
211
- * @returns {{ rqopt: RequestInit, qss: Record<string, string> }}
192
+ * @returns {{ rqopt: RequestInit, qss: Record<string, any> }}
212
193
  */
213
194
  export const initOptions = (method, opt) => {
214
195
  /** @type {RequestInit} */
@@ -219,7 +200,7 @@ export const initOptions = (method, opt) => {
219
200
  signal: opt.cancelable?.signal,
220
201
  headers: {}
221
202
  };
222
- /** @type {Record<string, string>} */
203
+ /** @type {Record<string, any>} */
223
204
  const qss = {
224
205
  // CAVEAT: If the language parameter is not set, some endpoints such as "/universe/ids/" may return incomplete results.
225
206
  // Therefore, the language parameter should always be set.
@@ -228,7 +209,8 @@ export const initOptions = (method, opt) => {
228
209
  if (opt.query) {
229
210
  // Object.assign(query, options.query); Object.assign is too slow
230
211
  const oqs = opt.query;
231
- Object.keys(oqs).forEach(k => qss[k] = oqs[k]);
212
+ for (const key in oqs)
213
+ qss[key] = oqs[key];
232
214
  }
233
215
  if (opt.auth) {
234
216
  // @ts-ignore The header is indeed an object
@@ -248,17 +230,17 @@ export const initOptions = (method, opt) => {
248
230
  * @template {any} T
249
231
  * @param {string} endpointUrl
250
232
  * @param {RequestInit} rqopt request options
251
- * @param {URLSearchParams} rqp queries
233
+ * @param {URLSearchParams} usp queries
252
234
  * @param {number} pc pageCount
253
235
  * @param {(minus?: number) => void=} increment
254
236
  * @returns {Promise<T | null>}
255
237
  */
256
- export const fetchP = async (endpointUrl, rqopt, rqp, pc, increment = () => { }) => {
238
+ export const fetchP = async (endpointUrl, rqopt, usp, pc, increment = () => { }) => {
257
239
  const rqs = [];
258
240
  for (let i = 2; i <= pc;) {
259
- rqp.set("page", (i++) + "");
241
+ usp.set("page", (i++) + "");
260
242
  increment();
261
- rqs.push(fetch(`${endpointUrl}?${rqp + ""}`, rqopt).then(res => res.json()).catch(reason => {
243
+ rqs.push(fetch(`${endpointUrl}?${usp + ""}`, rqopt).then(res => res.json()).catch(reason => {
262
244
  console.warn(reason);
263
245
  return [];
264
246
  }).finally(() => {
@@ -296,7 +278,6 @@ export const replaceCbt = (endpoint, ids) => {
296
278
  return endpoint.replace(/{([\w]+)}/g, $0 => ids[idx++] + "");
297
279
  };
298
280
  /**
299
- *
300
281
  * @template {unknown} T
301
282
  * @param {T} endp this means endpoint url fragment like `/characters/{character_id}/` or `/characters/{character_id}/agents_research/`
302
283
  * + The version parameter is forced to apply `latest`
@@ -330,9 +311,12 @@ export async function getSDEVersion() {
330
311
  return "sde-202Xxxxx-TRANQUILITY";
331
312
  }
332
313
  }
314
+ export const getUniversalLogger = (banner, logSelector = ".log-frame") => {
315
+ return consoleUtil.getLogger(banner, logSelector);
316
+ };
333
317
  export function getLogger() {
334
- const clog = console.log.bind(console, '- - -> Get the character data of "CCP Zoetrope"'.magenta);
335
- const rlog = console.log.bind(console, "- - -> Run ESI request".cyan);
318
+ const clog = consoleUtil.getLogger('- - -> Get the character data of "CCP Zoetrope"'.magenta);
319
+ const rlog = consoleUtil.getLogger("- - -> Run ESI request".cyan);
336
320
  return { clog, rlog };
337
321
  }
338
322
  /**
@@ -364,7 +348,6 @@ function fireWithoutAuth(fn, method, endpoint, pathParams, opt) {
364
348
  }
365
349
  return fn[method](endpoint, pathParams, opt);
366
350
  }
367
- // It should complete correctly.
368
351
  /**
369
352
  * #### Fire a request that does not require authentication.
370
353
  *
@@ -373,17 +356,18 @@ function fireWithoutAuth(fn, method, endpoint, pathParams, opt) {
373
356
  */
374
357
  export async function fireRequestsDoesNotRequireAuth(fn) {
375
358
  const { clog, rlog } = getLogger();
359
+ const ID_CCP_Zoetrope = 2112625428;
376
360
  try {
377
361
  // - - - - - - - - - - - -
378
362
  // Character
379
363
  // - - - - - - - - - - - -
380
364
  // Here, I borrow data from "CCP Zoetrope".
381
365
  clog();
382
- await fireWithoutAuth(fn, "get", "/characters/{character_id}/", 2112625428).then(log);
366
+ await fireWithoutAuth(fn, "get", "/characters/{character_id}/", ID_CCP_Zoetrope).then(log);
383
367
  clog('(portrait)');
384
- await fireWithoutAuth(fn, "get", "/characters/{character_id}/portrait/", 2112625428).then(log);
368
+ await fireWithoutAuth(fn, "get", "/characters/{character_id}/portrait/", ID_CCP_Zoetrope).then(log);
385
369
  clog('(affiliation)');
386
- const affiliation = await fireWithoutAuth(fn, "post", "/characters/affiliation/", { body: [2112625428] });
370
+ const affiliation = await fireWithoutAuth(fn, "post", "/characters/affiliation/", { body: [ID_CCP_Zoetrope] });
387
371
  log(affiliation);
388
372
  clog('(corporation)');
389
373
  await fireWithoutAuth(fn, "get", "/corporations/{corporation_id}/", affiliation[0].corporation_id).then(log);
@@ -396,6 +380,7 @@ export async function fireRequestsDoesNotRequireAuth(fn) {
396
380
  const ids = await fireWithoutAuth(fn, "post", "/universe/ids/", { body: ["the forge", "plex"] });
397
381
  log(ids.inventory_types, ids.regions);
398
382
  rlog(`get:/markets/${ids?.regions?.[0].id}/orders/?type_id=${ids?.inventory_types?.[0].id}, item PLEX`.green);
383
+ // in this case, "order_type" is required
399
384
  const orders = await fireWithoutAuth(fn, "get", "/markets/{region_id}/orders/", ids?.regions?.[0].id, {
400
385
  query: {
401
386
  // page: 1,
@@ -416,29 +401,23 @@ export async function fireRequestsDoesNotRequireAuth(fn) {
416
401
  // The following is code to observe the behavior of completion by generics.
417
402
  // Authentication is required, so an error will occur.
418
403
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
419
- let ok = await fireWithoutAuth(fn, "get", "/characters/{character_id}/ship/", 994562, {
404
+ let willFailed = await fireWithoutAuth(fn, "get", "/characters/{character_id}/ship/", ID_CCP_Zoetrope, {
420
405
  auth: true,
421
406
  ignoreError: true,
422
407
  token: "token.token.token"
423
408
  });
424
409
  // in this case, "categories" and "search" is required
425
- await fireWithoutAuth(fn, "get", "/characters/{character_id}/search/", 994562, {
410
+ await fireWithoutAuth(fn, "get", "/characters/{character_id}/search/", ID_CCP_Zoetrope, {
426
411
  query: {
427
412
  categories: ["agent"],
428
413
  search: "ok"
429
414
  },
430
415
  auth: true
431
416
  });
432
- // in this case, "order_type" is required
433
- await fireWithoutAuth(fn, "get", "/markets/{region_id}/orders/", 994562, {
434
- query: {
435
- order_type: "all"
436
- },
437
- });
438
417
  // TODO: want TypeScript semantics to throw an error because there is a required query parameter, but it's not possible
439
418
  // Or rather, I don't know how to do it.
440
419
  await fireWithoutAuth(fn, "get", "/characters/{character_id}/search/");
441
- log(ok);
420
+ log(willFailed);
442
421
  }
443
422
  catch (e) {
444
423
  console.error("Failed to request -", e);
@@ -18,9 +18,9 @@ import type { ESIRequestOptions } from "./rq-util.mjs";
18
18
  * const esiRequest = taggedApi.injectESIRequestBody(...);
19
19
  * const ret = await esiRequest.universe.get("/universe/structures/", { query: { filter: "market" }});
20
20
  *
21
- * @template {Record<string, unknown>} Opt
22
- * @param {TESIRequestFunctionSignature<{}>} requestBody
23
- * @returns {XESI.TaggedESIRequestMap}
21
+ * @template {Record<string, unknown>} Opt - The options type for the request.
22
+ * @param {TESIRequestFunctionSignature<Opt>} requestBody - The function signature for the ESI request.
23
+ * @returns {XESI.TaggedESIRequestMap} - The tagged ESI request map.
24
24
  * @since 2.3
25
25
  */
26
26
  export declare function injectESIRequestBody<Opt extends Record<string, unknown>>(requestBody: TESIRequestFunctionSignature<Opt>): XESI.TaggedESIRequestMap<Opt>;
@@ -29,6 +29,7 @@ export declare function injectESIRequestBody<Opt extends Record<string, unknown>
29
29
  */
30
30
  /**
31
31
  * Injects the minimal implementation of ESI requests into `XESI.TaggedESIRequestMap`.
32
+ *
32
33
  * @since 2.3
33
34
  * @type {XESI.TaggedESIRequestMap<ESIRequestOptions>}
34
35
  */
@@ -10,11 +10,14 @@
10
10
  * @file eve-esi-types/lib/tagged-request-api.mts
11
11
  */
12
12
  import { request } from "./request-api.mjs";
13
+ /**
14
+ * @import { TESIRequestFunctionMethods } from "../v2"
15
+ */
13
16
  /**
14
17
  * @typedef {`${string}${"" | `,${string}`}`} TMethodList
15
18
  */
16
19
  /** @satisfies {`${XESI.ESITags}:${TMethodList}`[]} */
17
- const ESITagsWithMethodList = [
20
+ const ESITagMethodMapping = [
18
21
  "Alliance:get", "Assets:get,post",
19
22
  "Calendar:get,put", "Character:get,post",
20
23
  "Clones:get", "Contacts:get,post,put,delete",
@@ -43,31 +46,39 @@ const ESITagsWithMethodList = [
43
46
  * const esiRequest = taggedApi.injectESIRequestBody(...);
44
47
  * const ret = await esiRequest.universe.get("/universe/structures/", { query: { filter: "market" }});
45
48
  *
46
- * @template {Record<string, unknown>} Opt
47
- * @param {TESIRequestFunctionSignature<{}>} requestBody
48
- * @returns {XESI.TaggedESIRequestMap}
49
+ * @template {Record<string, unknown>} Opt - The options type for the request.
50
+ * @param {TESIRequestFunctionSignature<Opt>} requestBody - The function signature for the ESI request.
51
+ * @returns {XESI.TaggedESIRequestMap} - The tagged ESI request map.
49
52
  * @since 2.3
50
53
  */
51
54
  export function injectESIRequestBody(requestBody) {
52
55
  const rq = /** @type {XESI.TaggedESIRequestMap<Opt>} */ ({});
53
- for (const tagEntry of ESITagsWithMethodList) {
56
+ // DEVNOTE: 2025/03/08 - In reality, you only need one function instance for each of "get", "post", "put", and "delete",
57
+ // so you can just refer to the cached functions as a map.
58
+ const methodMap = /** @type {TESIRequestFunctionMethods<Opt>} */ ({});
59
+ /** @type {TESIEntryMethod[]} */ (["get", "post", "put", "delete"]).forEach((method) => {
60
+ methodMap[method] = /** @type {TESIRequestFunctionEachMethod<typeof method, Opt>} */ ((e, params, opt) => requestBody(method, e, params, opt));
61
+ });
62
+ for (const tagEntry of ESITagMethodMapping) {
54
63
  const [tag, methodList] = /** @type {[tag: XESI.ESITags, methods: TMethodList]} */ (tagEntry.split(":"));
55
64
  const methods = /** @type {TESIEntryMethod[]} */ (methodList.split(","));
56
65
  const entry = /** @type {XESI.ESITaggedEndpointRequest<typeof tag, Opt>} */ ({});
57
66
  for (const method of methods) {
67
+ // However, from the point of view of type annotation, the parameters are different, so you need to cast it as `as type` instead of `satisfies`.
58
68
  // @ts-expect-error
59
- entry[method] = /** @satisfies {XESI.TaggedEndpointRequestFunction<typeof method, typeof tag>} */ ((e, params, opt) => requestBody(method, e, params, opt));
69
+ entry[method] = /** @type {XESI.TaggedEndpointRequestFunction<typeof method, typeof tag, Opt>} */ (methodMap[method]);
60
70
  }
61
71
  const camelCased = /** @type {XESI.LCamelCase<XESI.ESITags>} */ (tag[0].toLowerCase() + tag.slice(1).replace(/\s(.)/g, "$1"));
62
72
  rq[camelCased] = entry;
63
73
  }
64
- return rq;
74
+ return Object.freeze(rq);
65
75
  }
66
76
  /**
67
77
  * @import { ESIRequestOptions } from "./rq-util.mjs";
68
78
  */
69
79
  /**
70
80
  * Injects the minimal implementation of ESI requests into `XESI.TaggedESIRequestMap`.
81
+ *
71
82
  * @since 2.3
72
83
  * @type {XESI.TaggedESIRequestMap<ESIRequestOptions>}
73
84
  */
package/minimal-rq.mjs CHANGED
@@ -15,7 +15,7 @@ import { request } from "./lib/request-api.mjs";
15
15
  // constants, types
16
16
  // - - - - - - - - - - - - - - - - - - - -
17
17
  // shorthands
18
- const log = console.log;
18
+ const log = util.getUniversalLogger("[request-mini]: ");
19
19
  /**
20
20
  * @typedef {import("./v2").IESIRequestFunction<util.ESIRequestOptions>} IESIRequestFunction
21
21
  * @typedef {import("./v2").TESIRequestFunctionMethods<util.ESIRequestOptions>} TESIRequestFunctionMethods
@@ -44,17 +44,18 @@ async function getEVEStatus(fn) {
44
44
  }
45
45
  const { clog, rlog } = util.getLogger();
46
46
  CaseIESIRequestFunction: {
47
+ const ID_CCP_Zoetrope = 2112625428;
47
48
  // - - - - - - - - - - - -
48
49
  // Character
49
50
  // - - - - - - - - - - - -
50
51
  // Here, I borrow data from "CCP Zoetrope".
51
52
  rlog("- - - - - - - > run as IESIRequestFunction<ESIRequestOptions>".red);
52
53
  clog();
53
- await fn.get("/characters/{character_id}/", 2112625428).then(log);
54
+ await fn.get("/characters/{character_id}/", ID_CCP_Zoetrope).then(log);
54
55
  clog('(portrait)');
55
- await fn.get("/characters/{character_id}/portrait/", 2112625428).then(log);
56
+ await fn.get("/characters/{character_id}/portrait/", ID_CCP_Zoetrope).then(log);
56
57
  clog('(affiliation)');
57
- const affiliation = await fn.post("/characters/affiliation/", { body: [2112625428] });
58
+ const affiliation = await fn.post("/characters/affiliation/", { body: [ID_CCP_Zoetrope] });
58
59
  log(affiliation);
59
60
  clog('(corporation)');
60
61
  await fn.get("/corporations/{corporation_id}/", affiliation[0].corporation_id).then(log);
@@ -78,16 +79,23 @@ async function getEVEStatus(fn) {
78
79
  }
79
80
  return fn.get("/status/");
80
81
  }
82
+ const runTest = () => {
83
+ getEVEStatus(request).then(eveStatus => log(eveStatus));
84
+ };
81
85
  // type following and run
82
86
  // node minimal-rq.mjs -debug
83
87
  if (!util.is("x")) {
84
- getEVEStatus(request).then(eveStatus => log(eveStatus));
88
+ runTest();
85
89
  }
86
90
  else {
87
91
  // @ts-ignore
88
- globalThis.runTest = () => {
89
- getEVEStatus(request).then(eveStatus => log(eveStatus));
90
- };
92
+ globalThis.runTest = runTest;
93
+ if (!util.isNode) {
94
+ const button = document.getElementById("run-test");
95
+ if (button) {
96
+ button.addEventListener("click", () => runTest());
97
+ }
98
+ }
91
99
  }
92
100
  // {
93
101
  // "players": 16503,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "eve-esi-types",
3
- "version": "2.3.3",
3
+ "version": "2.3.4",
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": {
@@ -14,8 +14,8 @@
14
14
  "files": [
15
15
  "v2",
16
16
  "lib",
17
+ "web",
17
18
  "*.d.mts",
18
- "index.html",
19
19
  "*.mjs",
20
20
  "LICENSE",
21
21
  "*.md",
package/web/index.css ADDED
@@ -0,0 +1,101 @@
1
+ @charset "utf8";
2
+ /*!
3
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
4
+ Copyright (C) 2025 jeffy-g <hirotom1107@gmail.com>
5
+ Released under the MIT license
6
+ https://opensource.org/licenses/mit-license.php
7
+ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8
+ */
9
+
10
+ .command {
11
+ font-family: consolas;
12
+ color: rgb(37 143 231);
13
+ background-color: rgba(192, 192, 192, 0.23);
14
+ padding: 4px 6px;
15
+ border: solid 1px silver;
16
+ border-radius: 4px;
17
+ }
18
+
19
+ /* button {
20
+ width: 100px;
21
+ transition: filter 300ms ease;
22
+ } */
23
+ button:disabled {
24
+ filter: opacity(0.3) blur(0.4px);
25
+ }
26
+ button.copy {
27
+ width: 20px;
28
+ height: 20px;
29
+ background: url('data:image/svg+xml;charset=UTF-8,<svg height="16px" viewBox="-21 0 512 512" width="16px" xmlns="http://www.w3.org/2000/svg"><path d="m186.667969 416c-49.984375 0-90.667969-40.683594-90.667969-90.667969v-218.664062h-37.332031c-32.363281 0-58.667969 26.300781-58.667969 58.664062v288c0 32.363281 26.304688 58.667969 58.667969 58.667969h266.664062c32.363281 0 58.667969-26.304688 58.667969-58.667969v-37.332031zm0 0"/><path d="m469.332031 58.667969c0-32.40625-26.261719-58.667969-58.664062-58.667969h-224c-32.40625 0-58.667969 26.261719-58.667969 58.667969v266.664062c0 32.40625 26.261719 58.667969 58.667969 58.667969h224c32.402343 0 58.664062-26.261719 58.664062-58.667969zm0 0"/></svg>') no-repeat center/14px;
30
+ border: solid 1px rgba(192, 192, 192, 0.73);
31
+ border-radius: 3px;
32
+ display: inline-block;
33
+ vertical-align: middle;
34
+ margin-left: 3px;
35
+ cursor: pointer;
36
+ padding: 2px;
37
+ box-sizing: content-box;
38
+ }
39
+
40
+ .footer {
41
+ position: fixed;
42
+
43
+ box-sizing: border-box;
44
+ margin: 0;
45
+ left: 0; bottom: 2px;
46
+ width: 100%;
47
+ padding: 2px 8px;
48
+
49
+ display: flex;
50
+ justify-content: flex-end;
51
+ align-items: center;
52
+ align-content: center;
53
+ justify-items: end;
54
+
55
+ font-size: 10px;
56
+ background-color: var(--card-bg);
57
+ color: snow;
58
+ }
59
+ .footer a {
60
+ text-decoration: none;
61
+ margin: 0 4px;
62
+ }
63
+
64
+ .log-frame {
65
+ position: relative;
66
+
67
+ height: calc(100vh - 100px - 30px);
68
+
69
+ border: none;
70
+ padding: 3px 4px;
71
+ border-radius: 4px;
72
+
73
+ font-family: consolas;
74
+ white-space: pre;
75
+ overflow: auto;
76
+
77
+ background-color: rgb(22 22 22);
78
+ color: #ececec;
79
+ /* &:empty {
80
+ padding: 0;
81
+ width: 0; height: 0;
82
+ border: none;
83
+ border-radius: unset;
84
+ } */
85
+ }
86
+
87
+ span.key {
88
+ color: rgb(255 150 150);
89
+ }
90
+ span.number {
91
+ color: rgb(89 174 255);
92
+ }
93
+ span.string {
94
+ color: rgb(95 249 95);
95
+ }
96
+ span.bool {
97
+ color: rgb(205, 108, 255);
98
+ }
99
+ span.nul {
100
+ color: rgb(255, 44, 44);
101
+ }
package/web/index.html ADDED
@@ -0,0 +1,57 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
+ <title>eve-esi-types ESI request test</title>
8
+ <script type="module" src="../minimal-rq.mjs"></script>
9
+ <link rel="stylesheet" href="./index.css">
10
+ </head>
11
+
12
+ <body>
13
+ <div class="container">
14
+ <button id="run-test">Run test</button>
15
+ </div>
16
+ <div class="info">
17
+ <div>example command: <input type="text" class="command" value="browser-sync start -s --port 8080 --no-open --ss &lt;this site directory>" size="72" readonly>
18
+ <button class="copy" onclick="copy('.command', '.')"></button>
19
+ </div>
20
+ then access to <a href="http://localhost:8080/web/?x=1&debug=1">eve-esi-types ESI request test</a>
21
+ </div>
22
+ <div class="log-frame" contenteditable></div>
23
+ <footer class="footer"></footer>
24
+ <script>
25
+ /** @type {(s: string, rep: string, regex?: RegExp) => void} */
26
+ function copy(selector, replacement, regex = /<[^>]+>/) {
27
+ /** @type {HTMLInputElement} */
28
+ const text = document.querySelector(selector);
29
+ const shellscript = text.value.replace(regex, replacement);
30
+ navigator.clipboard.writeText(shellscript).then(() => alert("Copied the text: " + shellscript));
31
+ }
32
+ /** @type {HTMLDivElement} */
33
+ const logElement = document.querySelector(".log-frame");
34
+ if (logElement) {
35
+ let inputBuffer = "";
36
+ logElement.addEventListener("keydown", function (e) {
37
+ if (e.ctrlKey) {
38
+ if (e.code === "KeyL") {
39
+ e.preventDefault();
40
+ logElement.innerHTML = "";
41
+ }
42
+ } else {
43
+ const key = e.key;
44
+ if (key === "Enter") {
45
+ const cmd = inputBuffer;
46
+ inputBuffer = "";
47
+ eval(`(${cmd})`);
48
+ } else if (key.length === 1) {
49
+ inputBuffer += key;
50
+ }
51
+ }
52
+ });
53
+ }
54
+ </script>
55
+ </body>
56
+
57
+ </html>
package/index.html DELETED
@@ -1,18 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>eve-esi-types ESI request test</title>
7
- <script type="module" src="./minimal-rq.mjs"></script>
8
- </head>
9
- <body>
10
- <div class="container">
11
- </div>
12
- <div class="info">
13
- browser-sync start -s --port 8080 --no-open --ss ./<br>
14
- then access to <a href="http://localhost:8080/?x=1&debug=1">eve-esi-types ESI request test</a>
15
- </div>
16
- <footer class="footer"></footer>
17
- </body>
18
- </html>