@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 +35 -11
- package/dist/index.d.mts +63 -5
- package/dist/index.mjs +298 -25
- package/dist/shared.d.mts +3 -1
- package/dist/shared.mjs +22 -9
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
## 1. 简介
|
|
4
4
|
|
|
5
|
-
`@wevu/web-apis` 为小程序运行时提供一组 Web API
|
|
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 {
|
|
33
|
+
import { installWebRuntimeGlobals } from '@wevu/web-apis'
|
|
33
34
|
|
|
34
|
-
|
|
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 {
|
|
55
|
+
import { installWebRuntimeGlobals } from '@wevu/web-apis'
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
installWebRuntimeGlobals({
|
|
57
58
|
targets: ['fetch', 'Headers', 'Request', 'Response'],
|
|
58
59
|
})
|
|
59
60
|
```
|
|
60
61
|
|
|
61
|
-
### 4.4
|
|
62
|
+
### 4.4 安装轻量通用 Web Runtime 能力
|
|
62
63
|
|
|
63
64
|
```ts
|
|
64
|
-
import {
|
|
65
|
+
import { installWebRuntimeGlobals } from '@wevu/web-apis'
|
|
65
66
|
|
|
66
|
-
|
|
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
|
-
| `
|
|
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
|
|
12
|
-
|
|
13
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 === "
|
|
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
|
|
60
|
-
if (!hasUsableConstructor(host.URLSearchParams, ["client=graphql-request"])) host
|
|
61
|
-
if (!hasUsableConstructor(host.Blob)) host
|
|
62
|
-
if (!hasUsableConstructor(host.FormData)) host
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
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.
|
|
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": {
|