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.
- package/lib/console-util.d.mts +15 -0
- package/lib/console-util.mjs +102 -0
- package/lib/constants.d.mts +10 -0
- package/lib/constants.mjs +23 -0
- package/lib/esi-error-types.d.ts +13 -2
- package/lib/request-api.mjs +4 -6
- package/lib/rq-util.d.mts +16 -16
- package/lib/rq-util.mjs +30 -51
- package/lib/tagged-request-api.d.mts +4 -3
- package/lib/tagged-request-api.mjs +18 -7
- package/minimal-rq.mjs +16 -8
- package/package.json +2 -2
- package/web/index.css +101 -0
- package/web/index.html +57 -0
- package/index.html +0 -18
|
@@ -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,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
|
+
})();
|
package/lib/esi-error-types.d.ts
CHANGED
|
@@ -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, ...
|
|
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;
|
package/lib/request-api.mjs
CHANGED
|
@@ -14,7 +14,7 @@ import * as util from "./rq-util.mjs";
|
|
|
14
14
|
// constants, types
|
|
15
15
|
// - - - - - - - - - - - - - - - - - - - -
|
|
16
16
|
// shorthands
|
|
17
|
-
const 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
|
-
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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}
|
|
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,
|
|
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
|
-
|
|
14
|
-
|
|
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 =
|
|
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
|
-
|
|
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 (
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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}
|
|
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,
|
|
238
|
+
export const fetchP = async (endpointUrl, rqopt, usp, pc, increment = () => { }) => {
|
|
257
239
|
const rqs = [];
|
|
258
240
|
for (let i = 2; i <= pc;) {
|
|
259
|
-
|
|
241
|
+
usp.set("page", (i++) + "");
|
|
260
242
|
increment();
|
|
261
|
-
rqs.push(fetch(`${endpointUrl}?${
|
|
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 =
|
|
335
|
-
const rlog =
|
|
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}/",
|
|
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/",
|
|
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: [
|
|
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
|
|
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/",
|
|
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(
|
|
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<
|
|
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
|
|
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<
|
|
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
|
|
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] = /** @
|
|
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 =
|
|
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}/",
|
|
54
|
+
await fn.get("/characters/{character_id}/", ID_CCP_Zoetrope).then(log);
|
|
54
55
|
clog('(portrait)');
|
|
55
|
-
await fn.get("/characters/{character_id}/portrait/",
|
|
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: [
|
|
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
|
-
|
|
88
|
+
runTest();
|
|
85
89
|
}
|
|
86
90
|
else {
|
|
87
91
|
// @ts-ignore
|
|
88
|
-
globalThis.runTest =
|
|
89
|
-
|
|
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
|
+
"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 <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>
|