eve-esi-types 2.2.6 → 2.3.2

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/README.md CHANGED
@@ -32,6 +32,31 @@ export declare function fire<
32
32
  >(mthd: M, endp: EP, pathParams?: P2, opt?: Opt): Promise<R>;
33
33
  ```
34
34
 
35
+ ## New Features in v2.3.0
36
+
37
+ ### ESI Tagged Types
38
+
39
+ > Introduced intuitive ESI requests handling using "tags" from the EVE Swagger JSON.
40
+
41
+ ### injectESIRequestBody
42
+
43
+ > Utilized `injectESIRequestBody` to generate ESI request API objects with narrowed endpoints by accessing camel-cased "tags".
44
+
45
+ ```ts
46
+ import * as taggedApi from "eve-esi-types/lib/tagged-request-api.mjs";
47
+
48
+ const esiRequest = taggedApi.injectESIRequestBody(...);
49
+ const ret = await esiRequest.universe.get("/universe/structures/", { query: { filter: "market" }});
50
+ ```
51
+
52
+ + or
53
+
54
+ ```ts
55
+ // Minimal default ESI request body implementation
56
+ import { esi } from "eve-esi-types/lib/tagged-request-api.mjs";
57
+
58
+ const ret = await esi.universe.get("/universe/structures/", { query: { filter: "market" }});
59
+ ```
35
60
 
36
61
  ## References
37
62
 
package/esi-types-util.md CHANGED
@@ -28,7 +28,11 @@ type TESIRequestFunctionSignature<ActualOpt> = <
28
28
  `IfParameterizedPath<EP, Opt>` if parameterized path then specify number type, otherwise will be `Opt` type.
29
29
 
30
30
  ```ts
