@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/dist/shared.mjs
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
//#region src/shared.ts
|
|
2
|
+
var RequestGlobalsEventTarget = class {
|
|
3
|
+
listeners = /* @__PURE__ */ new Map();
|
|
4
|
+
addEventListener(type, listener) {
|
|
5
|
+
const set = this.listeners.get(type) ?? /* @__PURE__ */ new Set();
|
|
6
|
+
set.add(listener);
|
|
7
|
+
this.listeners.set(type, set);
|
|
8
|
+
}
|
|
9
|
+
removeEventListener(type, listener) {
|
|
10
|
+
this.listeners.get(type)?.delete(listener);
|
|
11
|
+
}
|
|
12
|
+
dispatchEvent(event) {
|
|
13
|
+
const payload = {
|
|
14
|
+
...event,
|
|
15
|
+
target: event.target ?? this,
|
|
16
|
+
currentTarget: event.currentTarget ?? this
|
|
17
|
+
};
|
|
18
|
+
for (const listener of this.listeners.get(event.type) ?? []) listener(payload);
|
|
19
|
+
const handlerKey = `on${event.type}`;
|
|
20
|
+
const handler = this[handlerKey];
|
|
21
|
+
if (typeof handler === "function") handler(payload);
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
function resolveRequestGlobalsHost() {
|
|
26
|
+
if (typeof globalThis !== "undefined") return globalThis;
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
function resolveRequestGlobalsHosts() {
|
|
30
|
+
const hosts = [];
|
|
31
|
+
const primaryHost = resolveRequestGlobalsHost();
|
|
32
|
+
hosts.push(primaryHost);
|
|
33
|
+
for (const key of [
|
|
34
|
+
"wx",
|
|
35
|
+
"my",
|
|
36
|
+
"tt"
|
|
37
|
+
]) {
|
|
38
|
+
const candidate = primaryHost[key];
|
|
39
|
+
if (candidate && typeof candidate === "object" && !hosts.includes(candidate)) hosts.push(candidate);
|
|
40
|
+
}
|
|
41
|
+
return hosts;
|
|
42
|
+
}
|
|
43
|
+
function installRequestGlobalBinding(name, value) {
|
|
44
|
+
if (!name) return;
|
|
45
|
+
try {
|
|
46
|
+
Function("__weappRequestGlobalValue__", `${name} = __weappRequestGlobalValue__`)(value);
|
|
47
|
+
} catch {}
|
|
48
|
+
}
|
|
49
|
+
function cloneArrayBuffer(buffer) {
|
|
50
|
+
return buffer.slice(0);
|
|
51
|
+
}
|
|
52
|
+
function cloneArrayBufferView(view) {
|
|
53
|
+
const copied = new Uint8Array(view.byteLength);
|
|
54
|
+
copied.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
|
|
55
|
+
return copied.buffer;
|
|
56
|
+
}
|
|
57
|
+
function encodeText(value) {
|
|
58
|
+
if (typeof TextEncoder === "function") return new TextEncoder().encode(value).buffer;
|
|
59
|
+
const bytes = new Uint8Array(value.length);
|
|
60
|
+
for (let i = 0; i < value.length; i++) bytes[i] = value.charCodeAt(i) & 255;
|
|
61
|
+
return bytes.buffer;
|
|
62
|
+
}
|
|
63
|
+
function decodeText(value) {
|
|
64
|
+
if (typeof TextDecoder === "function") return new TextDecoder().decode(value);
|
|
65
|
+
let text = "";
|
|
66
|
+
for (const byte of new Uint8Array(value)) text += String.fromCharCode(byte);
|
|
67
|
+
return text;
|
|
68
|
+
}
|
|
69
|
+
function normalizeHeaderName(name) {
|
|
70
|
+
return name.trim().toLowerCase();
|
|
71
|
+
}
|
|
72
|
+
//#endregion
|
|
73
|
+
export { RequestGlobalsEventTarget, cloneArrayBuffer, cloneArrayBufferView, decodeText, encodeText, installRequestGlobalBinding, normalizeHeaderName, resolveRequestGlobalsHost, resolveRequestGlobalsHosts };
|
package/dist/url.d.mts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
//#region src/url.d.ts
|
|
2
|
+
type URLSearchParamValue = string | readonly string[];
|
|
3
|
+
declare class URLSearchParamsPolyfill {
|
|
4
|
+
private readonly onChange?;
|
|
5
|
+
private readonly entriesStore;
|
|
6
|
+
constructor(init?: string | URLSearchParamsPolyfill | Record<string, URLSearchParamValue> | Iterable<[string, string]>, onChange?: (() => void) | undefined);
|
|
7
|
+
append(key: string, value: string): void;
|
|
8
|
+
delete(key: string): void;
|
|
9
|
+
get(key: string): string | null;
|
|
10
|
+
getAll(key: string): string[];
|
|
11
|
+
has(key: string): boolean;
|
|
12
|
+
set(key: string, value: string): void;
|
|
13
|
+
forEach(callback: (value: string, key: string) => void): void;
|
|
14
|
+
entries(): ArrayIterator<[string, string]>;
|
|
15
|
+
keys(): ArrayIterator<string>;
|
|
16
|
+
values(): ArrayIterator<string>;
|
|
17
|
+
toString(): string;
|
|
18
|
+
[Symbol.iterator](): ArrayIterator<[string, string]>;
|
|
19
|
+
}
|
|
20
|
+
declare class URLPolyfill {
|
|
21
|
+
private hashValue;
|
|
22
|
+
private hrefValue;
|
|
23
|
+
private searchValue;
|
|
24
|
+
host: string;
|
|
25
|
+
hostname: string;
|
|
26
|
+
origin: string;
|
|
27
|
+
password: string;
|
|
28
|
+
pathname: string;
|
|
29
|
+
port: string;
|
|
30
|
+
protocol: string;
|
|
31
|
+
username: string;
|
|
32
|
+
readonly searchParams: URLSearchParamsPolyfill;
|
|
33
|
+
constructor(input: string | URLPolyfill, base?: string | URLPolyfill);
|
|
34
|
+
get hash(): string;
|
|
35
|
+
set hash(value: string);
|
|
36
|
+
get href(): string;
|
|
37
|
+
get search(): string;
|
|
38
|
+
set search(value: string);
|
|
39
|
+
toString(): string;
|
|
40
|
+
toJSON(): string;
|
|
41
|
+
private resetSearchParams;
|
|
42
|
+
private updateHref;
|
|
43
|
+
private syncSearchFromParams;
|
|
44
|
+
}
|
|
45
|
+
//#endregion
|
|
46
|
+
export { URLPolyfill, URLSearchParamsPolyfill };
|
package/dist/url.mjs
ADDED
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
//#region src/url.ts
|
|
2
|
+
const PLUS_REGEXP = /\+/g;
|
|
3
|
+
const LEADING_QUERY_REGEXP = /^\?/;
|
|
4
|
+
const ABSOLUTE_URL_REGEXP = /^([a-z][a-z\d+.-]*:)?\/\/([^/?#]+)(\/[^?#]*)?(\?[^#]*)?(#.*)?$/i;
|
|
5
|
+
const ABSOLUTE_URL_PREFIX_REGEXP = /^[a-z][a-z\d+.-]*:\/\//i;
|
|
6
|
+
const ENCODED_SPACE_REGEXP = /%20/g;
|
|
7
|
+
const HOST_WITH_PORT_REGEXP = /^([^:]*)(?::(.*))?$/;
|
|
8
|
+
function encodeSearchParam(value) {
|
|
9
|
+
return encodeURIComponent(value).replace(ENCODED_SPACE_REGEXP, "+");
|
|
10
|
+
}
|
|
11
|
+
function decodeSearchParam(value) {
|
|
12
|
+
return decodeURIComponent(value.replace(PLUS_REGEXP, " "));
|
|
13
|
+
}
|
|
14
|
+
function normalizeSearchSource(input) {
|
|
15
|
+
return input.replace(LEADING_QUERY_REGEXP, "");
|
|
16
|
+
}
|
|
17
|
+
function parseSearchEntries(input) {
|
|
18
|
+
if (!input) return [];
|
|
19
|
+
return normalizeSearchSource(input).split("&").filter(Boolean).map((segment) => {
|
|
20
|
+
const separatorIndex = segment.indexOf("=");
|
|
21
|
+
if (separatorIndex === -1) return [decodeSearchParam(segment), ""];
|
|
22
|
+
return [decodeSearchParam(segment.slice(0, separatorIndex)), decodeSearchParam(segment.slice(separatorIndex + 1))];
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
function serializeSearchEntries(entries) {
|
|
26
|
+
return entries.map(([key, value]) => `${encodeSearchParam(key)}=${encodeSearchParam(value)}`).join("&");
|
|
27
|
+
}
|
|
28
|
+
function parseAbsoluteUrl(input) {
|
|
29
|
+
const match = input.match(ABSOLUTE_URL_REGEXP);
|
|
30
|
+
if (!match) return null;
|
|
31
|
+
const protocol = match[1] ?? "";
|
|
32
|
+
const host = match[2] ?? "";
|
|
33
|
+
const pathname = match[3] || "/";
|
|
34
|
+
const search = match[4] ?? "";
|
|
35
|
+
const hash = match[5] ?? "";
|
|
36
|
+
const hostnameMatch = host.match(HOST_WITH_PORT_REGEXP);
|
|
37
|
+
return {
|
|
38
|
+
protocol,
|
|
39
|
+
host,
|
|
40
|
+
hostname: hostnameMatch?.[1] ?? host,
|
|
41
|
+
port: hostnameMatch?.[2] ?? "",
|
|
42
|
+
pathname,
|
|
43
|
+
search,
|
|
44
|
+
hash,
|
|
45
|
+
origin: protocol && host ? `${protocol}//${host}` : "",
|
|
46
|
+
href: `${protocol}//${host}${pathname}${search}${hash}`
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
function resolveRelativeUrl(input, base) {
|
|
50
|
+
const parsedBase = parseAbsoluteUrl(base);
|
|
51
|
+
if (!parsedBase) throw new TypeError(`Failed to construct URL from base ${base}`);
|
|
52
|
+
if (input.startsWith("//")) return `${parsedBase.protocol}${input}`;
|
|
53
|
+
if (input.startsWith("/")) return `${parsedBase.origin}${input}`;
|
|
54
|
+
if (input.startsWith("?") || input.startsWith("#")) {
|
|
55
|
+
const pathname = parsedBase.pathname || "/";
|
|
56
|
+
return `${`${parsedBase.origin}${pathname}`}${input}`;
|
|
57
|
+
}
|
|
58
|
+
const basePathSegments = parsedBase.pathname.split("/").slice(0, -1);
|
|
59
|
+
for (const segment of input.split("/")) {
|
|
60
|
+
if (!segment || segment === ".") continue;
|
|
61
|
+
if (segment === "..") {
|
|
62
|
+
basePathSegments.pop();
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
basePathSegments.push(segment);
|
|
66
|
+
}
|
|
67
|
+
return `${parsedBase.origin}/${basePathSegments.join("/")}`;
|
|
68
|
+
}
|
|
69
|
+
var URLSearchParamsPolyfill = class {
|
|
70
|
+
entriesStore = [];
|
|
71
|
+
constructor(init, onChange) {
|
|
72
|
+
this.onChange = onChange;
|
|
73
|
+
if (!init) return;
|
|
74
|
+
if (typeof init === "string") {
|
|
75
|
+
this.entriesStore.push(...parseSearchEntries(init));
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
if (typeof init[Symbol.iterator] === "function") {
|
|
79
|
+
for (const [key, value] of init) this.append(key, value);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
for (const [key, value] of Object.entries(init)) {
|
|
83
|
+
if (Array.isArray(value)) {
|
|
84
|
+
for (const item of value) this.append(key, item);
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
this.append(key, value);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
append(key, value) {
|
|
91
|
+
this.entriesStore.push([String(key), String(value)]);
|
|
92
|
+
this.onChange?.();
|
|
93
|
+
}
|
|
94
|
+
delete(key) {
|
|
95
|
+
const normalizedKey = String(key);
|
|
96
|
+
let changed = false;
|
|
97
|
+
for (let i = this.entriesStore.length - 1; i >= 0; i--) if (this.entriesStore[i]?.[0] === normalizedKey) {
|
|
98
|
+
this.entriesStore.splice(i, 1);
|
|
99
|
+
changed = true;
|
|
100
|
+
}
|
|
101
|
+
if (changed) this.onChange?.();
|
|
102
|
+
}
|
|
103
|
+
get(key) {
|
|
104
|
+
const normalizedKey = String(key);
|
|
105
|
+
return this.entriesStore.find(([entryKey]) => entryKey === normalizedKey)?.[1] ?? null;
|
|
106
|
+
}
|
|
107
|
+
getAll(key) {
|
|
108
|
+
const normalizedKey = String(key);
|
|
109
|
+
return this.entriesStore.filter(([entryKey]) => entryKey === normalizedKey).map(([, value]) => value);
|
|
110
|
+
}
|
|
111
|
+
has(key) {
|
|
112
|
+
return this.entriesStore.some(([entryKey]) => entryKey === String(key));
|
|
113
|
+
}
|
|
114
|
+
set(key, value) {
|
|
115
|
+
this.delete(key);
|
|
116
|
+
this.append(key, value);
|
|
117
|
+
}
|
|
118
|
+
forEach(callback) {
|
|
119
|
+
for (const [key, value] of this.entriesStore) callback(value, key);
|
|
120
|
+
}
|
|
121
|
+
entries() {
|
|
122
|
+
return this.entriesStore[Symbol.iterator]();
|
|
123
|
+
}
|
|
124
|
+
keys() {
|
|
125
|
+
return this.entriesStore.map(([key]) => key)[Symbol.iterator]();
|
|
126
|
+
}
|
|
127
|
+
values() {
|
|
128
|
+
return this.entriesStore.map(([, value]) => value)[Symbol.iterator]();
|
|
129
|
+
}
|
|
130
|
+
toString() {
|
|
131
|
+
return serializeSearchEntries(this.entriesStore);
|
|
132
|
+
}
|
|
133
|
+
[Symbol.iterator]() {
|
|
134
|
+
return this.entries();
|
|
135
|
+
}
|
|
136
|
+
};
|
|
137
|
+
var URLPolyfill = class {
|
|
138
|
+
hashValue = "";
|
|
139
|
+
hrefValue = "";
|
|
140
|
+
searchValue = "";
|
|
141
|
+
host = "";
|
|
142
|
+
hostname = "";
|
|
143
|
+
origin = "";
|
|
144
|
+
password = "";
|
|
145
|
+
pathname = "/";
|
|
146
|
+
port = "";
|
|
147
|
+
protocol = "";
|
|
148
|
+
username = "";
|
|
149
|
+
searchParams;
|
|
150
|
+
constructor(input, base) {
|
|
151
|
+
const inputString = typeof input === "string" ? input : input.toString();
|
|
152
|
+
const baseString = typeof base === "string" ? base : base ? base.toString() : void 0;
|
|
153
|
+
const parsed = parseAbsoluteUrl(ABSOLUTE_URL_PREFIX_REGEXP.test(inputString) ? inputString : baseString ? resolveRelativeUrl(inputString, baseString) : inputString);
|
|
154
|
+
if (!parsed) throw new TypeError(`Failed to construct URL from ${inputString}`);
|
|
155
|
+
this.protocol = parsed.protocol;
|
|
156
|
+
this.host = parsed.host;
|
|
157
|
+
this.hostname = parsed.hostname;
|
|
158
|
+
this.port = parsed.port;
|
|
159
|
+
this.pathname = parsed.pathname;
|
|
160
|
+
this.searchValue = parsed.search;
|
|
161
|
+
this.hashValue = parsed.hash;
|
|
162
|
+
this.origin = parsed.origin;
|
|
163
|
+
this.searchParams = new URLSearchParamsPolyfill(parsed.search, () => {
|
|
164
|
+
this.syncSearchFromParams();
|
|
165
|
+
});
|
|
166
|
+
this.updateHref();
|
|
167
|
+
}
|
|
168
|
+
get hash() {
|
|
169
|
+
return this.hashValue;
|
|
170
|
+
}
|
|
171
|
+
set hash(value) {
|
|
172
|
+
this.hashValue = value ? value.startsWith("#") ? value : `#${value}` : "";
|
|
173
|
+
this.updateHref();
|
|
174
|
+
}
|
|
175
|
+
get href() {
|
|
176
|
+
return this.hrefValue;
|
|
177
|
+
}
|
|
178
|
+
get search() {
|
|
179
|
+
return this.searchValue;
|
|
180
|
+
}
|
|
181
|
+
set search(value) {
|
|
182
|
+
this.searchValue = value ? value.startsWith("?") ? value : `?${value}` : "";
|
|
183
|
+
this.resetSearchParams(this.searchValue);
|
|
184
|
+
this.updateHref();
|
|
185
|
+
}
|
|
186
|
+
toString() {
|
|
187
|
+
return this.hrefValue;
|
|
188
|
+
}
|
|
189
|
+
toJSON() {
|
|
190
|
+
return this.toString();
|
|
191
|
+
}
|
|
192
|
+
resetSearchParams(value) {
|
|
193
|
+
const nextParams = new URLSearchParamsPolyfill(value);
|
|
194
|
+
this.searchParams.entriesStore.splice(0, this.searchParams.entriesStore.length);
|
|
195
|
+
nextParams.forEach((entryValue, entryKey) => {
|
|
196
|
+
this.searchParams.entriesStore.push([entryKey, entryValue]);
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
updateHref() {
|
|
200
|
+
this.hrefValue = `${this.protocol}//${this.host}${this.pathname}${this.searchValue}${this.hashValue}`;
|
|
201
|
+
}
|
|
202
|
+
syncSearchFromParams() {
|
|
203
|
+
const search = this.searchParams.toString();
|
|
204
|
+
this.searchValue = search ? `?${search}` : "";
|
|
205
|
+
this.updateHref();
|
|
206
|
+
}
|
|
207
|
+
};
|
|
208
|
+
//#endregion
|
|
209
|
+
export { URLPolyfill, URLSearchParamsPolyfill };
|
package/dist/web.d.mts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
//#region src/web.d.ts
|
|
2
|
+
type BlobPart = ArrayBuffer | ArrayBufferView | BlobPolyfill | string;
|
|
3
|
+
declare class BlobPolyfill {
|
|
4
|
+
readonly size: number;
|
|
5
|
+
readonly type: string;
|
|
6
|
+
private readonly parts;
|
|
7
|
+
constructor(parts?: BlobPart[], options?: {
|
|
8
|
+
type?: string;
|
|
9
|
+
});
|
|
10
|
+
arrayBuffer(): Promise<any>;
|
|
11
|
+
text(): Promise<string>;
|
|
12
|
+
}
|
|
13
|
+
type FormDataEntryValue = BlobPolyfill | string;
|
|
14
|
+
declare class FormDataPolyfill {
|
|
15
|
+
private readonly entriesList;
|
|
16
|
+
append(name: string, value: FormDataEntryValue): void;
|
|
17
|
+
delete(name: string): void;
|
|
18
|
+
get(name: string): FormDataEntryValue | null;
|
|
19
|
+
getAll(name: string): FormDataEntryValue[];
|
|
20
|
+
has(name: string): boolean;
|
|
21
|
+
set(name: string, value: FormDataEntryValue): void;
|
|
22
|
+
forEach(callback: (value: FormDataEntryValue, key: string, parent: FormDataPolyfill) => void): void;
|
|
23
|
+
entries(): Generator<[string, FormDataEntryValue], void, unknown>;
|
|
24
|
+
keys(): Generator<string, void, unknown>;
|
|
25
|
+
values(): Generator<FormDataEntryValue, void, unknown>;
|
|
26
|
+
[Symbol.iterator](): Generator<[string, FormDataEntryValue], void, unknown>;
|
|
27
|
+
get [Symbol.toStringTag](): string;
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
export { BlobPolyfill, FormDataPolyfill };
|
package/dist/web.mjs
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { cloneArrayBuffer, cloneArrayBufferView, decodeText, encodeText } from "./shared.mjs";
|
|
2
|
+
//#region src/web.ts
|
|
3
|
+
function normalizeBlobPart(part) {
|
|
4
|
+
if (typeof part === "string") return encodeText(part);
|
|
5
|
+
if (part && typeof part === "object" && typeof part.arrayBuffer === "function") return part.arrayBuffer();
|
|
6
|
+
if (part instanceof ArrayBuffer) return Promise.resolve(cloneArrayBuffer(part));
|
|
7
|
+
if (ArrayBuffer.isView(part)) return Promise.resolve(cloneArrayBufferView(part));
|
|
8
|
+
return Promise.resolve(encodeText(String(part)));
|
|
9
|
+
}
|
|
10
|
+
var BlobPolyfill = class BlobPolyfill {
|
|
11
|
+
size;
|
|
12
|
+
type;
|
|
13
|
+
parts;
|
|
14
|
+
constructor(parts = [], options) {
|
|
15
|
+
this.parts = [...parts];
|
|
16
|
+
this.type = options?.type ?? "";
|
|
17
|
+
this.size = parts.reduce((total, part) => {
|
|
18
|
+
if (typeof part === "string") return total + String(part).length;
|
|
19
|
+
if (part instanceof BlobPolyfill) return total + part.size;
|
|
20
|
+
if (part instanceof ArrayBuffer) return total + part.byteLength;
|
|
21
|
+
if (ArrayBuffer.isView(part)) return total + part.byteLength;
|
|
22
|
+
return total;
|
|
23
|
+
}, 0);
|
|
24
|
+
}
|
|
25
|
+
async arrayBuffer() {
|
|
26
|
+
const buffers = await Promise.all(this.parts.map((part) => normalizeBlobPart(part)));
|
|
27
|
+
const totalLength = buffers.reduce((sum, buffer) => sum + buffer.byteLength, 0);
|
|
28
|
+
const merged = new Uint8Array(totalLength);
|
|
29
|
+
let offset = 0;
|
|
30
|
+
for (const buffer of buffers) {
|
|
31
|
+
merged.set(new Uint8Array(buffer), offset);
|
|
32
|
+
offset += buffer.byteLength;
|
|
33
|
+
}
|
|
34
|
+
return merged.buffer;
|
|
35
|
+
}
|
|
36
|
+
async text() {
|
|
37
|
+
return decodeText(await this.arrayBuffer());
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var FormDataPolyfill = class {
|
|
41
|
+
entriesList = [];
|
|
42
|
+
append(name, value) {
|
|
43
|
+
this.entriesList.push([String(name), value instanceof BlobPolyfill ? value : String(value)]);
|
|
44
|
+
}
|
|
45
|
+
delete(name) {
|
|
46
|
+
const normalizedName = String(name);
|
|
47
|
+
let index = this.entriesList.length;
|
|
48
|
+
while (index-- > 0) if (this.entriesList[index]?.[0] === normalizedName) this.entriesList.splice(index, 1);
|
|
49
|
+
}
|
|
50
|
+
get(name) {
|
|
51
|
+
return this.entriesList.find((entry) => entry[0] === String(name))?.[1] ?? null;
|
|
52
|
+
}
|
|
53
|
+
getAll(name) {
|
|
54
|
+
return this.entriesList.filter((entry) => entry[0] === String(name)).map((entry) => entry[1]);
|
|
55
|
+
}
|
|
56
|
+
has(name) {
|
|
57
|
+
return this.entriesList.some((entry) => entry[0] === String(name));
|
|
58
|
+
}
|
|
59
|
+
set(name, value) {
|
|
60
|
+
this.delete(name);
|
|
61
|
+
this.append(name, value);
|
|
62
|
+
}
|
|
63
|
+
forEach(callback) {
|
|
64
|
+
for (const [key, value] of this.entriesList) callback(value, key, this);
|
|
65
|
+
}
|
|
66
|
+
*entries() {
|
|
67
|
+
yield* this.entriesList;
|
|
68
|
+
}
|
|
69
|
+
*keys() {
|
|
70
|
+
for (const [key] of this.entriesList) yield key;
|
|
71
|
+
}
|
|
72
|
+
*values() {
|
|
73
|
+
for (const [, value] of this.entriesList) yield value;
|
|
74
|
+
}
|
|
75
|
+
[Symbol.iterator]() {
|
|
76
|
+
return this.entries();
|
|
77
|
+
}
|
|
78
|
+
get [Symbol.toStringTag]() {
|
|
79
|
+
return "FormData";
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
//#endregion
|
|
83
|
+
export { BlobPolyfill, FormDataPolyfill };
|
package/dist/xhr.d.mts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { RequestGlobalsEventTarget } from "./shared.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/xhr.d.ts
|
|
4
|
+
type XhrBody = Document | XMLHttpRequestBodyInit | null | undefined;
|
|
5
|
+
declare class XMLHttpRequestUploadPolyfill extends RequestGlobalsEventTarget {}
|
|
6
|
+
declare class XMLHttpRequestPolyfill extends RequestGlobalsEventTarget {
|
|
7
|
+
static readonly UNSENT = 0;
|
|
8
|
+
static readonly OPENED = 1;
|
|
9
|
+
static readonly HEADERS_RECEIVED = 2;
|
|
10
|
+
static readonly LOADING = 3;
|
|
11
|
+
static readonly DONE = 4;
|
|
12
|
+
readonly UNSENT = 0;
|
|
13
|
+
readonly OPENED = 1;
|
|
14
|
+
readonly HEADERS_RECEIVED = 2;
|
|
15
|
+
readonly LOADING = 3;
|
|
16
|
+
readonly DONE = 4;
|
|
17
|
+
readonly upload: XMLHttpRequestUploadPolyfill;
|
|
18
|
+
readyState: number;
|
|
19
|
+
response: any;
|
|
20
|
+
responseText: string;
|
|
21
|
+
responseType: XMLHttpRequestResponseType;
|
|
22
|
+
responseURL: string;
|
|
23
|
+
status: number;
|
|
24
|
+
statusText: string;
|
|
25
|
+
timeout: number;
|
|
26
|
+
withCredentials: boolean;
|
|
27
|
+
onreadystatechange: ((event: {
|
|
28
|
+
type: string;
|
|
29
|
+
}) => void) | null;
|
|
30
|
+
onabort: ((event: {
|
|
31
|
+
type: string;
|
|
32
|
+
}) => void) | null;
|
|
33
|
+
onerror: ((event: {
|
|
34
|
+
type: string;
|
|
35
|
+
}) => void) | null;
|
|
36
|
+
onload: ((event: {
|
|
37
|
+
type: string;
|
|
38
|
+
}) => void) | null;
|
|
39
|
+
onloadend: ((event: {
|
|
40
|
+
type: string;
|
|
41
|
+
}) => void) | null;
|
|
42
|
+
onloadstart: ((event: {
|
|
43
|
+
type: string;
|
|
44
|
+
}) => void) | null;
|
|
45
|
+
onprogress: ((event: {
|
|
46
|
+
type: string;
|
|
47
|
+
}) => void) | null;
|
|
48
|
+
ontimeout: ((event: {
|
|
49
|
+
type: string;
|
|
50
|
+
}) => void) | null;
|
|
51
|
+
private method;
|
|
52
|
+
private url;
|
|
53
|
+
private readonly requestHeaders;
|
|
54
|
+
private responseHeaders;
|
|
55
|
+
private requestController;
|
|
56
|
+
private timeoutId;
|
|
57
|
+
private sent;
|
|
58
|
+
open(method: string, url: string): void;
|
|
59
|
+
setRequestHeader(key: string, value: string): void;
|
|
60
|
+
getAllResponseHeaders(): string;
|
|
61
|
+
getResponseHeader(key: string): string | null;
|
|
62
|
+
abort(): void;
|
|
63
|
+
send(body?: XhrBody): Promise<void>;
|
|
64
|
+
private finish;
|
|
65
|
+
private transitionTo;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
export { XMLHttpRequestPolyfill, XMLHttpRequestUploadPolyfill };
|
package/dist/xhr.mjs
ADDED
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { RequestGlobalsEventTarget, resolveRequestGlobalsHost } from "./shared.mjs";
|
|
2
|
+
import { AbortControllerPolyfill } from "./abort.mjs";
|
|
3
|
+
import { HeadersPolyfill, headersToObject } from "./http.mjs";
|
|
4
|
+
import { fetch } from "./fetch.mjs";
|
|
5
|
+
//#region src/xhr.ts
|
|
6
|
+
function createProgressEvent(type) {
|
|
7
|
+
return {
|
|
8
|
+
type,
|
|
9
|
+
lengthComputable: false,
|
|
10
|
+
loaded: 0,
|
|
11
|
+
total: 0
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
function createError(type) {
|
|
15
|
+
const error = new Error(type);
|
|
16
|
+
error.name = type === "abort" ? "AbortError" : type === "timeout" ? "TimeoutError" : "NetworkError";
|
|
17
|
+
return error;
|
|
18
|
+
}
|
|
19
|
+
function resolveFetch() {
|
|
20
|
+
const host = resolveRequestGlobalsHost();
|
|
21
|
+
return typeof host.fetch === "function" ? host.fetch.bind(host) : fetch;
|
|
22
|
+
}
|
|
23
|
+
var XMLHttpRequestUploadPolyfill = class extends RequestGlobalsEventTarget {};
|
|
24
|
+
var XMLHttpRequestPolyfill = class XMLHttpRequestPolyfill extends RequestGlobalsEventTarget {
|
|
25
|
+
static UNSENT = 0;
|
|
26
|
+
static OPENED = 1;
|
|
27
|
+
static HEADERS_RECEIVED = 2;
|
|
28
|
+
static LOADING = 3;
|
|
29
|
+
static DONE = 4;
|
|
30
|
+
UNSENT = XMLHttpRequestPolyfill.UNSENT;
|
|
31
|
+
OPENED = XMLHttpRequestPolyfill.OPENED;
|
|
32
|
+
HEADERS_RECEIVED = XMLHttpRequestPolyfill.HEADERS_RECEIVED;
|
|
33
|
+
LOADING = XMLHttpRequestPolyfill.LOADING;
|
|
34
|
+
DONE = XMLHttpRequestPolyfill.DONE;
|
|
35
|
+
upload = new XMLHttpRequestUploadPolyfill();
|
|
36
|
+
readyState = XMLHttpRequestPolyfill.UNSENT;
|
|
37
|
+
response = null;
|
|
38
|
+
responseText = "";
|
|
39
|
+
responseType = "";
|
|
40
|
+
responseURL = "";
|
|
41
|
+
status = 0;
|
|
42
|
+
statusText = "";
|
|
43
|
+
timeout = 0;
|
|
44
|
+
withCredentials = false;
|
|
45
|
+
onreadystatechange = null;
|
|
46
|
+
onabort = null;
|
|
47
|
+
onerror = null;
|
|
48
|
+
onload = null;
|
|
49
|
+
onloadend = null;
|
|
50
|
+
onloadstart = null;
|
|
51
|
+
onprogress = null;
|
|
52
|
+
ontimeout = null;
|
|
53
|
+
method = "GET";
|
|
54
|
+
url = "";
|
|
55
|
+
requestHeaders = new HeadersPolyfill();
|
|
56
|
+
responseHeaders = new HeadersPolyfill();
|
|
57
|
+
requestController = null;
|
|
58
|
+
timeoutId = null;
|
|
59
|
+
sent = false;
|
|
60
|
+
open(method, url) {
|
|
61
|
+
this.method = String(method || "GET").toUpperCase();
|
|
62
|
+
this.url = url;
|
|
63
|
+
this.status = 0;
|
|
64
|
+
this.statusText = "";
|
|
65
|
+
this.response = null;
|
|
66
|
+
this.responseText = "";
|
|
67
|
+
this.responseURL = "";
|
|
68
|
+
this.responseHeaders = new HeadersPolyfill();
|
|
69
|
+
this.sent = false;
|
|
70
|
+
this.transitionTo(XMLHttpRequestPolyfill.OPENED);
|
|
71
|
+
}
|
|
72
|
+
setRequestHeader(key, value) {
|
|
73
|
+
if (this.readyState !== XMLHttpRequestPolyfill.OPENED || this.sent) throw new Error("Failed to execute setRequestHeader: invalid readyState");
|
|
74
|
+
this.requestHeaders.append(key, value);
|
|
75
|
+
}
|
|
76
|
+
getAllResponseHeaders() {
|
|
77
|
+
if (this.readyState < XMLHttpRequestPolyfill.HEADERS_RECEIVED) return "";
|
|
78
|
+
let content = "";
|
|
79
|
+
this.responseHeaders.forEach((value, key) => {
|
|
80
|
+
content += `${key}: ${value}\r\n`;
|
|
81
|
+
});
|
|
82
|
+
return content;
|
|
83
|
+
}
|
|
84
|
+
getResponseHeader(key) {
|
|
85
|
+
if (this.readyState < XMLHttpRequestPolyfill.HEADERS_RECEIVED) return null;
|
|
86
|
+
return this.responseHeaders.get(key);
|
|
87
|
+
}
|
|
88
|
+
abort() {
|
|
89
|
+
if (!this.requestController) return;
|
|
90
|
+
this.requestController.abort();
|
|
91
|
+
}
|
|
92
|
+
async send(body) {
|
|
93
|
+
if (this.readyState !== XMLHttpRequestPolyfill.OPENED) throw new Error("Failed to execute send: invalid readyState");
|
|
94
|
+
this.sent = true;
|
|
95
|
+
this.dispatchEvent({ type: "loadstart" });
|
|
96
|
+
this.upload.dispatchEvent(createProgressEvent("loadstart"));
|
|
97
|
+
const controller = new (typeof AbortController === "function" ? AbortController : AbortControllerPolyfill)();
|
|
98
|
+
this.requestController = controller;
|
|
99
|
+
if (this.timeout > 0) this.timeoutId = setTimeout(() => {
|
|
100
|
+
controller.abort(createError("timeout"));
|
|
101
|
+
}, this.timeout);
|
|
102
|
+
try {
|
|
103
|
+
const response = await resolveFetch()(this.url, {
|
|
104
|
+
method: this.method,
|
|
105
|
+
headers: headersToObject(this.requestHeaders),
|
|
106
|
+
body,
|
|
107
|
+
signal: controller.signal
|
|
108
|
+
});
|
|
109
|
+
this.responseHeaders = typeof Headers === "function" && response.headers instanceof Headers ? response.headers : new HeadersPolyfill(response.headers);
|
|
110
|
+
this.status = response.status;
|
|
111
|
+
this.statusText = response.statusText ?? "";
|
|
112
|
+
this.responseURL = response.url ?? this.url;
|
|
113
|
+
this.transitionTo(XMLHttpRequestPolyfill.HEADERS_RECEIVED);
|
|
114
|
+
this.transitionTo(XMLHttpRequestPolyfill.LOADING);
|
|
115
|
+
if (this.responseType === "arraybuffer") this.response = await response.arrayBuffer();
|
|
116
|
+
else {
|
|
117
|
+
const text = await response.text();
|
|
118
|
+
this.responseText = text;
|
|
119
|
+
this.response = this.responseType === "json" ? text ? JSON.parse(text) : null : text;
|
|
120
|
+
}
|
|
121
|
+
this.finish("load");
|
|
122
|
+
} catch (error) {
|
|
123
|
+
const reason = controller.signal && "reason" in controller.signal ? controller.signal.reason : void 0;
|
|
124
|
+
if (controller.signal?.aborted) {
|
|
125
|
+
const type = reason instanceof Error && reason.name === "TimeoutError" ? "timeout" : "abort";
|
|
126
|
+
this.finish(type);
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.response = null;
|
|
130
|
+
this.responseText = "";
|
|
131
|
+
this.status = 0;
|
|
132
|
+
this.statusText = "";
|
|
133
|
+
this.transitionTo(XMLHttpRequestPolyfill.DONE);
|
|
134
|
+
this.dispatchEvent({ type: "error" });
|
|
135
|
+
this.dispatchEvent({ type: "loadend" });
|
|
136
|
+
throw error;
|
|
137
|
+
} finally {
|
|
138
|
+
if (this.timeoutId) {
|
|
139
|
+
clearTimeout(this.timeoutId);
|
|
140
|
+
this.timeoutId = null;
|
|
141
|
+
}
|
|
142
|
+
this.requestController = null;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
finish(type) {
|
|
146
|
+
this.transitionTo(XMLHttpRequestPolyfill.DONE);
|
|
147
|
+
if (type === "abort") this.dispatchEvent({ type: "abort" });
|
|
148
|
+
else if (type === "timeout") this.dispatchEvent({ type: "timeout" });
|
|
149
|
+
else {
|
|
150
|
+
this.dispatchEvent(createProgressEvent("progress"));
|
|
151
|
+
this.dispatchEvent({ type: "load" });
|
|
152
|
+
}
|
|
153
|
+
this.dispatchEvent({ type: "loadend" });
|
|
154
|
+
}
|
|
155
|
+
transitionTo(nextState) {
|
|
156
|
+
this.readyState = nextState;
|
|
157
|
+
this.dispatchEvent({ type: "readystatechange" });
|
|
158
|
+
}
|
|
159
|
+
};
|
|
160
|
+
//#endregion
|
|
161
|
+
export { XMLHttpRequestPolyfill, XMLHttpRequestUploadPolyfill };
|