@wevu/web-apis 1.2.2 → 1.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  ## 1. 简介
4
4
 
5
- `@wevu/web-apis` 为小程序运行时提供一组 Web API 兼容层,重点解决第三方请求库在小程序环境中缺失 `fetch`、`Request`、`Response`、`AbortController`、`XMLHttpRequest`、`URL`、`WebSocket` 等全局对象的问题。
5
+ `@wevu/web-apis` 为小程序运行时提供一组 Web API 兼容层,重点解决第三方库在小程序环境中缺失 `fetch`、`Request`、`Response`、`AbortController`、`XMLHttpRequest`、`URL`、`WebSocket`、`TextEncoder`、`TextDecoder`、`atob`、`btoa`、`queueMicrotask`、`performance.now`、`crypto.getRandomValues`、`Event`、`CustomEvent` 等全局对象的问题。
6
6
 
7
7
  它主要服务于:
8
8
 
9
- - `weapp-vite` 的请求全局注入能力
9
+ - `weapp-vite` 的 Web Runtime 全局注入能力
10
10
  - `wevu` 运行时对 Web 风格请求库的兼容
11
11
  - `axios`、`graphql-request` 等依赖 Web API 的第三方库
12
12
 
@@ -15,6 +15,7 @@
15
15
  - 按需安装 `fetch`、`Headers`、`Request`、`Response`
16
16
  - 提供 `AbortController` / `AbortSignal` 兼容层
17
17
  - 提供 `XMLHttpRequest`、`URL`、`URLSearchParams`、`Blob`、`FormData`、`WebSocket` 兼容层
18
+ - 提供 `atob`、`btoa`、`queueMicrotask`、`performance.now`、`crypto.getRandomValues`、`Event`、`CustomEvent` 兼容层
18
19
  - 自动把能力安装到可用的小程序宿主全局对象
19
20
  - 默认基于 `@wevu/api` 的请求能力完成底层转发
20
21
 
@@ -26,12 +27,12 @@ pnpm add @wevu/web-apis
26
27
 
27
28
  ## 4. 快速开始
28
29
 
29
- ### 4.1 安装完整请求全局
30
+ ### 4.1 安装完整 Web Runtime
30
31
 
31
32
  ```ts
32
- import { installRequestGlobals } from '@wevu/web-apis'
33
+ import { installWebRuntimeGlobals } from '@wevu/web-apis'
33
34
 
34
- installRequestGlobals()
35
+ installWebRuntimeGlobals()
35
36
 
36
37
  const response = await fetch('https://request-globals.invalid/data')
37
38
  console.log(await response.json())
@@ -51,19 +52,35 @@ controller.abort()
51
52
  ### 4.3 按目标精简注入
52
53
 
53
54
  ```ts
54
- import { installRequestGlobals } from '@wevu/web-apis'
55
+ import { installWebRuntimeGlobals } from '@wevu/web-apis'
55
56
 
