@wevu/web-apis 1.0.0
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/LICENSE +21 -0
- package/dist/abort.d.mts +17 -0
- package/dist/abort.mjs +28 -0
- package/dist/fetch.d.mts +26 -0
- package/dist/fetch.mjs +182 -0
- package/dist/http.d.mts +53 -0
- package/dist/http.mjs +170 -0
- package/dist/index.d.mts +23 -0
- package/dist/index.mjs +83 -0
- package/dist/shared.d.mts +28 -0
- package/dist/shared.mjs +73 -0
- package/dist/url.d.mts +46 -0
- package/dist/url.mjs +209 -0
- package/dist/web.d.mts +30 -0
- package/dist/web.mjs +83 -0
- package/dist/xhr.d.mts +68 -0
- package/dist/xhr.mjs +161 -0
- package/package.json +82 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 ice breaker
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/dist/abort.d.mts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { RequestGlobalsEventTarget } from "./shared.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/abort.d.ts
|
|
4
|
+
declare class AbortSignalPolyfill extends RequestGlobalsEventTarget {
|
|
5
|
+
aborted: boolean;
|
|
6
|
+
reason: unknown;
|
|
7
|
+
onabort: ((event: {
|
|
8
|
+
type: string;
|
|
9
|
+
}) => void) | null;
|
|
10
|
+
throwIfAborted(): void;
|
|
11
|
+
}
|
|
12
|
+
declare class AbortControllerPolyfill {
|
|
13
|
+
readonly signal: AbortSignalPolyfill;
|
|
14
|
+
abort(reason?: unknown): void;
|
|
15
|
+
}
|
|
16
|
+
//#endregion
|
|
17
|
+
export { AbortControllerPolyfill, AbortSignalPolyfill };
|
package/dist/abort.mjs
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { RequestGlobalsEventTarget } from "./shared.mjs";
|
|
2
|
+
//#region src/abort.ts
|
|
3
|
+
function createAbortError(reason) {
|
|
4
|
+
if (reason instanceof Error) return reason;
|
|
5
|
+
if (typeof DOMException === "function") return new DOMException("The operation was aborted.", "AbortError");
|
|
6
|
+
const error = /* @__PURE__ */ new Error("The operation was aborted.");
|
|
7
|
+
error.name = "AbortError";
|
|
8
|
+
return error;
|
|
9
|
+
}
|
|
10
|
+
var AbortSignalPolyfill = class extends RequestGlobalsEventTarget {
|
|
11
|
+
aborted = false;
|
|
12
|
+
reason;
|
|
13
|
+
onabort = null;
|
|
14
|
+
throwIfAborted() {
|
|
15
|
+
if (this.aborted) throw createAbortError(this.reason);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
var AbortControllerPolyfill = class {
|
|
19
|
+
signal = new AbortSignalPolyfill();
|
|
20
|
+
abort(reason) {
|
|
21
|
+
if (this.signal.aborted) return;
|
|
22
|
+
this.signal.aborted = true;
|
|
23
|
+
this.signal.reason = reason;
|
|
24
|
+
this.signal.dispatchEvent({ type: "abort" });
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
//#endregion
|
|
28
|
+
export { AbortControllerPolyfill, AbortSignalPolyfill };
|
package/dist/fetch.d.mts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/fetch.d.ts
|
|
2
|
+
interface RequestLikeInput {
|
|
3
|
+
url: string;
|
|
4
|
+
method?: string;
|
|
5
|
+
headers?: unknown;
|
|
6
|
+
signal?: AbortSignal | null;
|
|
7
|
+
bodyUsed?: boolean;
|
|
8
|
+
clone?: () => {
|
|
9
|
+
arrayBuffer?: () => Promise<ArrayBuffer>;
|
|
10
|
+
text?: () => Promise<string>;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
interface RequestGlobalsFetchInit {
|
|
14
|
+
method?: string;
|
|
15
|
+
headers?: unknown;
|
|
16
|
+
body?: unknown;
|
|
17
|
+
signal?: AbortSignal | null;
|
|
18
|
+
[key: string]: unknown;
|
|
19
|
+
}
|
|
20
|
+
type RequestGlobalsFetchInput = string | URL | RequestLikeInput;
|
|
21
|
+
/**
|
|
22
|
+
* @description 使用 @wevu/api 的 request 能力实现 fetch 语义对齐。
|
|
23
|
+
*/
|
|
24
|
+
declare function fetch(input: RequestGlobalsFetchInput, init?: RequestGlobalsFetchInit): Promise<Response>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { RequestGlobalsFetchInit, fetch };
|
package/dist/fetch.mjs
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { cloneArrayBuffer, cloneArrayBufferView, normalizeHeaderName } from "./shared.mjs";
|
|
2
|
+
import { HeadersPolyfill, ResponsePolyfill } from "./http.mjs";
|
|
3
|
+
import { wpi } from "@wevu/api";
|
|
4
|
+
//#region src/fetch.ts
|
|
5
|
+
const REQUEST_METHODS = [
|
|
6
|
+
"GET",
|
|
7
|
+
"HEAD",
|
|
8
|
+
"OPTIONS",
|
|
9
|
+
"POST",
|
|
10
|
+
"PUT",
|
|
11
|
+
"DELETE",
|
|
12
|
+
"TRACE",
|
|
13
|
+
"CONNECT"
|
|
14
|
+
];
|
|
15
|
+
const hasOwn = Object.prototype.hasOwnProperty;
|
|
16
|
+
function isObject(value) {
|
|
17
|
+
return typeof value === "object" && value !== null;
|
|
18
|
+
}
|
|
19
|
+
function isNativeUrlInstance(value) {
|
|
20
|
+
return typeof URL !== "undefined" && value instanceof URL;
|
|
21
|
+
}
|
|
22
|
+
function createAbortError() {
|
|
23
|
+
if (typeof DOMException === "function") return new DOMException("The operation was aborted.", "AbortError");
|
|
24
|
+
const error = /* @__PURE__ */ new Error("The operation was aborted.");
|
|
25
|
+
error.name = "AbortError";
|
|
26
|
+
return error;
|
|
27
|
+
}
|
|
28
|
+
function normalizeMethod(method) {
|
|
29
|
+
const normalized = (method ?? "GET").toUpperCase();
|
|
30
|
+
if (REQUEST_METHODS.includes(normalized)) return normalized;
|
|
31
|
+
return "GET";
|
|
32
|
+
}
|
|
33
|
+
function setHeader(target, key, value) {
|
|
34
|
+
const normalizedKey = normalizeHeaderName(key);
|
|
35
|
+
if (!normalizedKey) return;
|
|
36
|
+
const nextValue = String(value);
|
|
37
|
+
for (const currentKey of Object.keys(target)) if (normalizeHeaderName(currentKey) === normalizedKey) delete target[currentKey];
|
|
38
|
+
target[key] = nextValue;
|
|
39
|
+
}
|
|
40
|
+
function hasHeader(target, key) {
|
|
41
|
+
const normalizedKey = normalizeHeaderName(key);
|
|
42
|
+
return Object.keys(target).some((currentKey) => normalizeHeaderName(currentKey) === normalizedKey);
|
|
43
|
+
}
|
|
44
|
+
function mergeHeaderSource(target, source) {
|
|
45
|
+
if (!source) return;
|
|
46
|
+
if (typeof source.forEach === "function") {
|
|
47
|
+
source.forEach((value, key) => {
|
|
48
|
+
setHeader(target, key, value);
|
|
49
|
+
});
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
if (typeof source[Symbol.iterator] === "function") {
|
|
53
|
+
for (const entry of source) {
|
|
54
|
+
if (!entry || entry.length < 2) continue;
|
|
55
|
+
setHeader(target, entry[0], entry[1]);
|
|
56
|
+
}
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (!isObject(source)) return;
|
|
60
|
+
for (const [key, value] of Object.entries(source)) {
|
|
61
|
+
if (Array.isArray(value)) {
|
|
62
|
+
setHeader(target, key, value.join(", "));
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
setHeader(target, key, value);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function toHeaderMap(source) {
|
|
69
|
+
const headers = {};
|
|
70
|
+
mergeHeaderSource(headers, source);
|
|
71
|
+
return headers;
|
|
72
|
+
}
|
|
73
|
+
function isRequestLikeInput(input) {
|
|
74
|
+
return isObject(input) && typeof input.url === "string";
|
|
75
|
+
}
|
|
76
|
+
async function extractRequestBodyFromInput(input) {
|
|
77
|
+
if (!input || typeof input.clone !== "function") return;
|
|
78
|
+
if (input.bodyUsed) throw new TypeError("Failed to execute fetch: request body is already used");
|
|
79
|
+
const cloned = input.clone();
|
|
80
|
+
if (cloned?.arrayBuffer) return cloned.arrayBuffer();
|
|
81
|
+
if (cloned?.text) return cloned.text();
|
|
82
|
+
}
|
|
83
|
+
async function normalizeRequestBody(body, headers) {
|
|
84
|
+
if (body == null) return;
|
|
85
|
+
if (typeof body === "string") {
|
|
86
|
+
if (!hasHeader(headers, "content-type")) headers["content-type"] = "text/plain;charset=UTF-8";
|
|
87
|
+
return body;
|
|
88
|
+
}
|
|
89
|
+
if (typeof URLSearchParams !== "undefined" && body instanceof URLSearchParams) {
|
|
90
|
+
if (!hasHeader(headers, "content-type")) headers["content-type"] = "application/x-www-form-urlencoded;charset=UTF-8";
|
|
91
|
+
return body.toString();
|
|
92
|
+
}
|
|
93
|
+
if (body instanceof ArrayBuffer) return cloneArrayBuffer(body);
|
|
94
|
+
if (ArrayBuffer.isView(body)) return cloneArrayBufferView(body);
|
|
95
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) {
|
|
96
|
+
if (body.type && !hasHeader(headers, "content-type")) headers["content-type"] = body.type;
|
|
97
|
+
return body.arrayBuffer();
|
|
98
|
+
}
|
|
99
|
+
if (typeof FormData !== "undefined" && body instanceof FormData) throw new TypeError("Failed to execute fetch: FormData body is not supported in request globals fetch");
|
|
100
|
+
return String(body);
|
|
101
|
+
}
|
|
102
|
+
async function resolveRequestMeta(input, init = {}) {
|
|
103
|
+
const requestInput = isRequestLikeInput(input) ? input : void 0;
|
|
104
|
+
const url = typeof input === "string" ? input : isNativeUrlInstance(input) ? input.toString() : requestInput?.url;
|
|
105
|
+
if (!url) throw new TypeError("Failed to execute fetch: invalid request url");
|
|
106
|
+
const method = normalizeMethod(init.method ?? requestInput?.method);
|
|
107
|
+
const headers = toHeaderMap(requestInput?.headers);
|
|
108
|
+
mergeHeaderSource(headers, init.headers);
|
|
109
|
+
const hasBodyInInit = hasOwn.call(init, "body");
|
|
110
|
+
let rawBody = hasBodyInInit ? init.body : await extractRequestBodyFromInput(requestInput);
|
|
111
|
+
if (!hasBodyInInit && requestInput && (method === "GET" || method === "HEAD")) rawBody = void 0;
|
|
112
|
+
if ((method === "GET" || method === "HEAD") && rawBody != null) throw new TypeError("Failed to execute fetch: GET/HEAD request cannot have body");
|
|
113
|
+
return {
|
|
114
|
+
url,
|
|
115
|
+
method,
|
|
116
|
+
headers,
|
|
117
|
+
body: await normalizeRequestBody(rawBody, headers),
|
|
118
|
+
signal: init.signal ?? requestInput?.signal ?? null
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
function createFetchResponse(data, status, headers, url) {
|
|
122
|
+
return new ResponsePolyfill(data instanceof Uint8Array ? cloneArrayBufferView(data) : data, {
|
|
123
|
+
status,
|
|
124
|
+
headers: new HeadersPolyfill(headers),
|
|
125
|
+
url
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
function isRequestTask(value) {
|
|
129
|
+
return isObject(value) && typeof value.abort === "function";
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* @description 使用 @wevu/api 的 request 能力实现 fetch 语义对齐。
|
|
133
|
+
*/
|
|
134
|
+
function fetch(input, init) {
|
|
135
|
+
return resolveRequestMeta(input, init).then((meta) => {
|
|
136
|
+
if (meta.signal?.aborted) return Promise.reject(createAbortError());
|
|
137
|
+
return new Promise((resolve, reject) => {
|
|
138
|
+
let settled = false;
|
|
139
|
+
let aborted = false;
|
|
140
|
+
let requestTask;
|
|
141
|
+
function onAbort() {
|
|
142
|
+
if (settled) return;
|
|
143
|
+
aborted = true;
|
|
144
|
+
requestTask?.abort();
|
|
145
|
+
settled = true;
|
|
146
|
+
if (meta.signal) meta.signal.removeEventListener("abort", onAbort);
|
|
147
|
+
reject(createAbortError());
|
|
148
|
+
}
|
|
149
|
+
function cleanup() {
|
|
150
|
+
if (meta.signal) meta.signal.removeEventListener("abort", onAbort);
|
|
151
|
+
}
|
|
152
|
+
if (meta.signal) meta.signal.addEventListener("abort", onAbort, { once: true });
|
|
153
|
+
const requestResult = wpi.request({
|
|
154
|
+
url: meta.url,
|
|
155
|
+
method: meta.method,
|
|
156
|
+
header: meta.headers,
|
|
157
|
+
data: meta.body,
|
|
158
|
+
responseType: "arraybuffer",
|
|
159
|
+
success: (res) => {
|
|
160
|
+
if (settled) return;
|
|
161
|
+
settled = true;
|
|
162
|
+
cleanup();
|
|
163
|
+
resolve(createFetchResponse(res.data, res.statusCode, toHeaderMap(res.header), meta.url));
|
|
164
|
+
},
|
|
165
|
+
fail: (error) => {
|
|
166
|
+
if (settled) return;
|
|
167
|
+
settled = true;
|
|
168
|
+
cleanup();
|
|
169
|
+
if (aborted) {
|
|
170
|
+
reject(createAbortError());
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
const message = isObject(error) && typeof error.errMsg === "string" ? error.errMsg : String(error);
|
|
174
|
+
reject(new TypeError(message));
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
requestTask = isRequestTask(requestResult) ? requestResult : void 0;
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
//#endregion
|
|
182
|
+
export { fetch };
|
package/dist/http.d.mts
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
//#region src/http.d.ts
|
|
2
|
+
type HeaderRecord = Record<string, string>;
|
|
3
|
+
declare class HeadersPolyfill {
|
|
4
|
+
private readonly store;
|
|
5
|
+
constructor(init?: unknown);
|
|
6
|
+
append(key: string, value: string): void;
|
|
7
|
+
set(key: string, value: string): void;
|
|
8
|
+
get(key: string): string | null;
|
|
9
|
+
has(key: string): boolean;
|
|
10
|
+
delete(key: string): void;
|
|
11
|
+
forEach(callback: (value: string, key: string) => void): void;
|
|
12
|
+
entries(): ArrayIterator<[string, string]>;
|
|
13
|
+
keys(): ArrayIterator<string>;
|
|
14
|
+
values(): ArrayIterator<string>;
|
|
15
|
+
[Symbol.iterator](): ArrayIterator<[string, string]>;
|
|
16
|
+
}
|
|
17
|
+
type RequestBodyLike = string | ArrayBuffer | ArrayBufferView | Blob | null | undefined;
|
|
18
|
+
declare class RequestPolyfill {
|
|
19
|
+
readonly url: string;
|
|
20
|
+
readonly method: string;
|
|
21
|
+
readonly headers: HeadersPolyfill;
|
|
22
|
+
readonly signal: AbortSignal | null;
|
|
23
|
+
readonly [Symbol.toStringTag] = "Request";
|
|
24
|
+
private readonly bodyValue;
|
|
25
|
+
bodyUsed: boolean;
|
|
26
|
+
constructor(input: string | URL | RequestPolyfill, init?: Record<string, any>);
|
|
27
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
28
|
+
text(): Promise<string>;
|
|
29
|
+
clone(): RequestPolyfill;
|
|
30
|
+
}
|
|
31
|
+
declare class ResponsePolyfill {
|
|
32
|
+
readonly headers: HeadersPolyfill;
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly statusText: string;
|
|
35
|
+
readonly ok: boolean;
|
|
36
|
+
readonly url: string;
|
|
37
|
+
readonly redirected = false;
|
|
38
|
+
readonly type: ResponseType;
|
|
39
|
+
readonly body: ReadableStream<Uint8Array> | null;
|
|
40
|
+
readonly [Symbol.toStringTag] = "Response";
|
|
41
|
+
private readonly bodyValue;
|
|
42
|
+
bodyUsed: boolean;
|
|
43
|
+
constructor(body?: RequestBodyLike, init?: Record<string, any>);
|
|
44
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
45
|
+
blob(): Promise<Blob>;
|
|
46
|
+
formData(): Promise<void>;
|
|
47
|
+
json(): Promise<any>;
|
|
48
|
+
text(): Promise<string>;
|
|
49
|
+
clone(): ResponsePolyfill;
|
|
50
|
+
}
|
|
51
|
+
declare function headersToObject(headers: HeadersPolyfill | Headers): HeaderRecord;
|
|
52
|
+
//#endregion
|
|
53
|
+
export { HeadersPolyfill, RequestPolyfill, ResponsePolyfill, headersToObject };
|
package/dist/http.mjs
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { cloneArrayBuffer, cloneArrayBufferView, decodeText, encodeText, normalizeHeaderName } from "./shared.mjs";
|
|
2
|
+
//#region src/http.ts
|
|
3
|
+
function isIterableHeaders(input) {
|
|
4
|
+
return Boolean(input) && typeof input[Symbol.iterator] === "function";
|
|
5
|
+
}
|
|
6
|
+
function isHeaderObject(input) {
|
|
7
|
+
return typeof input === "object" && input !== null;
|
|
8
|
+
}
|
|
9
|
+
function isNativeUrlInstance(value) {
|
|
10
|
+
return typeof URL !== "undefined" && value instanceof URL;
|
|
11
|
+
}
|
|
12
|
+
var HeadersPolyfill = class {
|
|
13
|
+
store = /* @__PURE__ */ new Map();
|
|
14
|
+
constructor(init) {
|
|
15
|
+
if (!init) return;
|
|
16
|
+
if (typeof init.forEach === "function") {
|
|
17
|
+
init.forEach((value, key) => {
|
|
18
|
+
this.set(key, value);
|
|
19
|
+
});
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (isIterableHeaders(init)) {
|
|
23
|
+
for (const [key, value] of init) this.append(key, value);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (isHeaderObject(init)) for (const [key, value] of Object.entries(init)) this.append(key, Array.isArray(value) ? value.join(", ") : String(value));
|
|
27
|
+
}
|
|
28
|
+
append(key, value) {
|
|
29
|
+
const current = this.get(key);
|
|
30
|
+
this.set(key, current ? `${current}, ${value}` : value);
|
|
31
|
+
}
|
|
32
|
+
set(key, value) {
|
|
33
|
+
const normalized = normalizeHeaderName(key);
|
|
34
|
+
if (!normalized) return;
|
|
35
|
+
this.store.set(normalized, {
|
|
36
|
+
key,
|
|
37
|
+
value: String(value)
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
get(key) {
|
|
41
|
+
return this.store.get(normalizeHeaderName(key))?.value ?? null;
|
|
42
|
+
}
|
|
43
|
+
has(key) {
|
|
44
|
+
return this.store.has(normalizeHeaderName(key));
|
|
45
|
+
}
|
|
46
|
+
delete(key) {
|
|
47
|
+
this.store.delete(normalizeHeaderName(key));
|
|
48
|
+
}
|
|
49
|
+
forEach(callback) {
|
|
50
|
+
for (const { key, value } of this.store.values()) callback(value, key);
|
|
51
|
+
}
|
|
52
|
+
entries() {
|
|
53
|
+
return Array.from(this.store.values(), (item) => [item.key, item.value])[Symbol.iterator]();
|
|
54
|
+
}
|
|
55
|
+
keys() {
|
|
56
|
+
return Array.from(this.store.values(), (item) => item.key)[Symbol.iterator]();
|
|
57
|
+
}
|
|
58
|
+
values() {
|
|
59
|
+
return Array.from(this.store.values(), (item) => item.value)[Symbol.iterator]();
|
|
60
|
+
}
|
|
61
|
+
[Symbol.iterator]() {
|
|
62
|
+
return this.entries();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
function normalizeBody(body) {
|
|
66
|
+
if (body == null || typeof body === "string" || body instanceof ArrayBuffer || ArrayBuffer.isView(body)) return body;
|
|
67
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) return body;
|
|
68
|
+
return String(body);
|
|
69
|
+
}
|
|
70
|
+
async function readBodyAsArrayBuffer(body) {
|
|
71
|
+
if (body == null) return /* @__PURE__ */ new ArrayBuffer(0);
|
|
72
|
+
if (typeof body === "string") return encodeText(body);
|
|
73
|
+
if (body instanceof ArrayBuffer) return cloneArrayBuffer(body);
|
|
74
|
+
if (ArrayBuffer.isView(body)) return cloneArrayBufferView(body);
|
|
75
|
+
if (typeof Blob !== "undefined" && body instanceof Blob) return body.arrayBuffer();
|
|
76
|
+
return encodeText(String(body));
|
|
77
|
+
}
|
|
78
|
+
async function readBodyAsText(body) {
|
|
79
|
+
if (typeof body === "string") return body;
|
|
80
|
+
return decodeText(await readBodyAsArrayBuffer(body));
|
|
81
|
+
}
|
|
82
|
+
var RequestPolyfill = class RequestPolyfill {
|
|
83
|
+
url;
|
|
84
|
+
method;
|
|
85
|
+
headers;
|
|
86
|
+
signal;
|
|
87
|
+
[Symbol.toStringTag] = "Request";
|
|
88
|
+
bodyValue;
|
|
89
|
+
bodyUsed = false;
|
|
90
|
+
constructor(input, init = {}) {
|
|
91
|
+
const request = input instanceof RequestPolyfill ? input : void 0;
|
|
92
|
+
this.url = typeof input === "string" ? input : isNativeUrlInstance(input) ? input.toString() : request?.url ?? "";
|
|
93
|
+
this.method = String(init.method ?? request?.method ?? "GET").toUpperCase();
|
|
94
|
+
this.headers = new HeadersPolyfill(init.headers ?? request?.headers);
|
|
95
|
+
this.signal = init.signal ?? request?.signal ?? null;
|
|
96
|
+
this.bodyValue = normalizeBody(init.body ?? request?.bodyValue);
|
|
97
|
+
}
|
|
98
|
+
async arrayBuffer() {
|
|
99
|
+
this.bodyUsed = true;
|
|
100
|
+
return readBodyAsArrayBuffer(this.bodyValue);
|
|
101
|
+
}
|
|
102
|
+
async text() {
|
|
103
|
+
this.bodyUsed = true;
|
|
104
|
+
return readBodyAsText(this.bodyValue);
|
|
105
|
+
}
|
|
106
|
+
clone() {
|
|
107
|
+
return new RequestPolyfill(this.url, {
|
|
108
|
+
method: this.method,
|
|
109
|
+
headers: this.headers,
|
|
110
|
+
signal: this.signal,
|
|
111
|
+
body: this.bodyValue
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
var ResponsePolyfill = class ResponsePolyfill {
|
|
116
|
+
headers;
|
|
117
|
+
status;
|
|
118
|
+
statusText;
|
|
119
|
+
ok;
|
|
120
|
+
url;
|
|
121
|
+
redirected = false;
|
|
122
|
+
type = "basic";
|
|
123
|
+
body = null;
|
|
124
|
+
[Symbol.toStringTag] = "Response";
|
|
125
|
+
bodyValue;
|
|
126
|
+
bodyUsed = false;
|
|
127
|
+
constructor(body, init = {}) {
|
|
128
|
+
this.bodyValue = normalizeBody(body);
|
|
129
|
+
this.status = Number.isFinite(init.status) ? init.status : 200;
|
|
130
|
+
this.statusText = init.statusText ?? "";
|
|
131
|
+
this.ok = this.status >= 200 && this.status < 300;
|
|
132
|
+
this.headers = new HeadersPolyfill(init.headers);
|
|
133
|
+
this.url = init.url ?? "";
|
|
134
|
+
}
|
|
135
|
+
async arrayBuffer() {
|
|
136
|
+
this.bodyUsed = true;
|
|
137
|
+
return readBodyAsArrayBuffer(this.bodyValue);
|
|
138
|
+
}
|
|
139
|
+
async blob() {
|
|
140
|
+
if (typeof Blob !== "function") throw new TypeError("Blob is unavailable in current runtime");
|
|
141
|
+
return new Blob([await this.arrayBuffer()]);
|
|
142
|
+
}
|
|
143
|
+
async formData() {
|
|
144
|
+
throw new TypeError("formData is not supported in Response polyfill");
|
|
145
|
+
}
|
|
146
|
+
async json() {
|
|
147
|
+
return JSON.parse(await this.text());
|
|
148
|
+
}
|
|
149
|
+
async text() {
|
|
150
|
+
this.bodyUsed = true;
|
|
151
|
+
return readBodyAsText(this.bodyValue);
|
|
152
|
+
}
|
|
153
|
+
clone() {
|
|
154
|
+
return new ResponsePolyfill(this.bodyValue, {
|
|
155
|
+
status: this.status,
|
|
156
|
+
statusText: this.statusText,
|
|
157
|
+
headers: this.headers,
|
|
158
|
+
url: this.url
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
function headersToObject(headers) {
|
|
163
|
+
const result = {};
|
|
164
|
+
headers.forEach((value, key) => {
|
|
165
|
+
result[key] = value;
|
|
166
|
+
});
|
|
167
|
+
return result;
|
|
168
|
+
}
|
|
169
|
+
//#endregion
|
|
170
|
+
export { HeadersPolyfill, RequestPolyfill, ResponsePolyfill, headersToObject };
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { RequestGlobalsEventTarget } from "./shared.mjs";
|
|
2
|
+
import { AbortControllerPolyfill, AbortSignalPolyfill } from "./abort.mjs";
|
|
3
|
+
import { fetch } from "./fetch.mjs";
|
|
4
|
+
import { HeadersPolyfill, RequestPolyfill, ResponsePolyfill } from "./http.mjs";
|
|
5
|
+
import { URLPolyfill, URLSearchParamsPolyfill } from "./url.mjs";
|
|
6
|
+
import { BlobPolyfill, FormDataPolyfill } from "./web.mjs";
|
|
7
|
+
import { XMLHttpRequestPolyfill } from "./xhr.mjs";
|
|
8
|
+
|
|
9
|
+
//#region src/index.d.ts
|
|
10
|
+
type WeappInjectRequestGlobalsTarget = 'fetch' | 'Headers' | 'Request' | 'Response' | 'AbortController' | 'AbortSignal' | 'XMLHttpRequest';
|
|
11
|
+
interface InstallRequestGlobalsOptions {
|
|
12
|
+
targets?: WeappInjectRequestGlobalsTarget[];
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* @description 按需向小程序全局环境注入缺失的请求相关对象。
|
|
16
|
+
*/
|
|
17
|
+
declare function installRequestGlobals(options?: InstallRequestGlobalsOptions): Record<string, any>;
|
|
18
|
+
/**
|
|
19
|
+
* @description 仅安装 AbortController 与 AbortSignal 兼容层。
|
|
20
|
+
*/
|
|
21
|
+
declare function installAbortGlobals(): Record<string, any>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { AbortControllerPolyfill, AbortSignalPolyfill, BlobPolyfill, FormDataPolyfill, HeadersPolyfill, InstallRequestGlobalsOptions, RequestGlobalsEventTarget, RequestPolyfill, ResponsePolyfill, URLPolyfill, URLSearchParamsPolyfill, WeappInjectRequestGlobalsTarget, XMLHttpRequestPolyfill, fetch, installAbortGlobals, installRequestGlobals };
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { RequestGlobalsEventTarget, installRequestGlobalBinding, resolveRequestGlobalsHost, resolveRequestGlobalsHosts } from "./shared.mjs";
|
|
2
|
+
import { AbortControllerPolyfill, AbortSignalPolyfill } from "./abort.mjs";
|
|
3
|
+
import { HeadersPolyfill, RequestPolyfill, ResponsePolyfill } from "./http.mjs";
|
|
4
|
+
import { fetch } from "./fetch.mjs";
|
|
5
|
+
import { URLPolyfill, URLSearchParamsPolyfill } from "./url.mjs";
|
|
6
|
+
import { BlobPolyfill, FormDataPolyfill } from "./web.mjs";
|
|
7
|
+
import { XMLHttpRequestPolyfill } from "./xhr.mjs";
|
|
8
|
+
//#region src/index.ts
|
|
9
|
+
function installSingleTarget(host, target) {
|
|
10
|
+
if (target === "fetch") {
|
|
11
|
+
if (typeof host.fetch !== "function") host.fetch = fetch;
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
if (target === "Headers") {
|
|
15
|
+
if (typeof host.Headers !== "function") host.Headers = HeadersPolyfill;
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (target === "Request") {
|
|
19
|
+
if (typeof host.Request !== "function") host.Request = RequestPolyfill;
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
if (target === "Response") {
|
|
23
|
+
if (typeof host.Response !== "function") host.Response = ResponsePolyfill;
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (target === "AbortController") {
|
|
27
|
+
if (typeof host.AbortController !== "function") host.AbortController = AbortControllerPolyfill;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (target === "AbortSignal") {
|
|
31
|
+
if (typeof host.AbortSignal !== "function") host.AbortSignal = AbortSignalPolyfill;
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
if (target === "XMLHttpRequest" && typeof host.XMLHttpRequest !== "function") host.XMLHttpRequest = XMLHttpRequestPolyfill;
|
|
35
|
+
}
|
|
36
|
+
function installUrlGlobals(host) {
|
|
37
|
+
if (typeof host.URL !== "function") host.URL = URLPolyfill;
|
|
38
|
+
if (typeof host.URLSearchParams !== "function") host.URLSearchParams = URLSearchParamsPolyfill;
|
|
39
|
+
if (typeof host.Blob !== "function") host.Blob = BlobPolyfill;
|
|
40
|
+
if (typeof host.FormData !== "function") host.FormData = FormDataPolyfill;
|
|
41
|
+
}
|
|
42
|
+
function installGlobalBindingIfNeeded(host, target) {
|
|
43
|
+
const value = host[target];
|
|
44
|
+
if (value == null) return;
|
|
45
|
+
installRequestGlobalBinding(target, value);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* @description 按需向小程序全局环境注入缺失的请求相关对象。
|
|
49
|
+
*/
|
|
50
|
+
function installRequestGlobals(options = {}) {
|
|
51
|
+
const targets = options.targets ?? [
|
|
52
|
+
"fetch",
|
|
53
|
+
"Headers",
|
|
54
|
+
"Request",
|
|
55
|
+
"Response",
|
|
56
|
+
"AbortController",
|
|
57
|
+
"AbortSignal",
|
|
58
|
+
"XMLHttpRequest"
|
|
59
|
+
];
|
|
60
|
+
const hosts = resolveRequestGlobalsHosts();
|
|
61
|
+
const primaryHost = resolveRequestGlobalsHost();
|
|
62
|
+
const needsUrlGlobals = targets.some((target) => target === "fetch" || target === "Request" || target === "Response" || target === "XMLHttpRequest");
|
|
63
|
+
for (const host of hosts) {
|
|
64
|
+
if (needsUrlGlobals) installUrlGlobals(host);
|
|
65
|
+
for (const target of targets) installSingleTarget(host, target);
|
|
66
|
+
}
|
|
67
|
+
if (needsUrlGlobals) {
|
|
68
|
+
installGlobalBindingIfNeeded(primaryHost, "URL");
|
|
69
|
+
installGlobalBindingIfNeeded(primaryHost, "URLSearchParams");
|
|
70
|
+
installGlobalBindingIfNeeded(primaryHost, "Blob");
|
|
71
|
+
installGlobalBindingIfNeeded(primaryHost, "FormData");
|
|
72
|
+
}
|
|
73
|
+
for (const target of targets) installGlobalBindingIfNeeded(primaryHost, target);
|
|
74
|
+
return hosts[0];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* @description 仅安装 AbortController 与 AbortSignal 兼容层。
|
|
78
|
+
*/
|
|
79
|
+
function installAbortGlobals() {
|
|
80
|
+
return installRequestGlobals({ targets: ["AbortController", "AbortSignal"] });
|
|
81
|
+
}
|
|
82
|
+
//#endregion
|
|
83
|
+
export { AbortControllerPolyfill, AbortSignalPolyfill, BlobPolyfill, FormDataPolyfill, HeadersPolyfill, RequestGlobalsEventTarget, RequestPolyfill, ResponsePolyfill, URLPolyfill, URLSearchParamsPolyfill, XMLHttpRequestPolyfill, fetch, installAbortGlobals, installRequestGlobals };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
//#region src/shared.d.ts
|
|
2
|
+
interface RequestGlobalsEventLike {
|
|
3
|
+
type: string;
|
|
4
|
+
target?: unknown;
|
|
5
|
+
currentTarget?: unknown;
|
|
6
|
+
}
|
|
7
|
+
interface RequestGlobalsEventTargetLike {
|
|
8
|
+
addEventListener: (type: string, listener: (event: RequestGlobalsEventLike) => void) => void;
|
|
9
|
+
removeEventListener: (type: string, listener: (event: RequestGlobalsEventLike) => void) => void;
|
|
10
|
+
dispatchEvent: (event: RequestGlobalsEventLike) => boolean;
|
|
11
|
+
}
|
|
12
|
+
type EventListener = (event: RequestGlobalsEventLike) => void;
|
|
13
|
+
declare class RequestGlobalsEventTarget implements RequestGlobalsEventTargetLike {
|
|
14
|
+
private readonly listeners;
|
|
15
|
+
addEventListener(type: string, listener: EventListener): void;
|
|
16
|
+
removeEventListener(type: string, listener: EventListener): void;
|
|
17
|
+
dispatchEvent(event: RequestGlobalsEventLike): boolean;
|
|
18
|
+
}
|
|
19
|
+
declare function resolveRequestGlobalsHost(): Record<string, any>;
|
|
20
|
+
declare function resolveRequestGlobalsHosts(): Record<string, any>[];
|
|
21
|
+
declare function installRequestGlobalBinding(name: string, value: unknown): void;
|
|
22
|
+
declare function cloneArrayBuffer(buffer: ArrayBuffer): ArrayBuffer;
|
|
23
|
+
declare function cloneArrayBufferView(view: ArrayBufferView): ArrayBuffer;
|
|
24
|
+
declare function encodeText(value: string): ArrayBuffer;
|
|
25
|
+
declare function decodeText(value: ArrayBuffer): string;
|
|
26
|
+
declare function normalizeHeaderName(name: string): string;
|
|
27
|
+
//#endregion
|
|
28
|
+
export { RequestGlobalsEventLike, RequestGlobalsEventTarget, RequestGlobalsEventTargetLike, cloneArrayBuffer, cloneArrayBufferView, decodeText, encodeText, installRequestGlobalBinding, normalizeHeaderName, resolveRequestGlobalsHost, resolveRequestGlobalsHosts };
|