31
- type IfParameterizedPath<EP, Opt> = EP extends `${string}/{${string}}/${string | ""}` ? number | number[]: Opt;
31
+ type IfParameterizedPath<EP, Opt> = EP extends `${string}/{${string}}${string}`
32
+ ? PickPathParameters<EP> extends never
33
+ ? Opt : InferKeysLen<PickPathParameters<EP>> extends 1
34
+ ? number : [number, number]
35
+ : Opt;
32
36
  ```
33
37
 
34
38
  ### IdentifyParameters
@@ -0,0 +1,104 @@
1
+
2
+ type TEVEErrorBase = {
3
+ /**
4
+ * error message
5
+ */
6
+ error: string;
7
+ };
8
+ /**
9
+ * There are endpoints with status 200 only that contain the "X-Pages" header.
10
+ */
11
+ export type TSuccessStats = 200 | 201 | 204;
12
+ export type TRedirectStats = 304;
13
+ export type TClientErrorStats = 400 | 401 | 403 | 404 | 420 | 422;
14
+ export type TServerErrorStats = 500 | 503 | 504 | 520;
15
+ export type TESIErrorStats = TClientErrorStats | TServerErrorStats;
16
+ export type TStatsAll = TSuccessStats | TRedirectStats | TClientErrorStats | TServerErrorStats;
17
+ export type TESIErrorStatMap = {
18
+ // status 400
19
+ 400: BadRequest;
20
+ 401: Unauthorized;
21
+ 403: Forbidden;
22
+ 404: NotFound;
23
+ 420: ErrorLimited;
24
+ 422: Unprocessable;
25
+
26
+ // status 500
27
+ 500: InternalServerError;
28
+ 503: ServiceUnavailable;
29
+ 504: GatewayTimeout;
30
+ 520: EVEServerError;
31
+ };
32
+ /**
33
+ * ```ts
34
+ * const res = await fetch("<URL with ESI endpoint>");
35
+ * const status = res.status;
36
+ * if (status >= 400) {
37
+ * const errorType: TESIErrorWithStat<typeof status> = {
38
+ * status, ...res.json()
39
+ * };
40
+ * console.log(errorType);
41
+ * throw new Error(`message="${res.statusText}", status=${status}`);
42
+ * }
43
+ * ```
44
+ *
45
+ * @date 2025/3/3
46
+ * @since 2.4.0
47
+ */
48
+ export type TESIErrorWithStat<Stat extends TClientErrorStats | TServerErrorStats> = {
49
+ status: Stat;
50
+ } & TESIErrorStatMap[Stat];
51
+ // declare const bad: TESIErrorWithStat<400>;
52
+
53
+ /**
54
+ * Bad request model 400
55
+ */
56
+ export interface BadRequest extends TEVEErrorBase {}
57
+ /**
58
+ * Not Found model 404
59
+ */
60
+ export interface NotFound extends TEVEErrorBase {}
61
+ /**
62
+ * Unprocessable model 422[Unprocessable entity]
63
+ */
64
+ export interface Unprocessable extends TEVEErrorBase {}
65
+ /**
66
+ * Unauthorized model 401
67
+ */
68
+ export interface Unauthorized extends TEVEErrorBase {}
69
+ /**
70
+ * Forbidden model 403
71
+ */
72
+ export interface Forbidden extends TEVEErrorBase {
73
+ /**
74
+ * status code received from SSO
75
+ */
76
+ sso_status?: number;
77
+ }
78
+
79
+ /**
80
+ * Error limited model 420
81
+ */
82
+ export interface ErrorLimited extends TEVEErrorBase {}
83
+
84
+ /**
85
+ * Internal server error model 500
86
+ */
87
+ export interface InternalServerError extends TEVEErrorBase {}
88
+ /**
89
+ * Service unavailable model 503
90
+ */
91
+ export interface ServiceUnavailable extends TEVEErrorBase {}
92
+ /**
93
+ * Gateway timeout model 504
94
+ */
95
+ export interface GatewayTimeout extends TEVEErrorBase {
96
+ /**
97
+ * number of seconds the request was given
98
+ */
99
+ timeout?: number;
100
+ }
101
+ /**
102
+ * EVE server error model 520
103
+ */
104
+ export interface EVEServerError extends InternalServerError {}
@@ -0,0 +1,27 @@
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
+ import type { IESIRequestFunction } from "../v2";
10
+ /**
11
+ * @typedef {import("../v2").IESIRequestFunction<util.ESIRequestOptions>} IESIRequestFunction
12
+ * @typedef {import("../v2").TESIRequestFunctionMethods<util.ESIRequestOptions>} TESIRequestFunctionMethods
13
+ */
14
+ /** #### Sample of `TESIRequestFunctionSignature`
15
+ *
16
+ * + This is a minimal implementation using `TESIRequestFunctionSignature`.
17
+ * If the response contains "page", only the first page can be retrieved.
18
+ *
19
+ * @type {IESIRequestFunction}
20
+ * @param method - The HTTP method to use for the request
21
+ * @param endpoint - The Path of the ESI endpoint to send the request to
22
+ * @param pathParams - An object of parameters to include in the request
23
+ * @param options - An object of options to include in the request
24
+ * @returns A Promise object containing the response data
25
+ * @throws {ESIRequesError}
26
+ */
27
+ export declare const request: IESIRequestFunction<util.ESIRequestOptions>;
@@ -0,0 +1,79 @@
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").IESIRequestFunction<util.ESIRequestOptions>} IESIRequestFunction
21
+ * @typedef {import("../v2").TESIRequestFunctionMethods<util.ESIRequestOptions>} TESIRequestFunctionMethods
22
+ */
23
+ // - - - - - - - - - - - - - - - - - - - -
24
+ // main functions
25
+ // - - - - - - - - - - - - - - - - - - - -
26
+ /** #### Sample of `TESIRequestFunctionSignature`
27
+ *
28
+ * + This is a minimal implementation using `TESIRequestFunctionSignature`.
29
+ * If the response contains "page", only the first page can be retrieved.
30
+ *
31
+ * @type {IESIRequestFunction}
32
+ * @param method - The HTTP method to use for the request
33
+ * @param endpoint - The Path of the ESI endpoint to send the request to
34
+ * @param pathParams - An object of parameters to include in the request
35
+ * @param options - An object of options to include in the request
36
+ * @returns A Promise object containing the response data
37
+ * @throws {ESIRequesError}
38
+ */
39
+ // @ts-expect-error
40
+ export const request = async (method, endpoint, pathParams, opt) => {
41
+ if (typeof pathParams === "number") {
42
+ // @ts-expect-error
43
+ pathParams = [pathParams];
44
+ }
45
+ if (Array.isArray(pathParams)) {
46
+ // @ts-expect-error actualy endp is string
47
+ endpoint = util.replaceCbt(endpoint, pathParams);
48
+ }
49
+ // When only options are provided
50
+ const actualOpt = /** @type {NonNullable<typeof opt>} */ (opt || pathParams || {});
51
+ const { rqopt, qss } = util.initOptions(method, actualOpt);
52
+ // @ts-expect-error actualy endp is string
53
+ const endpointUrl = util.curl(endpoint);
54
+ const up = new URLSearchParams(qss);
55
+ const url = `${endpointUrl}${up.size ? `?${up}` : ""}`;
56
+ DEBUG && log(url);
57
+ try {
58
+ const res = await fetch(url, rqopt);
59
+ const { status } = res;
60
+ // The parameters are different for successful and error responses.
61
+ if (util.isSuccess(status)) {
62
+ return util.handleSuccessResponse(res, endpointUrl, rqopt, up);
63
+ }
64
+ // else if (isError(status)) {}
65
+ // Actually, throw Error
66
+ throw await util.handleESIError(res, endpointUrl, actualOpt.cancelable);
67
+ }
68
+ catch (e) {
69
+ log(e);
70
+ }
71
+ };
72
+ //
73
+ // implements rest methods of `request` (IESIRequestFunction)
74
+ //
75
+ /** @type {TESIEntryMethod[]} */ (["get", "post", "put", "delete"]).forEach((method) => {
76
+ request[method] = /** @type {TESIRequestFunctionEachMethod<typeof method>} */ (function (endpoint, params, opt) {
77
+ return this(method, endpoint, params, opt);
78
+ });
79
+ });
@@ -6,7 +6,8 @@
6
6
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
7
  */
8
8
  import "colors.ts";
9
- import type { TESIRequestFunctionMethods } from "./v2";
9
+ import type { TESIRequestFunctionMethods } from "../v2";
10
+ import type { TESIErrorStats } from "./esi-error-types";
10
11
  /**
11
12
  * this always `https://esi.evetech.net`
