@wevu/web-apis 1.2.3 → 1.2.6
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 +270 -10
- package/dist/shared.d.mts +3 -1
- package/dist/shared.mjs +19 -7
- package/package.json +2 -2
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";
|
|
@@ -7,10 +7,219 @@ import { BlobPolyfill, FormDataPolyfill } from "./web.mjs";
|
|
|
7
7
|
import { WebSocketPolyfill } from "./websocket.mjs";
|
|
8
8
|
import { XMLHttpRequestPolyfill } from "./xhr.mjs";
|
|
9
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
|
|
10
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
|
+
}
|
|
11
217
|
function resolveActualBindingTargets(targets) {
|
|
12
218
|
const bindingTargets = [...targets];
|
|
13
|
-
if (targets
|
|
219
|
+
if (hasRequestRuntimeBinaryUsage(targets)) {
|
|
220
|
+
bindingTargets.push("TextEncoder", "TextDecoder");
|
|
221
|
+
bindingTargets.push("URL", "URLSearchParams", "Blob", "FormData");
|
|
222
|
+
}
|
|
14
223
|
return [...new Set(bindingTargets)];
|
|
15
224
|
}
|
|
16
225
|
function isPlaceholderRequestGlobal(value) {
|
|
@@ -50,6 +259,14 @@ function installSingleTarget(host, target) {
|
|
|
50
259
|
if (typeof host.Response !== "function" || isPlaceholderRequestGlobal(host.Response)) assignHostGlobal(host, "Response", ResponsePolyfill);
|
|
51
260
|
return;
|
|
52
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);
|
|
268
|
+
return;
|
|
269
|
+
}
|
|
53
270
|
if (target === "AbortController") {
|
|
54
271
|
if (typeof host.AbortController !== "function" || isPlaceholderRequestGlobal(host.AbortController)) assignHostGlobal(host, "AbortController", AbortControllerPolyfill);
|
|
55
272
|
return;
|
|
@@ -62,6 +279,34 @@ function installSingleTarget(host, target) {
|
|
|
62
279
|
if (typeof host.WebSocket !== "function" || isPlaceholderRequestGlobal(host.WebSocket)) assignHostGlobal(host, "WebSocket", WebSocketPolyfill);
|
|
63
280
|
return;
|
|
64
281
|
}
|
|
282
|
+
if (target === "atob") {
|
|
283
|
+
if (typeof host.atob !== "function" || isPlaceholderRequestGlobal(host.atob)) assignHostGlobal(host, "atob", atobPolyfill);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
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
|
+
}
|
|
65
310
|
if (target === "XMLHttpRequest" && (typeof host.XMLHttpRequest !== "function" || isPlaceholderRequestGlobal(host.XMLHttpRequest))) assignHostGlobal(host, "XMLHttpRequest", XMLHttpRequestPolyfill);
|
|
66
311
|
}
|
|
67
312
|
function installUrlGlobals(host) {
|
|
@@ -100,22 +345,31 @@ function syncWeappViteRequestGlobalsActuals(host, targets) {
|
|
|
100
345
|
}
|
|
101
346
|
}
|
|
102
347
|
/**
|
|
103
|
-
* @description
|
|
348
|
+
* @description 按需向小程序全局环境注入缺失的 Web Runtime 对象。
|
|
104
349
|
*/
|
|
105
|
-
function
|
|
106
|
-
const targets = options.targets ?? [
|
|
350
|
+
function installWebRuntimeGlobals(options = {}) {
|
|
351
|
+
const targets = resolveInstallTargets(options.targets ?? [
|
|
107
352
|
"fetch",
|
|
108
353
|
"Headers",
|
|
109
354
|
"Request",
|
|
110
355
|
"Response",
|
|
356
|
+
"TextEncoder",
|
|
357
|
+
"TextDecoder",
|
|
111
358
|
"AbortController",
|
|
112
359
|
"AbortSignal",
|
|
113
360
|
"XMLHttpRequest",
|
|
114
|
-
"WebSocket"
|
|
115
|
-
|
|
361
|
+
"WebSocket",
|
|
362
|
+
"atob",
|
|
363
|
+
"btoa",
|
|
364
|
+
"queueMicrotask",
|
|
365
|
+
"performance",
|
|
366
|
+
"crypto",
|
|
367
|
+
"Event",
|
|
368
|
+
"CustomEvent"
|
|
369
|
+
]);
|
|
116
370
|
const hosts = resolveRequestGlobalsHosts();
|
|
117
371
|
const primaryHost = resolveRequestGlobalsHost();
|
|
118
|
-
const needsUrlGlobals = targets
|
|
372
|
+
const needsUrlGlobals = hasRequestRuntimeBinaryUsage(targets);
|
|
119
373
|
ensureRuntimeHostAliases(primaryHost);
|
|
120
374
|
for (const host of hosts) {
|
|
121
375
|
if (needsUrlGlobals) installUrlGlobals(host);
|
|
@@ -132,10 +386,16 @@ function installRequestGlobals(options = {}) {
|
|
|
132
386
|
return hosts[0];
|
|
133
387
|
}
|
|
134
388
|
/**
|
|
389
|
+
* @description 已废弃,请迁移到 `installWebRuntimeGlobals`。
|
|
390
|
+
*/
|
|
391
|
+
function installRequestGlobals(options = {}) {
|
|
392
|
+
return installWebRuntimeGlobals(options);
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
135
395
|
* @description 仅安装 AbortController 与 AbortSignal 兼容层。
|
|
136
396
|
*/
|
|
137
397
|
function installAbortGlobals() {
|
|
138
|
-
return
|
|
398
|
+
return installWebRuntimeGlobals({ targets: ["AbortController", "AbortSignal"] });
|
|
139
399
|
}
|
|
140
400
|
//#endregion
|
|
141
|
-
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
|
@@ -64,20 +64,32 @@ function cloneArrayBufferView(view) {
|
|
|
64
64
|
copied.set(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));
|
|
65
65
|
return copied.buffer;
|
|
66
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
|
+
}
|
|
67
73
|
function encodeText(value) {
|
|
68
74
|
if (typeof TextEncoder === "function") return new TextEncoder().encode(value).buffer;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
+
}
|
|
72
86
|
}
|
|
73
87
|
function decodeText(value) {
|
|
74
88
|
if (typeof TextDecoder === "function") return new TextDecoder().decode(value);
|
|
75
|
-
|
|
76
|
-
for (const byte of new Uint8Array(value)) text += String.fromCharCode(byte);
|
|
77
|
-
return text;
|
|
89
|
+
return decodeTextFallback(value);
|
|
78
90
|
}
|
|
79
91
|
function normalizeHeaderName(name) {
|
|
80
92
|
return name.trim().toLowerCase();
|
|
81
93
|
}
|
|
82
94
|
//#endregion
|
|
83
|
-
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.6",
|
|
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,7 +70,7 @@
|
|
|
70
70
|
"node": "^20.19.0 || >=22.12.0"
|
|
71
71
|
},
|
|
72
72
|
"dependencies": {
|
|
73
|
-
"@weapp-core/constants": "0.1.
|
|
73
|
+
"@weapp-core/constants": "^0.1.1",
|
|
74
74
|
"@wevu/api": "0.2.3"
|
|
75
75
|
},
|
|
76
76
|
"publishConfig": {
|