@fast-china/utils 2.0.0 → 2.0.2
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/CHANGELOG.md +27 -0
- package/Fast.png +0 -0
- package/README.md +27 -29
- package/README.zh.md +27 -29
- package/dist/base64/index.mjs.map +1 -1
- package/dist/crypto/index.d.mts +265 -96
- package/dist/crypto/index.mjs +563 -261
- package/dist/crypto/index.mjs.map +1 -1
- package/dist/identity/index.d.mts +5 -5
- package/dist/identity/index.mjs +2 -2
- package/dist/identity/index.mjs.map +1 -1
- package/dist/index.d.mts +3 -3
- package/dist/index.global.min.js +3 -0
- package/dist/index.global.min.js.map +1 -0
- package/dist/index.mjs +2 -2
- package/dist/storage/index.d.mts +11 -8
- package/dist/storage/index.mjs +21 -18
- package/dist/storage/index.mjs.map +1 -1
- package/dist/vue/emits.mjs.map +1 -1
- package/dist/vue/index.d.mts +2 -2
- package/dist/vue/install.d.mts +11 -29
- package/dist/vue/install.mjs +25 -25
- package/dist/vue/install.mjs.map +1 -1
- package/dist/vue/props.mjs.map +1 -1
- package/dist/vue/render.d.mts +2 -3
- package/dist/vue/render.mjs +3 -9
- package/dist/vue/render.mjs.map +1 -1
- package/docs/API.md +30 -14
- package/docs/API.zh-CN.md +30 -14
- package/docs/DEVELOPMENT_RELEASE.zh-CN.md +4 -4
- package/docs/RUNTIME_CONTRACT.md +10 -10
- package/package.json +9 -11
- package/dist/array/index.d.mts.map +0 -1
- package/dist/async/index.d.mts.map +0 -1
- package/dist/base64/index.d.mts.map +0 -1
- package/dist/color/index.d.mts.map +0 -1
- package/dist/crypto/index.d.mts.map +0 -1
- package/dist/date/index.d.mts.map +0 -1
- package/dist/dom/style.d.mts.map +0 -1
- package/dist/env/index.d.mts.map +0 -1
- package/dist/identity/index.d.mts.map +0 -1
- package/dist/logger/index.d.mts.map +0 -1
- package/dist/number/index.d.mts.map +0 -1
- package/dist/object/index.d.mts.map +0 -1
- package/dist/storage/index.d.mts.map +0 -1
- package/dist/string/index.d.mts.map +0 -1
- package/dist/vue/emits.d.mts.map +0 -1
- package/dist/vue/expose.d.mts.map +0 -1
- package/dist/vue/func.d.mts.map +0 -1
- package/dist/vue/install.d.mts.map +0 -1
- package/dist/vue/props.d.mts.map +0 -1
- package/dist/vue/render.d.mts.map +0 -1
- package/dist/vue/slots.d.mts.map +0 -1
- package/dist/vue/with.d.mts.map +0 -1
- package/src/array/index.ts +0 -173
- package/src/async/index.ts +0 -475
- package/src/base64/index.ts +0 -374
- package/src/color/index.ts +0 -208
- package/src/crypto/index.ts +0 -670
- package/src/date/index.ts +0 -451
- package/src/dom/index.ts +0 -6
- package/src/dom/style.ts +0 -92
- package/src/env/index.ts +0 -169
- package/src/identity/index.ts +0 -144
- package/src/index.ts +0 -20
- package/src/internal/text.ts +0 -46
- package/src/logger/index.ts +0 -219
- package/src/number/index.ts +0 -235
- package/src/object/index.ts +0 -160
- package/src/storage/index.ts +0 -524
- package/src/string/index.ts +0 -328
- package/src/vue/emits.ts +0 -71
- package/src/vue/expose.ts +0 -11
- package/src/vue/func.ts +0 -17
- package/src/vue/index.ts +0 -13
- package/src/vue/install.ts +0 -185
- package/src/vue/props.ts +0 -39
- package/src/vue/render.ts +0 -41
- package/src/vue/slots.ts +0 -23
- package/src/vue/with.ts +0 -10
package/src/env/index.ts
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
/** 可识别的主要 JavaScript 运行环境。 */
|
|
2
|
-
export type RuntimeKind = "browser" | "node" | "unknown" | "worker";
|
|
3
|
-
|
|
4
|
-
/** 环境检测需要逐项确认的 SubtleCrypto 最小能力集合。 */
|
|
5
|
-
type RuntimeSubtleCrypto = Partial<
|
|
6
|
-
Pick<SubtleCrypto, "decrypt" | "deriveBits" | "deriveKey" | "digest" | "encrypt" | "exportKey" | "generateKey" | "importKey" | "sign" | "verify">
|
|
7
|
-
>;
|
|
8
|
-
|
|
9
|
-
/** 环境检测读取的 Web Crypto 最小视图。 */
|
|
10
|
-
interface RuntimeEnvironmentCrypto extends Partial<Pick<Crypto, "getRandomValues">> {
|
|
11
|
-
/** 可选 SubtleCrypto 能力;只有所需方法全部存在时才视为完整 Web Crypto。 */
|
|
12
|
-
subtle?: RuntimeSubtleCrypto;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
/** 环境检测读取的最小 Navigator 视图。 */
|
|
16
|
-
interface RuntimeNavigator {
|
|
17
|
-
/** 平台报告的最大同时触点数;类型异常时按 `0` 处理。 */
|
|
18
|
-
maxTouchPoints?: unknown;
|
|
19
|
-
/** 平台报告的 User-Agent;类型异常时按空字符串处理。 */
|
|
20
|
-
userAgent?: unknown;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/** 环境检测读取的最小 Node 进程视图。 */
|
|
24
|
-
interface RuntimeProcess {
|
|
25
|
-
/** 可选运行时版本表。 */
|
|
26
|
-
versions?: RuntimeVersions;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
/** 环境检测读取的最小运行时版本表。 */
|
|
30
|
-
interface RuntimeVersions {
|
|
31
|
-
/** Node.js 版本文本;存在字符串值时识别为 Node 环境。 */
|
|
32
|
-
node?: unknown;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** 环境检测读取的最小 Window 视图。 */
|
|
36
|
-
interface RuntimeWindow {
|
|
37
|
-
/** DOM 文档标记;只检查是否为非空对象。 */
|
|
38
|
-
document?: unknown;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/** 可选平台全局对象的结构化视图,避免导入 Node 或 uni-app 全局类型。 */
|
|
42
|
-
interface RuntimeGlobals {
|
|
43
|
-
/** 可选 Web Crypto 能力;所有方法都在调用前逐项检查,不因对象存在而假定完整实现。 */
|
|
44
|
-
crypto?: RuntimeEnvironmentCrypto;
|
|
45
|
-
/** Web Worker 中通常存在的脚本导入函数;只检查其类型,不会在检测阶段调用。 */
|
|
46
|
-
importScripts?: unknown;
|
|
47
|
-
/** 浏览器或 WebView 暴露的最小 Navigator 字段;未知类型会被能力读取函数视为缺失。 */
|
|
48
|
-
navigator?: RuntimeNavigator;
|
|
49
|
-
/** 工具或测试环境可能暴露的 Node 版本标记;仅用于检测,不代表 Node 属于应用运行时契约。 */
|
|
50
|
-
process?: RuntimeProcess;
|
|
51
|
-
/** uni-app 平台标记;Storage 会在调用 `configureStorage` 时读取并校验该全局对象。 */
|
|
52
|
-
uni?: unknown;
|
|
53
|
-
/** 浏览器 Window 的最小结构;`document` 只用于能力判定,不在模块导入阶段读取 DOM 内容。 */
|
|
54
|
-
window?: RuntimeWindow | null;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const runtimeGlobals = globalThis as unknown as RuntimeGlobals;
|
|
58
|
-
|
|
59
|
-
/**
|
|
60
|
-
* 延迟读取当前 User-Agent。
|
|
61
|
-
*
|
|
62
|
-
* @returns Navigator 不存在或字段类型异常时返回空字符串。
|
|
63
|
-
*/
|
|
64
|
-
const currentUserAgent = (): string => (typeof runtimeGlobals.navigator?.userAgent === "string" ? runtimeGlobals.navigator.userAgent : "");
|
|
65
|
-
/**
|
|
66
|
-
* 延迟读取当前设备报告的最大触点数。
|
|
67
|
-
*
|
|
68
|
-
* @returns Navigator 不存在或字段类型异常时返回 `0`。
|
|
69
|
-
*/
|
|
70
|
-
const currentTouchPoints = (): number => (typeof runtimeGlobals.navigator?.maxTouchPoints === "number" ? runtimeGlobals.navigator.maxTouchPoints : 0);
|
|
71
|
-
|
|
72
|
-
/**
|
|
73
|
-
* 判断当前运行时是否具有浏览器 `window` 与 `document`。
|
|
74
|
-
*
|
|
75
|
-
* @returns 两项能力均存在时返回 `true`;不读取 DOM 内容。
|
|
76
|
-
*/
|
|
77
|
-
export function isBrowser(): boolean {
|
|
78
|
-
const window = runtimeGlobals.window;
|
|
79
|
-
return window !== undefined && window !== null && window.document !== null && typeof window.document === "object";
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/**
|
|
83
|
-
* 判断当前运行时是否像 Web Worker 且不是 Window。
|
|
84
|
-
*
|
|
85
|
-
* @remarks 经典、模块、Shared 与 Service Worker 全局通常都暴露 `importScripts`;模块
|
|
86
|
-
* Worker 中调用它可能抛错,本检测只检查能力存在,不会执行。
|
|
87
|
-
* @returns 具有 `importScripts` 且不是浏览器 Window 时返回 `true`。
|
|
88
|
-
*/
|
|
89
|
-
export function isWebWorker(): boolean {
|
|
90
|
-
return !isBrowser() && typeof runtimeGlobals.importScripts === "function";
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* 判断当前运行时是否暴露 Node.js 版本标记。
|
|
95
|
-
*
|
|
96
|
-
* @returns `process.versions.node` 为字符串时返回 `true`。
|
|
97
|
-
*/
|
|
98
|
-
export function isNode(): boolean {
|
|
99
|
-
return typeof runtimeGlobals.process?.versions?.node === "string";
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
/**
|
|
103
|
-
* 判断当前运行时是否暴露 uni-app 的 `uni` 全局对象。
|
|
104
|
-
*
|
|
105
|
-
* @returns 全局属性存在且不为 `undefined` 时返回 `true`;不调用任何平台 API。
|
|
106
|
-
*/
|
|
107
|
-
export function isUniApp(): boolean {
|
|
108
|
-
return runtimeGlobals.uni !== undefined;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* 判断当前运行时是否具备本库完整加密 API 所需的 Web Crypto 能力。
|
|
113
|
-
*
|
|
114
|
-
* @remarks 只具有 `getRandomValues` 的平台仍可调用随机数与随机字符串 API,但本函数
|
|
115
|
-
* 会返回 `false`,因为摘要、PBKDF2、AES-GCM、RSA 与 ECC 还需要完整的 `SubtleCrypto` 方法集。
|
|
116
|
-
* @returns 同时提供本库 Web Crypto 功能所需方法时返回 `true`。
|
|
117
|
-
*/
|
|
118
|
-
export function hasWebCrypto(): boolean {
|
|
119
|
-
const crypto = runtimeGlobals.crypto;
|
|
120
|
-
const subtle = crypto?.subtle;
|
|
121
|
-
return (
|
|
122
|
-
typeof crypto?.getRandomValues === "function" &&
|
|
123
|
-
typeof subtle?.decrypt === "function" &&
|
|
124
|
-
typeof subtle.deriveBits === "function" &&
|
|
125
|
-
typeof subtle.deriveKey === "function" &&
|
|
126
|
-
typeof subtle.digest === "function" &&
|
|
127
|
-
typeof subtle.encrypt === "function" &&
|
|
128
|
-
typeof subtle.exportKey === "function" &&
|
|
129
|
-
typeof subtle.generateKey === "function" &&
|
|
130
|
-
typeof subtle.importKey === "function" &&
|
|
131
|
-
typeof subtle.sign === "function" &&
|
|
132
|
-
typeof subtle.verify === "function"
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
/**
|
|
137
|
-
* 返回当前主要运行环境。
|
|
138
|
-
*
|
|
139
|
-
* @remarks 在使用 DOM 模拟器的 Node.js 进程中优先报告 `browser`,因为可观察能力比宿主进程名称更有用。
|
|
140
|
-
* @returns `browser`、`worker`、`node` 或无法识别时的 `unknown`。
|
|
141
|
-
*/
|
|
142
|
-
export function detectRuntime(): RuntimeKind {
|
|
143
|
-
if (isBrowser()) return "browser";
|
|
144
|
-
if (isWebWorker()) return "worker";
|
|
145
|
-
if (isNode()) return "node";
|
|
146
|
-
return "unknown";
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
/**
|
|
150
|
-
* 基于 User-Agent 启发式判断手机设备。
|
|
151
|
-
*
|
|
152
|
-
* @param userAgent - 默认读取当前 `navigator.userAgent`;平台对象不存在时使用空字符串。
|
|
153
|
-
* @remarks User-Agent 可以被伪造,不得用于鉴权、安全策略或永久功能分流。
|
|
154
|
-
* @returns 命中手机特征时返回 `true`。
|
|
155
|
-
*/
|
|
156
|
-
export function isMobileUserAgent(userAgent: string = currentUserAgent()): boolean {
|
|
157
|
-
return /Mobile|iPhone|Android.*Mobile|Windows Phone/iu.test(userAgent);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/**
|
|
161
|
-
* 基于 User-Agent 与触点数量启发式判断平板设备。
|
|
162
|
-
*
|
|
163
|
-
* @param userAgent - 默认读取当前 User-Agent。
|
|
164
|
-
* @param maxTouchPoints - 用于识别桌面 User-Agent 模式下的 iPadOS,默认读取当前触点数。
|
|
165
|
-
* @returns 命中平板特征时返回 `true`。
|
|
166
|
-
*/
|
|
167
|
-
export function isTabletUserAgent(userAgent: string = currentUserAgent(), maxTouchPoints: number = currentTouchPoints()): boolean {
|
|
168
|
-
return /iPad|Android(?!.*Mobile)|Tablet/iu.test(userAgent) || (/Macintosh/iu.test(userAgent) && maxTouchPoints > 1);
|
|
169
|
-
}
|
package/src/identity/index.ts
DELETED
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import { Local } from "../storage/index.js";
|
|
2
|
-
import { generateUuidV4, isUuidV4 } from "../string/index.js";
|
|
3
|
-
|
|
4
|
-
const defaultInstallationIdentityStorageKey = "identity:installation-id";
|
|
5
|
-
|
|
6
|
-
/** {@link configureInstallationIdentity} 接收的安装标识配置。 */
|
|
7
|
-
export interface InstallationIdentityConfiguration {
|
|
8
|
-
/**
|
|
9
|
-
* `Local` 中使用的业务键,默认 `identity:installation-id`。
|
|
10
|
-
*
|
|
11
|
-
* @remarks 必须是无外围空白的非空字符串,并在首次访问 Identity API 前配置;物理键仍会叠加 Storage 全局前缀。
|
|
12
|
-
*/
|
|
13
|
-
cacheKey?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** 浏览器或 uni-app 当前安装实例标识。 */
|
|
17
|
-
export interface InstallationIdentity {
|
|
18
|
-
/**
|
|
19
|
-
* `Local` 中使用的业务键。
|
|
20
|
-
*
|
|
21
|
-
* @remarks 首次读取会锁定默认配置;之后不能再切换为其他业务键。
|
|
22
|
-
*/
|
|
23
|
-
readonly cacheKey: string;
|
|
24
|
-
/**
|
|
25
|
-
* 当前内存中的安装标识;尚未取得标识或调用 {@link InstallationIdentity.clear clear} 后为空字符串。
|
|
26
|
-
*
|
|
27
|
-
* @remarks 直接赋值只改变内存,不会校验或持久化;通常应调用 {@link InstallationIdentity.getOrCreate getOrCreate}。
|
|
28
|
-
*/
|
|
29
|
-
deviceId: string;
|
|
30
|
-
/**
|
|
31
|
-
* 删除当前 `cacheKey` 对应的持久化标识,并把 `deviceId` 重置为空字符串。
|
|
32
|
-
*
|
|
33
|
-
* @throws `Error` 当 Storage 尚未配置或当前平台存储不可用。
|
|
34
|
-
*/
|
|
35
|
-
clear: () => void;
|
|
36
|
-
/**
|
|
37
|
-
* 按“显式参数、当前内存、持久化值、安全生成值”的优先级取得安装标识。
|
|
38
|
-
*
|
|
39
|
-
* @param installationId - 可选 UUID v4;传入时覆盖内存值和当前持久化值。
|
|
40
|
-
* @returns 已校验并同时写入 `deviceId` 与 `Local` 的 UUID v4。
|
|
41
|
-
* @throws `TypeError` 当显式参数、内存值或持久化值不是 UUID v4。
|
|
42
|
-
* @throws `Error` 当 Storage 尚未配置,或生成新值时平台缺少 Web Crypto。
|
|
43
|
-
*/
|
|
44
|
-
getOrCreate: (installationId?: string) => string;
|
|
45
|
-
/**
|
|
46
|
-
* 读取并校验当前 `cacheKey` 对应的持久化标识。
|
|
47
|
-
*
|
|
48
|
-
* @remarks 该方法不修改 `deviceId`,只负责读取;过期记录由 Storage 视为缺失。
|
|
49
|
-
* @returns 已持久化的 UUID v4;键缺失或过期时返回 `undefined`。
|
|
50
|
-
* @throws `TypeError` 当持久化值不是字符串或不是 UUID v4。
|
|
51
|
-
* @throws `Error` 当 Storage 尚未配置或当前平台存储不可用。
|
|
52
|
-
*/
|
|
53
|
-
read: () => string | undefined;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/**
|
|
57
|
-
* 校验安装标识格式。
|
|
58
|
-
*
|
|
59
|
-
* @param value - 外部传入或从 Storage 读取的候选值。
|
|
60
|
-
* @throws `TypeError` 当值不是 RFC 4122 UUID v4。
|
|
61
|
-
*/
|
|
62
|
-
const assertInstallationId = (value: string): void => {
|
|
63
|
-
if (!isUuidV4(value)) throw new TypeError("Installation Identity values must be RFC 4122 version 4 UUIDs.");
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
let activeStorageKey: string | undefined;
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 取得已经锁定的安装标识业务键。
|
|
70
|
-
*
|
|
71
|
-
* @remarks 首次读取会锁定默认值,防止标识已经写入后再切换键而产生两个安装标识。
|
|
72
|
-
* @returns 应用于后续全部 Identity 操作的业务键。
|
|
73
|
-
*/
|
|
74
|
-
const getInstallationIdentityStorageKey = (): string => {
|
|
75
|
-
activeStorageKey ??= defaultInstallationIdentityStorageKey;
|
|
76
|
-
return activeStorageKey;
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* 在应用入口配置安装标识使用的 Storage 业务键。
|
|
81
|
-
*
|
|
82
|
-
* @remarks 必须在首次读取 `installationIdentity.cacheKey` 或调用其他安装标识 API 前执行。相同配置
|
|
83
|
-
* 可以幂等重复调用;切换到不同键会抛错,避免同一页面产生分裂状态。
|
|
84
|
-
* @param options - 安装标识配置;省略 `cacheKey` 时使用 `identity:installation-id`。
|
|
85
|
-
* @throws `TypeError` 当 `cacheKey` 不是非空字符串或包含外围空白。
|
|
86
|
-
* @throws `Error` 当安装标识已经使用另一个业务键初始化。
|
|
87
|
-
*/
|
|
88
|
-
export function configureInstallationIdentity(options: InstallationIdentityConfiguration = {}): void {
|
|
89
|
-
const cacheKey = options.cacheKey ?? defaultInstallationIdentityStorageKey;
|
|
90
|
-
if (typeof cacheKey !== "string" || cacheKey.length === 0 || cacheKey.trim() !== cacheKey) {
|
|
91
|
-
throw new TypeError("Installation Identity cacheKey must be a non-empty string without surrounding whitespace.");
|
|
92
|
-
}
|
|
93
|
-
if (activeStorageKey === undefined) {
|
|
94
|
-
activeStorageKey = cacheKey;
|
|
95
|
-
return;
|
|
96
|
-
}
|
|
97
|
-
if (activeStorageKey !== cacheKey) throw new Error("Installation Identity has already been configured with a different cacheKey.");
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* 全局安装标识状态。
|
|
102
|
-
*
|
|
103
|
-
* @remarks 使用前必须在应用入口调用 `configureStorage()`。默认随机源只使用 Web Crypto,
|
|
104
|
-
* 能力缺失时明确抛错,不回退到 `Math.random()`。该值不是硬件标识、认证凭证或安全边界。
|
|
105
|
-
*/
|
|
106
|
-
export const installationIdentity: InstallationIdentity = {
|
|
107
|
-
get cacheKey(): string {
|
|
108
|
-
return getInstallationIdentityStorageKey();
|
|
109
|
-
},
|
|
110
|
-
deviceId: "",
|
|
111
|
-
clear(): void {
|
|
112
|
-
Local.remove(installationIdentity.cacheKey);
|
|
113
|
-
installationIdentity.deviceId = "";
|
|
114
|
-
},
|
|
115
|
-
getOrCreate(installationId?: string): string {
|
|
116
|
-
const candidate =
|
|
117
|
-
installationId ??
|
|
118
|
-
(installationIdentity.deviceId.length > 0 ? installationIdentity.deviceId : installationIdentity.read()) ??
|
|
119
|
-
generateUuidV4();
|
|
120
|
-
assertInstallationId(candidate);
|
|
121
|
-
Local.set(installationIdentity.cacheKey, candidate);
|
|
122
|
-
installationIdentity.deviceId = candidate;
|
|
123
|
-
return candidate;
|
|
124
|
-
},
|
|
125
|
-
read(): string | undefined {
|
|
126
|
-
const stored = Local.get(installationIdentity.cacheKey);
|
|
127
|
-
if (stored === undefined) return undefined;
|
|
128
|
-
if (typeof stored !== "string") throw new TypeError("The stored identity is corrupted.");
|
|
129
|
-
assertInstallationId(stored);
|
|
130
|
-
return stored;
|
|
131
|
-
},
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* 返回已有安装标识,否则创建并持久化一个安全 UUID v4。
|
|
136
|
-
*
|
|
137
|
-
* @param installationId - 可选的显式安装标识;传入时会校验并覆盖当前持久化值。
|
|
138
|
-
* @returns 显式值、内存值、持久化值或新生成值中的最终安装标识。
|
|
139
|
-
* @throws `TypeError` 当显式值或持久化值不是 UUID v4。
|
|
140
|
-
* @throws `Error` 当 Storage 尚未配置或平台缺少 Web Crypto。
|
|
141
|
-
*/
|
|
142
|
-
export function getOrCreateInstallationId(installationId?: string): string {
|
|
143
|
-
return installationIdentity.getOrCreate(installationId);
|
|
144
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fast.Utils public API.
|
|
3
|
-
*
|
|
4
|
-
* @packageDocumentation
|
|
5
|
-
*/
|
|
6
|
-
export * from "./array/index.js";
|
|
7
|
-
export * from "./async/index.js";
|
|
8
|
-
export * from "./base64/index.js";
|
|
9
|
-
export * from "./color/index.js";
|
|
10
|
-
export * from "./crypto/index.js";
|
|
11
|
-
export * from "./date/index.js";
|
|
12
|
-
export * from "./dom/index.js";
|
|
13
|
-
export * from "./env/index.js";
|
|
14
|
-
export * from "./identity/index.js";
|
|
15
|
-
export * from "./logger/index.js";
|
|
16
|
-
export * from "./number/index.js";
|
|
17
|
-
export * from "./object/index.js";
|
|
18
|
-
export * from "./storage/index.js";
|
|
19
|
-
export * from "./string/index.js";
|
|
20
|
-
export * from "./vue/index.js";
|
package/src/internal/text.ts
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
/** 延迟访问 Encoding API 时使用的平台全局对象最小视图。 */
|
|
2
|
-
interface RuntimeEncodingGlobals {
|
|
3
|
-
/** 可选 TextDecoder 构造器;缺失时只允许不依赖文本解码的 API 继续工作。 */
|
|
4
|
-
TextDecoder?: typeof TextDecoder;
|
|
5
|
-
/** 可选 TextEncoder 构造器;缺失时只允许纯字节 API 继续工作。 */
|
|
6
|
-
TextEncoder?: typeof TextEncoder;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const runtimeEncodingGlobals = globalThis as unknown as RuntimeEncodingGlobals;
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* 延迟解析 UTF-8 TextDecoder,确保模块导入阶段不依赖 Encoding API。
|
|
13
|
-
*
|
|
14
|
-
* @returns 启用 Fatal 模式的新解码器,非法 UTF-8 会直接失败。
|
|
15
|
-
* @throws `Error` 当当前平台没有提供 `TextDecoder`。
|
|
16
|
-
*/
|
|
17
|
-
export const getTextDecoder = (): TextDecoder => {
|
|
18
|
-
const TextDecoderConstructor = runtimeEncodingGlobals.TextDecoder;
|
|
19
|
-
if (typeof TextDecoderConstructor !== "function") {
|
|
20
|
-
throw new Error("TextDecoder is unavailable in the current runtime.");
|
|
21
|
-
}
|
|
22
|
-
return new TextDecoderConstructor("utf-8", { fatal: true });
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* 延迟解析 TextEncoder,让纯字节 API 在缺少 Encoding API 的平台仍可导入。
|
|
27
|
-
*
|
|
28
|
-
* @returns 新建的 UTF-8 编码器。
|
|
29
|
-
* @throws `Error` 当当前平台没有提供 `TextEncoder`。
|
|
30
|
-
*/
|
|
31
|
-
export const getTextEncoder = (): TextEncoder => {
|
|
32
|
-
const TextEncoderConstructor = runtimeEncodingGlobals.TextEncoder;
|
|
33
|
-
if (typeof TextEncoderConstructor !== "function") {
|
|
34
|
-
throw new Error("TextEncoder is unavailable in the current runtime.");
|
|
35
|
-
}
|
|
36
|
-
return new TextEncoderConstructor();
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
/**
|
|
40
|
-
* 在确认平台能力后把 JavaScript 字符串编码为 UTF-8。
|
|
41
|
-
*
|
|
42
|
-
* @param value - 待编码文本。
|
|
43
|
-
* @returns 使用独立 ArrayBuffer 的 UTF-8 字节数组。
|
|
44
|
-
* @throws `Error` 当当前平台没有提供 `TextEncoder`。
|
|
45
|
-
*/
|
|
46
|
-
export const encodeUtf8 = (value: string): Uint8Array<ArrayBuffer> => getTextEncoder().encode(value);
|
package/src/logger/index.ts
DELETED
|
@@ -1,219 +0,0 @@
|
|
|
1
|
-
/** 日志严重级别,按从低到高排列。 */
|
|
2
|
-
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
3
|
-
|
|
4
|
-
/** 日志输出目标需要实现的最小控制台接口。 */
|
|
5
|
-
export interface LoggerSink {
|
|
6
|
-
/**
|
|
7
|
-
* 接收通过级别过滤后的调试参数。
|
|
8
|
-
* @param data - 已格式化的品牌、作用域、消息以及保持原始类型的附加值。
|
|
9
|
-
*/
|
|
10
|
-
debug: (...data: unknown[]) => void;
|
|
11
|
-
/**
|
|
12
|
-
* 接收通过级别过滤后的普通信息参数;对应 Logger 的 `info` 级别。
|
|
13
|
-
* @param data - 已格式化的品牌、作用域、消息以及保持原始类型的附加值。
|
|
14
|
-
*/
|
|
15
|
-
log: (...data: unknown[]) => void;
|
|
16
|
-
/**
|
|
17
|
-
* 接收通过级别过滤后的警告参数。
|
|
18
|
-
* @param data - 已格式化的品牌、作用域、消息以及保持原始类型的附加值。
|
|
19
|
-
*/
|
|
20
|
-
warn: (...data: unknown[]) => void;
|
|
21
|
-
/**
|
|
22
|
-
* 接收通过级别过滤后的错误参数。
|
|
23
|
-
* @param data - 已格式化的品牌、作用域、消息以及保持原始类型的附加值。
|
|
24
|
-
*/
|
|
25
|
-
error: (...data: unknown[]) => void;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/** {@link createLogger} 的不可变配置。 */
|
|
29
|
-
export interface LoggerOptions {
|
|
30
|
-
/** 最低输出级别,默认 `info`;低于该优先级的消息不会传给 Sink。 */
|
|
31
|
-
level?: LogLevel;
|
|
32
|
-
/** 日志品牌前缀,默认 `Fast`;必须是无外围空白的非空字符串。 */
|
|
33
|
-
prefix?: string;
|
|
34
|
-
/** 可注入输出目标,默认当前运行时的 `console`;Logger 不会修改该对象。 */
|
|
35
|
-
sink?: LoggerSink;
|
|
36
|
-
/** uni-app App-Plus/HBuilderX 中把附加参数逐条转成单行文本输出,默认 `false`;其他平台忽略。 */
|
|
37
|
-
uniAppPlusSplit?: boolean;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/** 配置隔离、无全局可变状态的轻量日志器。 */
|
|
41
|
-
export interface Logger {
|
|
42
|
-
/**
|
|
43
|
-
* 输出指定作用域的调试信息。
|
|
44
|
-
* @param scope - 模块、组件或业务来源名称。
|
|
45
|
-
* @param message - 主消息文本。
|
|
46
|
-
* @param data - 保持原始类型的附加值。
|
|
47
|
-
* @throws `TypeError` 或 `RangeError` 当作用域不是无外围空白的非空字符串。
|
|
48
|
-
*/
|
|
49
|
-
debug: (scope: string, message: string, ...data: unknown[]) => void;
|
|
50
|
-
/**
|
|
51
|
-
* 输出指定作用域的普通信息。
|
|
52
|
-
* @param scope - 模块、组件或业务来源名称。
|
|
53
|
-
* @param message - 主消息文本。
|
|
54
|
-
* @param data - 保持原始类型的附加值。
|
|
55
|
-
* @throws `TypeError` 或 `RangeError` 当作用域不是无外围空白的非空字符串。
|
|
56
|
-
*/
|
|
57
|
-
info: (scope: string, message: string, ...data: unknown[]) => void;
|
|
58
|
-
/**
|
|
59
|
-
* 输出指定作用域的警告信息。
|
|
60
|
-
* @param scope - 模块、组件或业务来源名称。
|
|
61
|
-
* @param message - 主消息文本。
|
|
62
|
-
* @param data - 保持原始类型的附加值。
|
|
63
|
-
* @throws `TypeError` 或 `RangeError` 当作用域不是无外围空白的非空字符串。
|
|
64
|
-
*/
|
|
65
|
-
warn: (scope: string, message: string, ...data: unknown[]) => void;
|
|
66
|
-
/**
|
|
67
|
-
* 输出指定作用域的错误信息。
|
|
68
|
-
* @param scope - 模块、组件或业务来源名称。
|
|
69
|
-
* @param message - 主消息文本。
|
|
70
|
-
* @param data - 保持原始类型的附加值。
|
|
71
|
-
* @throws `TypeError` 或 `RangeError` 当作用域不是无外围空白的非空字符串。
|
|
72
|
-
*/
|
|
73
|
-
error: (scope: string, message: string, ...data: unknown[]) => void;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const levelPriority: Readonly<Record<LogLevel, number>> = {
|
|
77
|
-
debug: 10,
|
|
78
|
-
info: 20,
|
|
79
|
-
warn: 30,
|
|
80
|
-
error: 40,
|
|
81
|
-
};
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* 判断未知值是否为受支持日志级别。
|
|
85
|
-
*
|
|
86
|
-
* @param value - 待检查配置值。
|
|
87
|
-
* @returns 值是 `debug`、`info`、`warn` 或 `error` 时返回 `true`。
|
|
88
|
-
*/
|
|
89
|
-
const isLogLevel = (value: unknown): value is LogLevel => typeof value === "string" && Object.hasOwn(levelPriority, value);
|
|
90
|
-
|
|
91
|
-
/** uni-app App-Plus 检测所需的平台全局对象最小视图。 */
|
|
92
|
-
interface RuntimeLoggerGlobals {
|
|
93
|
-
/** App-Plus 原生运行时标记。 */
|
|
94
|
-
plus?: unknown;
|
|
95
|
-
/** uni-app 运行时标记。 */
|
|
96
|
-
uni?: unknown;
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
const runtimeLoggerGlobals = globalThis as unknown as RuntimeLoggerGlobals;
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* 检测 uni-app App-Plus 日志环境。
|
|
103
|
-
*
|
|
104
|
-
* @returns 全局 `uni` 与 `plus` 同时存在时返回 `true`。
|
|
105
|
-
*/
|
|
106
|
-
const isUniAppPlus = (): boolean => {
|
|
107
|
-
return runtimeLoggerGlobals.uni !== undefined && runtimeLoggerGlobals.plus !== undefined;
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
/**
|
|
111
|
-
* 把日志附加值转换为适合 HBuilderX 单行输出的文本。
|
|
112
|
-
*
|
|
113
|
-
* @remarks 循环引用会替换为 `[Circular]`,BigInt 保留 `n` 后缀,Error 优先输出堆栈。
|
|
114
|
-
* @param value - 任意日志附加值。
|
|
115
|
-
* @returns 不会因 JSON 序列化失败而中断日志调用的文本。
|
|
116
|
-
*/
|
|
117
|
-
const formatSplitValue = (value: unknown): string => {
|
|
118
|
-
if (typeof value === "string") return value;
|
|
119
|
-
if (typeof value === "bigint") return `${value.toString()}n`;
|
|
120
|
-
if (value instanceof Error) return value.stack ?? `${value.name}: ${value.message}`;
|
|
121
|
-
const visited = new WeakSet();
|
|
122
|
-
try {
|
|
123
|
-
const serialized: unknown = JSON.stringify(
|
|
124
|
-
value,
|
|
125
|
-
(_key, item: unknown): unknown => {
|
|
126
|
-
if (typeof item === "bigint") return `${item.toString()}n`;
|
|
127
|
-
if (typeof item !== "object" || item === null) return item;
|
|
128
|
-
if (visited.has(item)) return "[Circular]";
|
|
129
|
-
visited.add(item);
|
|
130
|
-
return item;
|
|
131
|
-
},
|
|
132
|
-
2
|
|
133
|
-
);
|
|
134
|
-
return typeof serialized === "string" ? serialized : String(value);
|
|
135
|
-
} catch {
|
|
136
|
-
return String(value);
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
const defaultConsoleSink: LoggerSink = {
|
|
141
|
-
debug: (...data): void => {
|
|
142
|
-
if (typeof console.debug === "function") console.debug(...data);
|
|
143
|
-
else console.log(...data);
|
|
144
|
-
},
|
|
145
|
-
log: (...data): void => {
|
|
146
|
-
console.log(...data);
|
|
147
|
-
},
|
|
148
|
-
warn: (...data): void => {
|
|
149
|
-
console.warn(...data);
|
|
150
|
-
},
|
|
151
|
-
error: (...data): void => {
|
|
152
|
-
console.error(...data);
|
|
153
|
-
},
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
/**
|
|
157
|
-
* 创建独立日志器。
|
|
158
|
-
*
|
|
159
|
-
* @remarks 本库其他模块不会自动记录、吞掉或转换异常。日志内容可能进入持久化平台,
|
|
160
|
-
* 调用方不得传入密码、令牌、密钥或完整个人数据。
|
|
161
|
-
* @param options - 级别、前缀、输出目标和 uni-app App-Plus 拆分选项。
|
|
162
|
-
* @returns 不会修改全局控制台或其他日志器配置的新实例。
|
|
163
|
-
* @throws `RangeError` 当级别未知,或前缀、作用域不是有效的非空字符串。
|
|
164
|
-
*/
|
|
165
|
-
export function createLogger(options: LoggerOptions = {}): Logger {
|
|
166
|
-
const requestedLevel: unknown = options.level ?? "info";
|
|
167
|
-
const requestedPrefix: unknown = options.prefix ?? "Fast";
|
|
168
|
-
const sink = options.sink ?? defaultConsoleSink;
|
|
169
|
-
if (!isLogLevel(requestedLevel)) throw new RangeError(`Unknown logger level: ${String(requestedLevel)}.`);
|
|
170
|
-
if (typeof requestedPrefix !== "string" || requestedPrefix.length === 0) {
|
|
171
|
-
throw new RangeError("Logger prefix must be a non-empty string.");
|
|
172
|
-
}
|
|
173
|
-
const level = requestedLevel;
|
|
174
|
-
const prefix = requestedPrefix;
|
|
175
|
-
const uniAppPlusSplit = options.uniAppPlusSplit ?? false;
|
|
176
|
-
|
|
177
|
-
/**
|
|
178
|
-
* 应用级别过滤、标题格式和平台输出策略。
|
|
179
|
-
*
|
|
180
|
-
* @param messageLevel - 本条消息的严重级别。
|
|
181
|
-
* @param scope - 模块、组件或业务来源名称。
|
|
182
|
-
* @param message - 主消息文本。
|
|
183
|
-
* @param data - 保持原始类型的附加值。
|
|
184
|
-
* @throws `RangeError` 当作用域不是非空字符串或包含外围空白。
|
|
185
|
-
*/
|
|
186
|
-
const write = (messageLevel: LogLevel, scope: string, message: string, data: readonly unknown[]): void => {
|
|
187
|
-
if (typeof scope !== "string") throw new TypeError("Logger scope must be a string.");
|
|
188
|
-
if (scope.length === 0 || scope.trim() !== scope) {
|
|
189
|
-
throw new RangeError("Logger scope must be a non-empty string without surrounding whitespace.");
|
|
190
|
-
}
|
|
191
|
-
if (levelPriority[messageLevel] < levelPriority[level]) return;
|
|
192
|
-
const heading = `[${prefix}:${scope}]`;
|
|
193
|
-
const sinkMethod: keyof LoggerSink = messageLevel === "info" ? "log" : messageLevel;
|
|
194
|
-
if (uniAppPlusSplit && isUniAppPlus()) {
|
|
195
|
-
sink[sinkMethod](`${heading} ${message}`);
|
|
196
|
-
for (const item of data) sink[sinkMethod](formatSplitValue(item));
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
sink[sinkMethod](heading, message, ...data);
|
|
200
|
-
};
|
|
201
|
-
|
|
202
|
-
return {
|
|
203
|
-
debug: (scope, message, ...data): void => {
|
|
204
|
-
write("debug", scope, message, data);
|
|
205
|
-
},
|
|
206
|
-
info: (scope, message, ...data): void => {
|
|
207
|
-
write("info", scope, message, data);
|
|
208
|
-
},
|
|
209
|
-
warn: (scope, message, ...data): void => {
|
|
210
|
-
write("warn", scope, message, data);
|
|
211
|
-
},
|
|
212
|
-
error: (scope, message, ...data): void => {
|
|
213
|
-
write("error", scope, message, data);
|
|
214
|
-
},
|
|
215
|
-
};
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
/** 默认使用 `Fast` 前缀和 `info` 级别的便捷日志器。 */
|
|
219
|
-
export const logger: Logger = createLogger();
|