12
13
  */
@@ -25,10 +26,6 @@ export type ESIRequestOptions = {
25
26
  * will need it for `POST` request etc.
26
27
  */
27
28
  body?: any;
28
- /**
29
- * if want response data with ignore error then can be set to `true`.
30
- */
31
- ignoreError?: boolean;
32
29
  /**
33
30
  * cancel request immediately
34
31
  */
@@ -46,6 +43,9 @@ export type ESIRequestOptions = {
46
43
  */
47
44
  auth?: true;
48
45
  };
46
+ /**
47
+ * @typedef {string | number | boolean} Truthy
48
+ */
49
49
  /**
50
50
  * simple named error class.
51
51
  */
@@ -61,11 +61,58 @@ export declare class ESIErrorLimitReachedError extends ESIRequesError {
61
61
  /**
62
62
  * @typedef {import("./rq-util.mjs").ESIRequestOptions} ESIRequestOptions
63
63
  */
64
+ /**
65
+ * #### status: 200 | 201 | 204
66
+ *
67
+ * + Returns a json object only if the status is `200` or `201`.
68
+ *
69
+ * @param {Response} response
70
+ * @param {string} endpointUrl
71
+ * @param {RequestInit} requestOpt
72
+ * @param {URLSearchParams} urlParams
73
+ * @param {(minus?: Truthy) => void=} increment
74
+ * @returns {Promise<any>}
75
+ */
76
+ export declare const handleSuccessResponse: (response: Response, endpointUrl: string, requestOpt: RequestInit, urlParams: URLSearchParams, increment?: (minus?: Truthy) => void) => Promise<any>;
77
+ /**
78
+ * @import {
79
+ * TESIErrorStats,
80
+ * TESIErrorStatMap,
81
+ * TESIErrorWithStat
82
+ * } from "./esi-error-types";
83
+ */
84
+ /**
85
+ * #### status: (400 | 401 | 403 | 404 | 420 | 422) or (500 | 503 | 504 | 520)
86
+ *
87
+ * @param {Response} res
88
+ * @param {string} endpointUrl
89
+ * @param {AbortController} abortable
90
+ * @returns {Promise<void>}
91
+ */
92
+ export declare const handleESIError: (res: Response, endpointUrl: string, abortable?: AbortController) => Promise<void>;
93
+ /**
94
+ * @param {number} stat
95
+ * @returns {stat is 200 | 201 | 204}
96
+ */
97
+ export declare const isSuccess: (stat: number) => stat is 200 | 201 | 204;
98
+ /**
99
+ * @param {number} stat
100
+ * @returns {stat is TESIErrorStats}
101
+ */
102
+ export declare const isError: (stat: number) => stat is TESIErrorStats;
103
+ /**
104
+ * @returns {boolean}
105
+ */
64
106
  export declare const isDebug: () => boolean;
107
+ /**
108
+ * @param {string} opt
109
+ * @returns {boolean}
110
+ */
111
+ export declare const is: (opt: string) => boolean;
65
112
  /**
66
113
  * @param {string} method
67
114
  * @param {ESIRequestOptions} opt
68
- * @returns
115
+ * @returns {{ rqopt: RequestInit, qss: Record<string, string> }}
69
116
  */
70
117
  export declare const initOptions: (method: string, opt: ESIRequestOptions) => {
71
118
  rqopt: RequestInit;
@@ -75,12 +122,13 @@ export declare const initOptions: (method: string, opt: ESIRequestOptions) => {
75
122
  * fetch the extra pages
76
123
  *
77
124
  * + if the `x-pages` header property ware more than 1
78
- *
125
+ * @template {any} T
79
126
  * @param {string} endpointUrl
80
127
  * @param {RequestInit} rqopt request options
81
128
  * @param {URLSearchParams} rqp queries
82
129
  * @param {number} pc pageCount
83
130
  * @param {(minus?: number) => void=} increment
131
+ * @returns {Promise<T | null>}
84
132
  */
85
133
  export declare const fetchP: <T extends unknown>(endpointUrl: string, rqopt: RequestInit, rqp: URLSearchParams, pc: number, increment?: (minus?: Truthy) => void) => Promise<T | null>;
86
134
  /** ### replace (C)urly (B)races (T)oken
@@ -92,13 +140,14 @@ export declare const fetchP: <T extends unknown>(endpointUrl: string, rqopt: Req
92
140
  *
93
141
  * @param {string} endpoint e.g - "/characters/{character_id}/"
94
142
  * @param {number[]} ids
95
- * @returns fragment of qualified endpoint uri or null.
143
+ * @returns {string | null} fragment of qualified endpoint uri or null.
96
144
  */
97
145
  export declare const replaceCbt: (endpoint: string, ids: number[]) => string;
98
146
  /**
99
147
  *
100
148
  * @param {string} endp this means endpoint url fragment like `/characters/{character_id}/` or `/characters/{character_id}/agents_research/`
101
149
  * + The version parameter is forced to apply `latest`
150
+ * @returns {string}
102
151
  */
103
152
  export declare const curl: (endp: string) => string;
104
153
  /**
@@ -115,5 +164,6 @@ export declare function getLogger(): {
115
164
  * #### Fire a request that does not require authentication.
116
165
  *
117
166
  * @param {TESIRequestFunctionSignature<ESIRequestOptions> | TESIRequestFunctionMethods} fn
167
+ * @returns {Promise<void>}
118
168
  */
119
169
  export declare function fireRequestsDoesNotRequireAuth(fn: TESIRequestFunctionSignature<ESIRequestOptions> | TESIRequestFunctionMethods<ESIRequestOptions>): Promise<void>;
@@ -5,7 +5,7 @@
5
5
  // https://opensource.org/licenses/mit-license.php
6
6
  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
7
  */
8
- /// <reference types="./v2"/>
8
+ /// <reference types="../v2"/>
9
9
  // - - - - - - - - - - - - - - - - - - - -
10
10
  // imports
11
11
  // - - - - - - - - - - - - - - - - - - - -
@@ -24,6 +24,9 @@ let LOG = false;
24
24
  * this always `https://esi.evetech.net`
25
25
  */
26
26
  export const BASE = "https://esi.evetech.net";
27
+ /**
28
+ * @typedef {string | number | boolean} Truthy
29
+ */
27
30
  /**
28
31
  * simple named error class.
29
32
  */
@@ -46,13 +49,121 @@ export class ESIErrorLimitReachedError extends ESIRequesError {
46
49
  // - - - - - - - - - - - - - - - - - - - -
47
50
  // utility functions
48
51
  // - - - - - - - - - - - - - - - - - - - -
52
+ /**
53
+ * #### status: 200 | 201 | 204
54
+ *
55
+ * + Returns a json object only if the status is `200` or `201`.
56
+ *
57
+ * @param {Response} response
58
+ * @param {string} endpointUrl
59
+ * @param {RequestInit} requestOpt
60
+ * @param {URLSearchParams} urlParams
61
+ * @param {(minus?: Truthy) => void=} increment
62
+ * @returns {Promise<any>}
63
+ */
64
+ export const handleSuccessResponse = async (response, endpointUrl, requestOpt, urlParams, increment = () => { }) => {
65
+ // NoContentResponse
66
+ if (response.status === 204)
67
+ return {};
68
+ /** @type {any} */
69
+ const data = await response.json();
70
+ // - - - - x-pages response.
71
+ // +undefined is NaN
72
+ // @ts-expect-error becouse +null is 0
73
+ const pc = +response.headers.get("x-pages");
74
+ // has remaining pages? NaN > 1 === false !isNaN(pageCount)
75
+ if (pc > 1) {
76
+ LOG && log('found "x-pages" header, pages: %d', pc);
77
+ const remData = await fetchP(endpointUrl, requestOpt, urlParams, pc, increment);
78
+ // finally, decide product data.
79
+ if (isArray(data) && isArray(remData)) {
80
+ // DEVNOTE: 2019/7/23 15:01:48 - types
81
+ return data.concat(remData);
82
+ }
83
+ else {
84
+ remData && Object.assign(data, remData);
85
+ }
86
+ }
87
+ return data;
88
+ };
89
+ /**
90
+ * @import {
91
+ * TESIErrorStats,
92
+ * TESIErrorStatMap,
93
+ * TESIErrorWithStat
94
+ * } from "./esi-error-types";
95
+ */
96
+ /**
97
+ * #### status: (400 | 401 | 403 | 404 | 420 | 422) or (500 | 503 | 504 | 520)
98
+ *
99
+ * @param {Response} res
100
+ * @param {string} endpointUrl
101
+ * @param {AbortController} abortable
102
+ * @returns {Promise<void>}
103
+ */
104
+ export const handleESIError = async (res, endpointUrl, abortable) => {
105
+ const status = /** @type {TESIErrorStats} */ (res.status);
106
+ /** @type {TESIErrorStatMap[typeof status]} */
107
+ const esiError = await res.json();
108
+ /** @type {TESIErrorWithStat<typeof status>} */
109
+ const errorType = {
110
+ status, ...esiError
111
+ };
112
+ // log ESI Error details
113
+ console.warn(errorType);
114
+ if (status === 420) {
115
+ abortable && abortable.abort();
116
+ throw new ESIErrorLimitReachedError();
117
+ }
118
+ else {
119
+ // console.log(res);
120
+ throw new ESIRequesError(`${res.statusText} (status=${status}, url=${endpointUrl})`);
121
+ }
122
+ };
123
+ /** @satisfies {TESIErrorStats[]} */
124
+ const ESIErrorStats = [
125
+ // status 400
126
+ 400, // BadRequest;
127
+ 401, // Unauthorized;
128
+ 403, // Forbidden;
129
+ 404, // NotFound;
130
+ 420, // ErrorLimited;
131
+ 422, // Unprocessable;
132
+ // status 500
133
+ 500, // InternalServerError;
134
+ 503, // ServiceUnavailable;
135
+ 504, // GatewayTimeout;
136
+ 520, // EVEServerError;
137
+ ];
138
+ /**
139
+ * @param {number} stat
140
+ * @returns {stat is 200 | 201 | 204}
141
+ */
142
+ export const isSuccess = (stat) => {
143
+ return stat === 200 || stat === 201 || stat === 204;
144
+ };
145
+ /**
146
+ * @param {number} stat
147
+ * @returns {stat is TESIErrorStats}
148
+ */
149
+ export const isError = (stat) => {
150
+ return ESIErrorStats.includes(/** @type {TESIErrorStats} */ (stat));
151
+ };
152
+ /**
153
+ * @returns {boolean}
154
+ */
49
155
  export const isDebug = () => {
50
156
  return process.argv.includes("-debug");
51
157
  };
158
+ /**
159
+ * @param {string} opt
160
+ * @returns {boolean}
161
+ */
162
+ export const is = (opt) => process.argv.includes(`-${opt}`);
52
163
  /**
53
164
  * @param {string} method
54
165
  * @param {ESIRequestOptions} opt
55
- * @returns
166
+ * @returns {{ rqopt: RequestInit, qss: Record<string, string> }}
56
167
  */
57
168
  export const initOptions = (method, opt) => {
58
169
  /** @type {RequestInit} */
@@ -63,6 +174,7 @@ export const initOptions = (method, opt) => {
63
174
  signal: opt.cancelable?.signal,
64
175
  headers: {}
65
176
  };
177
+ /** @type {Record<string, string>} */
66
178
  const qss = {
67
179
  // language: "en",
68
180
  };
@@ -86,12 +198,13 @@ export const initOptions = (method, opt) => {
86
198
  * fetch the extra pages
87
199
  *
88
200
  * + if the `x-pages` header property ware more than 1
89
- *
201
+ * @template {any} T
90
202
  * @param {string} endpointUrl
91
203
  * @param {RequestInit} rqopt request options
92
204
  * @param {URLSearchParams} rqp queries
93
205
  * @param {number} pc pageCount
94
206
  * @param {(minus?: number) => void=} increment
207
+ * @returns {Promise<T | null>}
95
208
  */
96
209
  export const fetchP = async (endpointUrl, rqopt, rqp, pc, increment = () => { }) => {
97
210
  const rqs = [];
@@ -112,7 +225,7 @@ export const fetchP = async (endpointUrl, rqopt, rqp, pc, increment = () => { })
112
225
  for (let i = 0, end = jsons.length; i < end;) {
113
226
  combined = combined.concat(jsons[i++]);
114
227
  }
115
- return combined;
228
+ return /** @type {T} */ (combined);
116
229
  }
117
230
  LOG && log("> > > pages result are object < < < --", jsons);
118
231
  return null;
@@ -127,22 +240,17 @@ export const fetchP = async (endpointUrl, rqopt, rqp, pc, increment = () => { })
127
240
  *
128
241
  * @param {string} endpoint e.g - "/characters/{character_id}/"
129
242
  * @param {number[]} ids
130
- * @returns fragment of qualified endpoint uri or null.
243
+ * @returns {string | null} fragment of qualified endpoint uri or null.
131
244
  */
132
245
  export const replaceCbt = (endpoint, ids) => {
133
- const re = /{([\w]+)}/g;
134
- /** @type {RegExpExecArray?} */
135
- let m;
136
246
  let idx = 0;
137
- while (m = re.exec(endpoint)) {
138
- endpoint = endpoint.replace(m[0], ids[idx++] + "");
139
- }
140
- return endpoint;
247
+ return endpoint.replace(/{([\w]+)}/g, $0 => ids[idx++] + "");
141
248
  };
142
249
  /**
143
250
  *
144
251
  * @param {string} endp this means endpoint url fragment like `/characters/{character_id}/` or `/characters/{character_id}/agents_research/`
145
252
  * + The version parameter is forced to apply `latest`
253
+ * @returns {string}
146
254
  */
147
255
  export const curl = (endp) => {
148
256
  endp = endp.replace(/^\/+|\/+$/g, "");
@@ -159,7 +267,7 @@ export async function getSDEVersion() {
159
267
  const res = await fetch(sdeZipUrl, { method: "head", mode: "cors" });
160
268
  const date = res.headers.get("last-modified");
161
269
  if (date) {
162
- const YMD = new Date(date).toLocaleDateString('en-CA').replace(/-/g, '');
270
+ const YMD = new Date(date).toLocaleDateString("en-CA").replace(/-/g, "");
163
271
  return `sde-${YMD}-TRANQUILITY`;
164
272
  }
165
273
  else {
@@ -174,12 +282,12 @@ export async function getSDEVersion() {
174
282
  }
175
283
  export function getLogger() {
176
284
  const clog = console.log.bind(console, '- - -> Get the character data of "CCP Zoetrope"'.magenta);
177
- const rlog = console.log.bind(console, '- - -> Run ESI request'.cyan);
285
+ const rlog = console.log.bind(console, "- - -> Run ESI request".cyan);
178
286
  return { clog, rlog };
179
287
  }
180
288
  /**
181
289
  * Need typescript v5.5 later
182
- * @import * as ESI from "./v2";
290
+ * @import * as ESI from "../v2";
183
291
  * @typedef {ESI.TESIResponseOKMap} TESIResponseOKMap
184
292
  * @typedef {ESI.IESIRequestFunction<ESIRequestOptions>} IESIRequestFunction
185
293
  * @typedef {ESI.TESIRequestFunctionMethods<ESIRequestOptions>} TESIRequestFunctionMethods
@@ -211,6 +319,7 @@ function fireWithoutAuth(fn, method, endpoint, pathParams, opt) {
211
319
  * #### Fire a request that does not require authentication.
212
320
  *
213
321
  * @param {TESIRequestFunctionSignature<ESIRequestOptions> | TESIRequestFunctionMethods} fn
322
+ * @returns {Promise<void>}
214
323
  */
215
324
  export async function fireRequestsDoesNotRequireAuth(fn) {
216
325
  const { clog, rlog } = getLogger();
@@ -277,6 +386,7 @@ export async function fireRequestsDoesNotRequireAuth(fn) {
277
386
  },
278
387
  });
279
388
  // TODO: want TypeScript semantics to throw an error because there is a required query parameter, but it's not possible
389
+ // Or rather, I don't know how to do it.
280
390
  await fireWithoutAuth(fn, "get", "/characters/{character_id}/search/");
281
391
  log(ok);
282
392
  }
@@ -0,0 +1,35 @@
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/esi-tagged-types"/>
9
+ import type { ESIRequestOptions } from "./rq-util.mjs";
10
+ /**
11
+ * `esi-tagged-types` and `injectESIRequestBody` allow for more intuitive use of ESI requests based on the "tags" defined in the EVE Swagger JSON.
12
+ *
13
+ * + The `ESI request API object` constructed by `injectESIRequestBody` lists narrowed endpoints by accessing the camel-cased "tags" members.
14
+ *
15
+ * @example
16
+ * import * as taggedApi from "eve-esi-types/lib/tagged-request-api.mjs";
17
+ *
18
+ * const esiRequest = taggedApi.injectESIRequestBody(...);
19
+ * const ret = await esiRequest.universe.get("/universe/structures/", { query: { filter: "market" }});
20
+ *
21
+ * @template {Record<string, unknown>} Opt
22
+ * @param {TESIRequestFunctionSignature<{}>} requestBody
23
+ * @returns {XESI.TaggedESIRequestMap}
24
+ * @since 2.3
25
+ */
26
+ export declare function injectESIRequestBody<Opt extends Record<string, unknown>>(requestBody: TESIRequestFunctionSignature<Opt>): XESI.TaggedESIRequestMap<Opt>;
27
+ /**
28
+ * @import { ESIRequestOptions } from "./rq-util.mjs";
29
+ */
30
+ /**
31
+ * Injects the minimal implementation of ESI requests into `XESI.TaggedESIRequestMap`.
32
+ * @since 2.3
33
+ * @type {XESI.TaggedESIRequestMap<ESIRequestOptions>}
34
+ */
35
+ export declare const esi: import("../v2/esi-tagged-types").TaggedESIRequestMap<ESIRequestOptions>;