56
- installRequestGlobals({
57
+ installWebRuntimeGlobals({
57
58
  targets: ['fetch', 'Headers', 'Request', 'Response'],
58
59
  })
59
60
  ```
60
61
 
61
- ### 4.4 安装并使用 WebSocket
62
+ ### 4.4 安装轻量通用 Web Runtime 能力
62
63
 
63
64
  ```ts
64
- import { installRequestGlobals } from '@wevu/web-apis'
65
+ import { installWebRuntimeGlobals } from '@wevu/web-apis'
65
66
 
66
- installRequestGlobals({
67
+ installWebRuntimeGlobals({
68
+ targets: ['atob', 'btoa', 'queueMicrotask', 'performance', 'crypto', 'Event', 'CustomEvent'],
69
+ })
70
+
71
+ const encoded = btoa('AB')
72
+ const decoded = atob(encoded)
73
+ const now = performance.now()
74
+ const bytes = crypto.getRandomValues(new Uint8Array(4))
75
+ const event = new CustomEvent('payload', { detail: { ok: true } })
76
+ ```
77
+
78
+ ### 4.5 安装并使用 WebSocket
79
+
80
+ ```ts
81
+ import { installWebRuntimeGlobals } from '@wevu/web-apis'
82
+
83
+ installWebRuntimeGlobals({
67
84
  targets: ['WebSocket'],
68
85
  })
69
86
 
@@ -86,7 +103,8 @@ socket.onclose = (event) => {
86
103
 
87
104
  | 导出 | 说明 |
88
105
  | ---------------------------------------------------------- | ----------------------------------------------- |
89
- | `installRequestGlobals` | 按需安装请求相关全局对象 |
106
+ | `installWebRuntimeGlobals` | 按需安装 Web Runtime 全局对象 |
107
+ | `installRequestGlobals` | 旧别名,兼容历史代码 |
90
108
  | `installAbortGlobals` | 仅安装 `AbortController` / `AbortSignal` |
91
109
  | `fetch` | 基于小程序请求能力适配的 `fetch` 实现 |
92
110
  | `HeadersPolyfill` / `RequestPolyfill` / `ResponsePolyfill` | HTTP 相关兼容类 |
@@ -99,6 +117,7 @@ socket.onclose = (event) => {
99
117
  - 在小程序环境中运行 `axios` 的 `fetch` 适配器
100
118
  - 在小程序环境中运行 `graphql-request`
101
119
  - 在小程序环境中直接复用浏览器风格的 `WebSocket` 客户端代码
120
+ - 在小程序环境中运行依赖 `atob` / `btoa` / `queueMicrotask` / `performance.now` / `crypto.getRandomValues` 的工具库
102
121
  - 给依赖 `URL` / `FormData` / `Blob` 的库补齐基础全局对象
103
122
 
104
123
  ## 7. WebSocket 兼容说明
@@ -121,3 +140,8 @@ pnpm --filter @wevu/web-apis typecheck
121
140
 
122
141
  - `@wevu/api`:[../weapi/README.md](../weapi/README.md)
123
142
  - `wevu`:[../wevu/README.md](../wevu/README.md)
143
+
144
+ ## 10. 兼容说明
145
+
146
+ - 新项目建议使用 `installWebRuntimeGlobals()`
147
+ - `installRequestGlobals()` 仍保留为兼容别名,后续会逐步淡出文档主叙事
package/dist/index.d.mts CHANGED
@@ -7,13 +7,71 @@ import { BlobPolyfill, FormDataPolyfill } from "./web.mjs";
7
7
  import { WebSocketPolyfill } from "./websocket.mjs";
8
8
  import { XMLHttpRequestPolyfill } from "./xhr.mjs";
9
9
 
10
+ //#region src/base64.d.ts
11
+ declare function btoaPolyfill(input?: string): string;
12
+ declare function atobPolyfill(input?: string): string;
13
+ //#endregion
14
+ //#region src/crypto.d.ts
15
+ type IntegerTypedArray = Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | BigInt64Array | BigUint64Array;
16
+ declare function getRandomValuesPolyfill<T extends IntegerTypedArray>(typedArray: T): (T & Int8Array<ArrayBufferLike>) | (T & Uint8Array<ArrayBufferLike>) | (T & Uint8ClampedArray<ArrayBufferLike>) | (T & Int16Array<ArrayBufferLike>) | (T & Uint16Array<ArrayBufferLike>) | (T & Int32Array<ArrayBufferLike>) | (T & Uint32Array<ArrayBufferLike>) | (T & BigInt64Array<ArrayBufferLike>) | (T & BigUint64Array<ArrayBufferLike>);
17
+ declare const cryptoPolyfill: {
18
+ getRandomValues: typeof getRandomValuesPolyfill;
19
+ };
20
+ //#endregion
21
+ //#region src/events.d.ts
22
+ interface EventInitPolyfill {
23
+ bubbles?: boolean;
24
+ cancelable?: boolean;
25
+ composed?: boolean;
26
+ }
27
+ interface CustomEventInitPolyfill<T = any> extends EventInitPolyfill {
28
+ detail?: T;
29
+ }
30
+ declare class EventPolyfill {
31
+ readonly bubbles: boolean;
32
+ readonly cancelable: boolean;
33
+ readonly composed: boolean;
34
+ readonly isTrusted = false;
35
+ readonly timeStamp: number;
36
+ readonly type: string;
37
+ currentTarget: unknown;
38
+ target: unknown;
39
+ defaultPrevented: boolean;
40
+ cancelBubble: boolean;
41
+ constructor(type: string, init?: EventInitPolyfill);
42
+ composedPath(): {}[];
43
+ preventDefault(): void;
44
+ stopImmediatePropagation(): void;
45
+ stopPropagation(): void;
46
+ }
47
+ declare class CustomEventPolyfill<T = any> extends EventPolyfill {
48
+ readonly detail: T | null;
49
+ constructor(type: string, init?: CustomEventInitPolyfill<T>);
50
+ }
51
+ //#endregion
52
+ //#region src/performance.d.ts
53
+ declare const performancePolyfill: {
54
+ __weappVitePerformancePolyfill: boolean;
55
+ now(): number;
56
+ timeOrigin: number;
57
+ };
58
+ //#endregion
59
+ //#region src/task.d.ts
60
+ declare function queueMicrotaskPolyfill(callback: () => void): void;
61
+ //#endregion
10
62
  //#region src/index.d.ts
11
- type WeappInjectRequestGlobalsTarget = 'fetch' | 'Headers' | 'Request' | 'Response' | 'AbortController' | 'AbortSignal' | 'XMLHttpRequest' | 'WebSocket';
12
- interface InstallRequestGlobalsOptions {
13
- targets?: WeappInjectRequestGlobalsTarget[];
63
+ type WeappInjectWebRuntimeGlobalsTarget = 'fetch' | 'Headers' | 'Request' | 'Response' | 'TextEncoder' | 'TextDecoder' | 'AbortController' | 'AbortSignal' | 'XMLHttpRequest' | 'WebSocket' | 'atob' | 'btoa' | 'queueMicrotask' | 'performance' | 'crypto' | 'Event' | 'CustomEvent';
64
+ type WeappInjectRequestGlobalsTarget = WeappInjectWebRuntimeGlobalsTarget;
65
+ interface InstallWebRuntimeGlobalsOptions {
66
+ targets?: WeappInjectWebRuntimeGlobalsTarget[];
14
67
  }
68
+ interface InstallRequestGlobalsOptions extends InstallWebRuntimeGlobalsOptions {}
69
+ /**
70
+ * @description 按需向小程序全局环境注入缺失的 Web Runtime 对象。
71
+ */
72
+ declare function installWebRuntimeGlobals(options?: InstallWebRuntimeGlobalsOptions): Record<string, any>;
15
73
  /**
16
- * @description 按需向小程序全局环境注入缺失的请求相关对象。
74
+ * @description 已废弃,请迁移到 `installWebRuntimeGlobals`。
17
75
  */
18
76
  declare function installRequestGlobals(options?: InstallRequestGlobalsOptions): Record<string, any>;
19
77
  /**
@@ -21,4 +79,4 @@ declare function installRequestGlobals(options?: InstallRequestGlobalsOptions):
21
79
  */
22
80
  declare function installAbortGlobals(): Record<string, any>;
23
81
  //#endregion
24
- export { AbortControllerPolyfill, AbortSignalPolyfill, BlobPolyfill, FormDataPolyfill, HeadersPolyfill, InstallRequestGlobalsOptions, RequestGlobalsEventTarget, RequestPolyfill, ResponsePolyfill, URLPolyfill, URLSearchParamsPolyfill, WeappInjectRequestGlobalsTarget, WebSocketPolyfill, XMLHttpRequestPolyfill, fetch, installAbortGlobals, installRequestGlobals };
82
+ export { AbortControllerPolyfill, AbortSignalPolyfill, BlobPolyfill, CustomEventPolyfill, EventPolyfill, FormDataPolyfill, HeadersPolyfill, InstallRequestGlobalsOptions, InstallWebRuntimeGlobalsOptions, RequestGlobalsEventTarget, RequestPolyfill, ResponsePolyfill, URLPolyfill, URLSearchParamsPolyfill, WeappInjectRequestGlobalsTarget, WeappInjectWebRuntimeGlobalsTarget, WebSocketPolyfill, XMLHttpRequestPolyfill, atobPolyfill, btoaPolyfill, cryptoPolyfill, fetch, installAbortGlobals, installRequestGlobals, installWebRuntimeGlobals, performancePolyfill, queueMicrotaskPolyfill };
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { RequestGlobalsEventTarget, installRequestGlobalBinding, resolveRequestGlobalsHost, resolveRequestGlobalsHosts } from "./shared.mjs";
1
+ import { RequestGlobalsEventTarget, decodeTextFallback, encodeTextFallback, installRequestGlobalBinding, resolveRequestGlobalsHost, resolveRequestGlobalsHosts } from "./shared.mjs";
2
2
  import { AbortControllerPolyfill, AbortSignalPolyfill } from "./abort.mjs";
3
3
  import { HeadersPolyfill, RequestPolyfill, ResponsePolyfill } from "./http.mjs";
4
4
  import { fetch } from "./fetch.mjs";
@@ -6,14 +6,224 @@ import { URLPolyfill, URLSearchParamsPolyfill } from "./url.mjs";
6
6
  import { BlobPolyfill, FormDataPolyfill } from "./web.mjs";
7
7
  import { WebSocketPolyfill } from "./websocket.mjs";
8
8
  import { XMLHttpRequestPolyfill } from "./xhr.mjs";
9
+ import { REQUEST_GLOBAL_ACTUALS_KEY, REQUEST_GLOBAL_PLACEHOLDER_KEY } from "@weapp-core/constants";
10
+ //#region src/base64.ts
11
+ const BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
12
+ const BASE64_LOOKUP = new Uint8Array(256);
13
+ const BASE64_INVALID_INPUT_RE = /[^A-Za-z\d+/=]/u;
14
+ for (let index = 0; index < BASE64_LOOKUP.length; index++) BASE64_LOOKUP[index] = 255;
15
+ for (let index = 0; index < 64; index++) BASE64_LOOKUP[BASE64_CHARS.charCodeAt(index)] = index;
16
+ function toLatin1Byte(value, index) {
17
+ const codePoint = value.charCodeAt(index);
18
+ if (codePoint > 255) throw new TypeError(`Failed to execute 'btoa': character outside Latin1 range at index ${index}`);
19
+ return codePoint;
20
+ }
21
+ function btoaPolyfill(input = "") {
22
+ const source = String(input);
23
+ let output = "";
24
+ for (let index = 0; index < source.length; index += 3) {
25
+ const byte0 = toLatin1Byte(source, index);
26
+ const byte1 = index + 1 < source.length ? toLatin1Byte(source, index + 1) : NaN;
27
+ const byte2 = index + 2 < source.length ? toLatin1Byte(source, index + 2) : NaN;
28
+ const triplet = byte0 << 16 | (Number.isNaN(byte1) ? 0 : byte1) << 8 | (Number.isNaN(byte2) ? 0 : byte2);
29
+ output += BASE64_CHARS[triplet >> 18 & 63];
30
+ output += BASE64_CHARS[triplet >> 12 & 63];
31
+ output += Number.isNaN(byte1) ? "=" : BASE64_CHARS[triplet >> 6 & 63];
32
+ output += Number.isNaN(byte2) ? "=" : BASE64_CHARS[triplet & 63];
33
+ }
34
+ return output;
35
+ }
36
+ function atobPolyfill(input = "") {
37
+ const source = String(input).replace(/[\t\n\f\r ]+/g, "");
38
+ if (source.length % 4 === 1 || BASE64_INVALID_INPUT_RE.test(source)) throw new TypeError("Failed to execute 'atob': the input is not correctly encoded");
39
+ let output = "";
40
+ for (let index = 0; index < source.length; index += 4) {
41
+ const char0 = source.charCodeAt(index);
42
+ const char1 = source.charCodeAt(index + 1);
43
+ const char2 = source.charAt(index + 2);
44
+ const char3 = source.charAt(index + 3);
45
+ const sextet0 = BASE64_LOOKUP[char0] ?? 255;
46
+ const sextet1 = BASE64_LOOKUP[char1] ?? 255;
47
+ const sextet2 = char2 === "=" ? 64 : BASE64_LOOKUP[source.charCodeAt(index + 2)] ?? 255;
48
+ const sextet3 = char3 === "=" ? 64 : BASE64_LOOKUP[source.charCodeAt(index + 3)] ?? 255;
49
+ if (sextet0 > 63 || sextet1 > 63 || sextet2 > 64 || sextet3 > 64) throw new TypeError("Failed to execute 'atob': the input is not correctly encoded");
50
+ const triplet = sextet0 << 18 | sextet1 << 12 | (sextet2 & 63) << 6 | sextet3 & 63;
51
+ output += String.fromCharCode(triplet >> 16 & 255);
52
+ if (char2 !== "=") output += String.fromCharCode(triplet >> 8 & 255);
53
+ if (char3 !== "=") output += String.fromCharCode(triplet & 255);
54
+ }
55
+ return output;
56
+ }
57
+ //#endregion
58
+ //#region src/crypto.ts
59
+ const MAX_RANDOM_VALUES_BYTE_LENGTH = 65536;
60
+ function isIntegerTypedArray(value) {
61
+ return value instanceof Int8Array || value instanceof Uint8Array || value instanceof Uint8ClampedArray || value instanceof Int16Array || value instanceof Uint16Array || value instanceof Int32Array || value instanceof Uint32Array || value instanceof BigInt64Array || value instanceof BigUint64Array;
62
+ }
63
+ function getNativeCrypto() {
64
+ const candidate = globalThis.crypto;
65
+ if (candidate && typeof candidate.getRandomValues === "function") return candidate;
66
+ }
67
+ function fillArrayWithMathRandom(target) {
68
+ const bytes = new Uint8Array(target.buffer, target.byteOffset, target.byteLength);
69
+ for (let index = 0; index < bytes.length; index++) bytes[index] = Math.floor(Math.random() * 256);
70
+ }
71
+ function fillArrayWithHostRandomValues(target) {
72
+ for (const hostKey of [
73
+ "wx",
74
+ "my",
75
+ "tt"
76
+ ]) {
77
+ const host = globalThis[hostKey];
78
+ if (!host || typeof host.getRandomValues !== "function") continue;
79
+ try {
80
+ host.getRandomValues(target);
81
+ return true;
82
+ } catch {}
83
+ }
84
+ return false;
85
+ }
86
+ function getRandomValuesPolyfill(typedArray) {
87
+ if (!isIntegerTypedArray(typedArray)) throw new TypeError("Failed to execute 'getRandomValues': input must be an integer TypedArray");
88
+ if (typedArray.byteLength > MAX_RANDOM_VALUES_BYTE_LENGTH) throw new TypeError("Failed to execute 'getRandomValues': byteLength exceeds 65536");
89
+ const nativeCrypto = getNativeCrypto();
90
+ if (nativeCrypto && nativeCrypto.getRandomValues !== getRandomValuesPolyfill) return nativeCrypto.getRandomValues(typedArray);
91
+ if (!fillArrayWithHostRandomValues(typedArray)) fillArrayWithMathRandom(typedArray);
92
+ return typedArray;
93
+ }
94
+ const cryptoPolyfill = { getRandomValues: getRandomValuesPolyfill };
95
+ //#endregion
96
+ //#region src/events.ts
97
+ var EventPolyfill = class {
98
+ bubbles;
99
+ cancelable;
100
+ composed;
101
+ isTrusted = false;
102
+ timeStamp = Date.now();
103
+ type;
104
+ currentTarget = null;
105
+ target = null;
106
+ defaultPrevented = false;
107
+ cancelBubble = false;
108
+ constructor(type, init = {}) {
109
+ this.type = String(type);
110
+ this.bubbles = init.bubbles === true;
111
+ this.cancelable = init.cancelable === true;
112
+ this.composed = init.composed === true;
113
+ }
114
+ composedPath() {
115
+ return this.target == null ? [] : [this.target];
116
+ }
117
+ preventDefault() {
118
+ if (this.cancelable) this.defaultPrevented = true;
119
+ }
120
+ stopImmediatePropagation() {
121
+ this.cancelBubble = true;
122
+ }
123
+ stopPropagation() {
124
+ this.cancelBubble = true;
125
+ }
126
+ };
127
+ var CustomEventPolyfill = class extends EventPolyfill {
128
+ detail;
129
+ constructor(type, init = {}) {
130
+ super(type, init);
131
+ this.detail = init.detail ?? null;
132
+ }
133
+ };
134
+ //#endregion
135
+ //#region src/performance.ts
136
+ const performanceTimeOrigin = Date.now();
137
+ const PERFORMANCE_POLYFILL_MARKER = "__weappVitePerformancePolyfill";
138
+ function resolveNativePerformance() {
139
+ const candidate = globalThis.performance;
140
+ if (candidate && candidate?.[PERFORMANCE_POLYFILL_MARKER] !== true && typeof candidate.now === "function") return candidate;
141
+ for (const hostKey of [
142
+ "wx",
143
+ "my",
144
+ "tt"
145
+ ]) {
146
+ const host = globalThis[hostKey];
147
+ if (!host || typeof host.getPerformance !== "function") continue;
148
+ try {
149
+ const performance = host.getPerformance();
150
+ if (performance && typeof performance.now === "function") return performance;
151
+ } catch {}
152
+ }
153
+ }
154
+ const performancePolyfill = {
155
+ [PERFORMANCE_POLYFILL_MARKER]: true,
156
+ now() {
157
+ const nativePerformance = resolveNativePerformance();
158
+ if (nativePerformance && nativePerformance !== performancePolyfill) try {
159
+ return Number(nativePerformance.now());
160
+ } catch {}
161
+ return Date.now() - performanceTimeOrigin;
162
+ },
163
+ timeOrigin: performanceTimeOrigin
164
+ };
165
+ //#endregion
166
+ //#region src/task.ts
167
+ function queueMicrotaskPolyfill(callback) {
168
+ if (typeof callback !== "function") throw new TypeError("Failed to execute 'queueMicrotask': callback must be a function");
169
+ const nativeQueueMicrotask = globalThis.queueMicrotask;
170
+ if (typeof nativeQueueMicrotask === "function" && nativeQueueMicrotask !== queueMicrotaskPolyfill) {
171
+ nativeQueueMicrotask(callback);
172
+ return;
173
+ }
174
+ Promise.resolve().then(callback).catch((error) => {
175
+ setTimeout(() => {
176
+ throw error;
177
+ }, 0);
178
+ });
179
+ }
180
+ //#endregion
181
+ //#region src/textCodec.ts
182
+ function normalizeTextDecoderInput(input) {
183
+ if (input == null) return /* @__PURE__ */ new ArrayBuffer(0);
184
+ if (input instanceof ArrayBuffer) return input.slice(0);
185
+ if (ArrayBuffer.isView(input)) {
186
+ const copied = new Uint8Array(input.byteLength);
187
+ copied.set(new Uint8Array(input.buffer, input.byteOffset, input.byteLength));
188
+ return copied.buffer;
189
+ }
190
+ return /* @__PURE__ */ new ArrayBuffer(0);
191
+ }
192
+ var TextEncoderPolyfill = class {
193
+ encoding = "utf-8";
194
+ encode(input = "") {
195
+ return new Uint8Array(encodeTextFallback(String(input)));
196
+ }
197
+ };
198
+ var TextDecoderPolyfill = class {
199
+ encoding = "utf-8";
200
+ fatal = false;
201
+ ignoreBOM = false;
202
+ decode(input) {
203
+ return decodeTextFallback(normalizeTextDecoderInput(input));
204
+ }
205
+ };
206
+ //#endregion
9
207
  //#region src/index.ts
208
+ function hasRequestRuntimeBinaryUsage(targets) {
209
+ return targets.some((target) => target === "fetch" || target === "Request" || target === "Response" || target === "XMLHttpRequest" || target === "WebSocket");
210
+ }
211
+ function resolveInstallTargets(targets) {
212
+ const installTargets = [...targets];
213
+ if (hasRequestRuntimeBinaryUsage(targets)) installTargets.push("TextEncoder", "TextDecoder");
214
+ if (targets.includes("CustomEvent")) installTargets.push("Event");
215
+ return [...new Set(installTargets)];
216
+ }
10
217
  function resolveActualBindingTargets(targets) {
11
218
  const bindingTargets = [...targets];
12
- if (targets.some((target) => target === "fetch" || target === "Request" || target === "Response" || target === "XMLHttpRequest")) bindingTargets.push("URL", "URLSearchParams", "Blob", "FormData");
219
+ if (hasRequestRuntimeBinaryUsage(targets)) {
220
+ bindingTargets.push("TextEncoder", "TextDecoder");
221
+ bindingTargets.push("URL", "URLSearchParams", "Blob", "FormData");
222
+ }
13
223
  return [...new Set(bindingTargets)];
14
224
  }
15
225
  function isPlaceholderRequestGlobal(value) {
16
- return Boolean(value && typeof value === "function" && value.__weappViteRequestGlobalsPlaceholder__ === true);
226
+ return Boolean(value && typeof value === "function" && value[REQUEST_GLOBAL_PLACEHOLDER_KEY] === true);
17
227
  }
18
228
  function hasUsableConstructor(value, args = []) {
19
229
  if (typeof value !== "function" || isPlaceholderRequestGlobal(value)) return false;
@@ -24,42 +234,86 @@ function hasUsableConstructor(value, args = []) {
24
234
  return false;
25
235
  }
26
236
  }
237
+ function assignHostGlobal(host, key, value) {
238
+ try {
239
+ host[key] = value;
240
+ return true;
241
+ } catch {
242
+ return false;
243
+ }
244
+ }
27
245
  function installSingleTarget(host, target) {
28
246
  if (target === "fetch") {
29
- if (typeof host.fetch !== "function" || isPlaceholderRequestGlobal(host.fetch)) host.fetch = fetch;
247
+ if (typeof host.fetch !== "function" || isPlaceholderRequestGlobal(host.fetch)) assignHostGlobal(host, "fetch", fetch);
30
248
  return;
31
249
  }
32
250
  if (target === "Headers") {
33
- if (typeof host.Headers !== "function" || isPlaceholderRequestGlobal(host.Headers)) host.Headers = HeadersPolyfill;
251
+ if (typeof host.Headers !== "function" || isPlaceholderRequestGlobal(host.Headers)) assignHostGlobal(host, "Headers", HeadersPolyfill);
34
252
  return;
35
253
  }
36
254
  if (target === "Request") {
37
- if (typeof host.Request !== "function" || isPlaceholderRequestGlobal(host.Request)) host.Request = RequestPolyfill;
255
+ if (typeof host.Request !== "function" || isPlaceholderRequestGlobal(host.Request)) assignHostGlobal(host, "Request", RequestPolyfill);
38
256
  return;
39
257
  }
40
258
  if (target === "Response") {
41
- if (typeof host.Response !== "function" || isPlaceholderRequestGlobal(host.Response)) host.Response = ResponsePolyfill;
259
+ if (typeof host.Response !== "function" || isPlaceholderRequestGlobal(host.Response)) assignHostGlobal(host, "Response", ResponsePolyfill);
260
+ return;
261
+ }
262
+ if (target === "TextEncoder") {
263
+ if (typeof host.TextEncoder !== "function" || isPlaceholderRequestGlobal(host.TextEncoder)) assignHostGlobal(host, "TextEncoder", TextEncoderPolyfill);
264
+ return;
265
+ }
266
+ if (target === "TextDecoder") {
267
+ if (typeof host.TextDecoder !== "function" || isPlaceholderRequestGlobal(host.TextDecoder)) assignHostGlobal(host, "TextDecoder", TextDecoderPolyfill);
42
268
  return;
43
269
  }
44
270
  if (target === "AbortController") {
45
- if (typeof host.AbortController !== "function" || isPlaceholderRequestGlobal(host.AbortController)) host.AbortController = AbortControllerPolyfill;
271
+ if (typeof host.AbortController !== "function" || isPlaceholderRequestGlobal(host.AbortController)) assignHostGlobal(host, "AbortController", AbortControllerPolyfill);
46
272
  return;
47
273
  }
48
274
  if (target === "AbortSignal") {
49
- if (typeof host.AbortSignal !== "function" || isPlaceholderRequestGlobal(host.AbortSignal)) host.AbortSignal = AbortSignalPolyfill;
275
+ if (typeof host.AbortSignal !== "function" || isPlaceholderRequestGlobal(host.AbortSignal)) assignHostGlobal(host, "AbortSignal", AbortSignalPolyfill);
50
276
  return;
51
277
  }
52
278
  if (target === "WebSocket") {
53
- if (typeof host.WebSocket !== "function" || isPlaceholderRequestGlobal(host.WebSocket)) host.WebSocket = WebSocketPolyfill;
279
+ if (typeof host.WebSocket !== "function" || isPlaceholderRequestGlobal(host.WebSocket)) assignHostGlobal(host, "WebSocket", WebSocketPolyfill);
280
+ return;
281
+ }
282
+ if (target === "atob") {
283
+ if (typeof host.atob !== "function" || isPlaceholderRequestGlobal(host.atob)) assignHostGlobal(host, "atob", atobPolyfill);
54
284
  return;
55
285
  }
56
- if (target === "XMLHttpRequest" && (typeof host.XMLHttpRequest !== "function" || isPlaceholderRequestGlobal(host.XMLHttpRequest))) host.XMLHttpRequest = XMLHttpRequestPolyfill;
286
+ if (target === "btoa") {
287
+ if (typeof host.btoa !== "function" || isPlaceholderRequestGlobal(host.btoa)) assignHostGlobal(host, "btoa", btoaPolyfill);
288
+ return;
289
+ }
290
+ if (target === "queueMicrotask") {
291
+ if (typeof host.queueMicrotask !== "function" || isPlaceholderRequestGlobal(host.queueMicrotask)) assignHostGlobal(host, "queueMicrotask", queueMicrotaskPolyfill);
292
+ return;
293
+ }
294
+ if (target === "performance") {
295
+ if (!host.performance || typeof host.performance.now !== "function") assignHostGlobal(host, "performance", performancePolyfill);
296
+ return;
297
+ }
298
+ if (target === "crypto") {
299
+ if (!host.crypto || typeof host.crypto.getRandomValues !== "function") assignHostGlobal(host, "crypto", cryptoPolyfill);
300
+ return;
301
+ }
302
+ if (target === "Event") {
303
+ if (typeof host.Event !== "function" || isPlaceholderRequestGlobal(host.Event)) assignHostGlobal(host, "Event", EventPolyfill);
304
+ return;
305
+ }
306
+ if (target === "CustomEvent") {
307
+ if (typeof host.CustomEvent !== "function" || isPlaceholderRequestGlobal(host.CustomEvent)) assignHostGlobal(host, "CustomEvent", CustomEventPolyfill);
308
+ return;
309
+ }
310
+ if (target === "XMLHttpRequest" && (typeof host.XMLHttpRequest !== "function" || isPlaceholderRequestGlobal(host.XMLHttpRequest))) assignHostGlobal(host, "XMLHttpRequest", XMLHttpRequestPolyfill);
57
311
  }
58
312
  function installUrlGlobals(host) {
59
- if (!hasUsableConstructor(host.URL, ["https://request-globals.invalid"])) host.URL = URLPolyfill;
60
- if (!hasUsableConstructor(host.URLSearchParams, ["client=graphql-request"])) host.URLSearchParams = URLSearchParamsPolyfill;
61
- if (!hasUsableConstructor(host.Blob)) host.Blob = BlobPolyfill;
62
- if (!hasUsableConstructor(host.FormData)) host.FormData = FormDataPolyfill;
313
+ if (!hasUsableConstructor(host.URL, ["https://request-globals.invalid"])) assignHostGlobal(host, "URL", URLPolyfill);
314
+ if (!hasUsableConstructor(host.URLSearchParams, ["client=graphql-request"])) assignHostGlobal(host, "URLSearchParams", URLSearchParamsPolyfill);
315
+ if (!hasUsableConstructor(host.Blob)) assignHostGlobal(host, "Blob", BlobPolyfill);
316
+ if (!hasUsableConstructor(host.FormData)) assignHostGlobal(host, "FormData", FormDataPolyfill);
63
317
  }
64
318
  function installGlobalBindingIfNeeded(host, target) {
65
319
  const value = host[target];
@@ -79,30 +333,43 @@ function ensureRuntimeHostAliases(host) {
79
333
  }
80
334
  }
81
335
  function syncWeappViteRequestGlobalsActuals(host, targets) {
82
- const globalObject = resolveRequestGlobalsHost();
83
- const actuals = globalObject.__weappViteRequestGlobalsActuals && typeof globalObject.__weappViteRequestGlobalsActuals === "object" ? globalObject.__weappViteRequestGlobalsActuals : globalObject.__weappViteRequestGlobalsActuals = Object.create(null);
336
+ const globalObject = host != null && (typeof host === "object" || typeof host === "function") ? host : resolveRequestGlobalsHost();
337
+ let actuals = globalObject[REQUEST_GLOBAL_ACTUALS_KEY];
338
+ if (!actuals || typeof actuals !== "object") {
339
+ actuals = Object.create(null);
340
+ assignHostGlobal(globalObject, REQUEST_GLOBAL_ACTUALS_KEY, actuals);
341
+ }
84
342
  for (const target of resolveActualBindingTargets(targets)) {
85
343
  const value = host[target];
86
344
  if (value != null) actuals[target] = value;
87
345
  }
88
346
  }
89
347
  /**
90
- * @description 按需向小程序全局环境注入缺失的请求相关对象。
348
+ * @description 按需向小程序全局环境注入缺失的 Web Runtime 对象。
91
349
  */
92
- function installRequestGlobals(options = {}) {
93
- const targets = options.targets ?? [
350
+ function installWebRuntimeGlobals(options = {}) {
351
+ const targets = resolveInstallTargets(options.targets ?? [
94
352
  "fetch",
95
353
  "Headers",
96
354
  "Request",
97
355
  "Response",
356
+ "TextEncoder",
357
+ "TextDecoder",
98
358
  "AbortController",
99
359
  "AbortSignal",
100
360
  "XMLHttpRequest",
101
- "WebSocket"
102
- ];
361
+ "WebSocket",
362
+ "atob",
363
+ "btoa",
364
+ "queueMicrotask",
365
+ "performance",
366
+ "crypto",
367
+ "Event",
368
+ "CustomEvent"
369
+ ]);
103
370
  const hosts = resolveRequestGlobalsHosts();
104
371
  const primaryHost = resolveRequestGlobalsHost();
105
- const needsUrlGlobals = targets.some((target) => target === "fetch" || target === "Request" || target === "Response" || target === "XMLHttpRequest");
372
+ const needsUrlGlobals = hasRequestRuntimeBinaryUsage(targets);
106
373
  ensureRuntimeHostAliases(primaryHost);
107
374
  for (const host of hosts) {
108
375
  if (needsUrlGlobals) installUrlGlobals(host);
@@ -119,10 +386,16 @@ function installRequestGlobals(options = {}) {
119
386
  return hosts[0];
120
387
  }
121
388
  /**
389
+ * @description 已废弃,请迁移到 `installWebRuntimeGlobals`。
390
+ */
391
+ function installRequestGlobals(options = {}) {
392
+ return installWebRuntimeGlobals(options);
393
+ }
394
+ /**
122
395
  * @description 仅安装 AbortController 与 AbortSignal 兼容层。
123
396
  */
124
397
  function installAbortGlobals() {
125
- return installRequestGlobals({ targets: ["AbortController", "AbortSignal"] });
398
+ return installWebRuntimeGlobals({ targets: ["AbortController", "AbortSignal"] });
126
399
  }
127
400
  //#endregion
128
- export { AbortControllerPolyfill, AbortSignalPolyfill, BlobPolyfill, FormDataPolyfill, HeadersPolyfill, RequestGlobalsEventTarget, RequestPolyfill, ResponsePolyfill, URLPolyfill, URLSearchParamsPolyfill, WebSocketPolyfill, XMLHttpRequestPolyfill, fetch, installAbortGlobals, installRequestGlobals };
401
+ export { AbortControllerPolyfill, AbortSignalPolyfill, BlobPolyfill, CustomEventPolyfill, EventPolyfill, FormDataPolyfill, HeadersPolyfill, RequestGlobalsEventTarget, RequestPolyfill, ResponsePolyfill, URLPolyfill, URLSearchParamsPolyfill, WebSocketPolyfill, XMLHttpRequestPolyfill, atobPolyfill, btoaPolyfill, cryptoPolyfill, fetch, installAbortGlobals, installRequestGlobals, installWebRuntimeGlobals, performancePolyfill, queueMicrotaskPolyfill };
package/dist/shared.d.mts CHANGED
@@ -21,8 +21,10 @@ declare function resolveRequestGlobalsHosts(): Record<string, any>[];
21
21
  declare function installRequestGlobalBinding(name: string, value: unknown): void;
22
22
  declare function cloneArrayBuffer(buffer: ArrayBuffer): ArrayBuffer;
23
23
  declare function cloneArrayBufferView(view: ArrayBufferView): ArrayBuffer;
24
+ declare function encodeTextFallback(value: string): ArrayBuffer;
24
25
  declare function encodeText(value: string): ArrayBuffer;
26
+ declare function decodeTextFallback(value: ArrayBuffer): string;
25
27
  declare function decodeText(value: ArrayBuffer): string;
26
28
  declare function normalizeHeaderName(name: string): string;
27
29
  //#endregion
28
- export { RequestGlobalsEventLike, RequestGlobalsEventTarget, RequestGlobalsEventTargetLike, cloneArrayBuffer, cloneArrayBufferView, decodeText, encodeText, installRequestGlobalBinding, normalizeHeaderName, resolveRequestGlobalsHost, resolveRequestGlobalsHosts };
30
+ export { RequestGlobalsEventLike, RequestGlobalsEventTarget, RequestGlobalsEventTargetLike, cloneArrayBuffer, cloneArrayBufferView, decodeText, decodeTextFallback, encodeText, encodeTextFallback, installRequestGlobalBinding, normalizeHeaderName, resolveRequestGlobalsHost, resolveRequestGlobalsHosts };
package/dist/shared.mjs CHANGED
@@ -27,7 +27,7 @@ function resolveRequestGlobalsHost() {
27
27
  return {};
28
28
  }
29
29
  function isRequestGlobalsHostCandidate(value) {
30
- return typeof value === "object" || typeof value === "function";
30
+ return value != null && (typeof value === "object" || typeof value === "function");
31
31
  }
32
32
  function pushRequestGlobalsHost(hosts, candidate) {
33
33
  if (!isRequestGlobalsHostCandidate(candidate)) return;
@@ -52,7 +52,8 @@ function resolveRequestGlobalsHosts() {
52
52
  function installRequestGlobalBinding(name, value) {
53
53
  if (!name) return;
54
54
  try {
55
- Function("__weappRequestGlobalValue__", `${name} = __weappRequestGlobalValue__`)(value);
55
+ const host = resolveRequestGlobalsHost();
56
+ host[name] = value;
56
57
  } catch {}
57
58
  }
58
59
  function cloneArrayBuffer(buffer) {
@@ -63,20 +64,32 @@ function cloneArrayBufferView(view) {
63
64
  copied.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
64
65
  return copied.buffer;
65
66
  }
67
+ function encodeTextFallback(value) {
68
+ const binary = unescape(encodeURIComponent(String(value)));
69
+ const bytes = new Uint8Array(binary.length);
70
+ for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i);
71
+ return bytes.buffer;
72
+ }
66
73
  function encodeText(value) {
67
74
  if (typeof TextEncoder === "function") return new TextEncoder().encode(value).buffer;
68
- const bytes = new Uint8Array(value.length);
69
- for (let i = 0; i < value.length; i++) bytes[i] = value.charCodeAt(i) & 255;
70
- return bytes.buffer;
75
+ return encodeTextFallback(value);
76
+ }
77
+ function decodeTextFallback(value) {
78
+ const bytes = new Uint8Array(value);
79
+ let binary = "";
80
+ for (const byte of bytes) binary += String.fromCharCode(byte);
81
+ try {
82
+ return decodeURIComponent(escape(binary));
83
+ } catch {
84
+ return binary;
85
+ }
71
86
  }
72
87
  function decodeText(value) {
73
88
  if (typeof TextDecoder === "function") return new TextDecoder().decode(value);
74
- let text = "";
75
- for (const byte of new Uint8Array(value)) text += String.fromCharCode(byte);
76
- return text;
89
+ return decodeTextFallback(value);
77
90
  }
78
91
  function normalizeHeaderName(name) {
79
92
  return name.trim().toLowerCase();
80
93
  }
81
94
  //#endregion
82
- export { RequestGlobalsEventTarget, cloneArrayBuffer, cloneArrayBufferView, decodeText, encodeText, installRequestGlobalBinding, normalizeHeaderName, resolveRequestGlobalsHost, resolveRequestGlobalsHosts };
95
+ export { RequestGlobalsEventTarget, cloneArrayBuffer, cloneArrayBufferView, decodeText, decodeTextFallback, encodeText, encodeTextFallback, installRequestGlobalBinding, normalizeHeaderName, resolveRequestGlobalsHost, resolveRequestGlobalsHosts };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@wevu/web-apis",
3
3
  "type": "module",
4
- "version": "1.2.2",
4
+ "version": "1.2.5",
5
5
  "description": "Web API polyfills and global installers for mini-program runtimes",
6
6
  "author": "ice breaker <1324318532@qq.com>",
7
7
  "license": "MIT",
@@ -70,6 +70,7 @@
70
70
  "node": "^20.19.0 || >=22.12.0"
71
71
  },
72
72
  "dependencies": {
73
+ "@weapp-core/constants": "0.1.0",
73
74
  "@wevu/api": "0.2.3"
74
75
  },
75
76
  "publishConfig": {