@wevu/api 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +50 -9
- package/dist/index.cjs +228 -8
- package/dist/index.d.cts +66 -6
- package/dist/index.d.mts +66 -6
- package/dist/index.mjs +226 -7
- package/package.json +11 -6
- package/types/index.d.ts +26 -0
package/README.md
CHANGED
|
@@ -2,13 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## 简介
|
|
4
4
|
|
|
5
|
-
`@wevu/api`
|
|
5
|
+
`@wevu/api` 提供跨平台的小程序 API 封装,默认推荐 Promise 风格,同时兼容传统回调风格。
|
|
6
6
|
|
|
7
7
|
## 特性
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
9
|
+
- 动态代理,覆盖微信小程序全量 API
|
|
10
|
+
- 跨平台适配(微信/支付宝/百度/字节/QQ/快应用/京东/小红书/快手/淘宝等)
|
|
11
|
+
- Promise 风格优先,回调风格可用
|
|
12
|
+
- 支持显式注入平台适配器
|
|
12
13
|
|
|
13
14
|
## 安装
|
|
14
15
|
|
|
@@ -18,16 +19,56 @@ pnpm add @wevu/api
|
|
|
18
19
|
|
|
19
20
|
## 使用
|
|
20
21
|
|
|
22
|
+
### Promise 风格(推荐)
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
import { wpi } from '@wevu/api'
|
|
26
|
+
|
|
27
|
+
const res = await wpi.request({
|
|
28
|
+
url: 'https://example.com',
|
|
29
|
+
method: 'GET',
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
console.log(res)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### 回调风格(兼容)
|
|
36
|
+
|
|
21
37
|
```ts
|
|
22
|
-
import {
|
|
38
|
+
import { wpi } from '@wevu/api'
|
|
39
|
+
|
|
40
|
+
wpi.request({
|
|
41
|
+
url: 'https://example.com',
|
|
42
|
+
method: 'GET',
|
|
43
|
+
success(res) {
|
|
44
|
+
console.log(res)
|
|
45
|
+
},
|
|
46
|
+
fail(err) {
|
|
47
|
+
console.error(err)
|
|
48
|
+
},
|
|
49
|
+
})
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 显式注入平台适配器
|
|
53
|
+
|
|
54
|
+
```ts
|
|
55
|
+
import { createWeapi } from '@wevu/api'
|
|
56
|
+
|
|
57
|
+
const api = createWeapi({
|
|
58
|
+
adapter: wx,
|
|
59
|
+
platform: 'wx',
|
|
60
|
+
})
|
|
23
61
|
|
|
24
|
-
|
|
25
|
-
console.log(VERSION)
|
|
62
|
+
await api.getSystemInfo()
|
|
26
63
|
```
|
|
27
64
|
|
|
28
|
-
##
|
|
65
|
+
## 行为说明
|
|
29
66
|
|
|
30
|
-
|
|
67
|
+
- **只在不传回调时返回 Promise**
|
|
68
|
+
- 同步 API(`*Sync`)与事件 API(`onXxx/offXxx`)直接透传
|
|
69
|
+
- 缺失 API 时:
|
|
70
|
+
- 回调风格触发 `fail/complete`
|
|
71
|
+
- Promise 风格返回 rejected Promise
|
|
31
72
|
|
|
32
73
|
## 相关链接
|
|
33
74
|
|
package/dist/index.cjs
CHANGED
|
@@ -1,16 +1,236 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
|
|
1
2
|
|
|
2
|
-
//#region src/
|
|
3
|
+
//#region src/core/adapter.ts
|
|
4
|
+
const GLOBAL_ADAPTER_KEYS = [
|
|
5
|
+
{
|
|
6
|
+
platform: "wx",
|
|
7
|
+
key: "wx"
|
|
8
|
+
},
|
|
9
|
+
{
|
|
10
|
+
platform: "my",
|
|
11
|
+
key: "my"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
platform: "tt",
|
|
15
|
+
key: "tt"
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
platform: "qq",
|
|
19
|
+
key: "qq"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
platform: "swan",
|
|
23
|
+
key: "swan"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
platform: "ks",
|
|
27
|
+
key: "ks"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
platform: "jd",
|
|
31
|
+
key: "jd"
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
platform: "xhs",
|
|
35
|
+
key: "xhs"
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
platform: "dd",
|
|
39
|
+
key: "dd"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
platform: "qa",
|
|
43
|
+
key: "qa"
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
platform: "qapp",
|
|
47
|
+
key: "qapp"
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
platform: "uni",
|
|
51
|
+
key: "uni"
|
|
52
|
+
}
|
|
53
|
+
];
|
|
54
|
+
function resolveGlobalThis() {
|
|
55
|
+
if (typeof globalThis !== "undefined") return globalThis;
|
|
56
|
+
if (typeof window !== "undefined") return window;
|
|
57
|
+
}
|
|
58
|
+
function isAdapterCandidate(value) {
|
|
59
|
+
return typeof value === "object" || typeof value === "function";
|
|
60
|
+
}
|
|
3
61
|
/**
|
|
4
|
-
* @description
|
|
62
|
+
* @description 侦测当前运行环境的全局 API 对象
|
|
5
63
|
*/
|
|
6
|
-
function
|
|
7
|
-
|
|
64
|
+
function detectGlobalAdapter() {
|
|
65
|
+
const root = resolveGlobalThis();
|
|
66
|
+
if (!root) return {};
|
|
67
|
+
for (const item of GLOBAL_ADAPTER_KEYS) {
|
|
68
|
+
const candidate = root[item.key];
|
|
69
|
+
if (isAdapterCandidate(candidate)) return {
|
|
70
|
+
adapter: candidate,
|
|
71
|
+
platform: item.platform
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/core/utils.ts
|
|
79
|
+
function isPlainObject(value) {
|
|
80
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
8
81
|
}
|
|
82
|
+
function hasCallbacks(value) {
|
|
83
|
+
if (!isPlainObject(value)) return false;
|
|
84
|
+
return typeof value.success === "function" || typeof value.fail === "function" || typeof value.complete === "function";
|
|
85
|
+
}
|
|
86
|
+
function isSyncMethod(name) {
|
|
87
|
+
return name.endsWith("Sync");
|
|
88
|
+
}
|
|
89
|
+
function isEventMethod(name) {
|
|
90
|
+
return /^on[A-Z]/.test(name) || /^off[A-Z]/.test(name);
|
|
91
|
+
}
|
|
92
|
+
function shouldSkipPromise(name) {
|
|
93
|
+
return isSyncMethod(name) || isEventMethod(name);
|
|
94
|
+
}
|
|
95
|
+
function createNotSupportedError(methodName, platform) {
|
|
96
|
+
return { errMsg: `${platform ? `${platform}.${methodName}` : methodName}:fail method not supported` };
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
//#endregion
|
|
100
|
+
//#region src/core/createWeapi.ts
|
|
101
|
+
const INTERNAL_KEYS = new Set([
|
|
102
|
+
"setAdapter",
|
|
103
|
+
"getAdapter",
|
|
104
|
+
"platform",
|
|
105
|
+
"raw"
|
|
106
|
+
]);
|
|
107
|
+
function normalizePlatformName(value) {
|
|
108
|
+
return value || void 0;
|
|
109
|
+
}
|
|
110
|
+
function resolveOptionsArg(args) {
|
|
111
|
+
const nextArgs = args.slice();
|
|
112
|
+
const lastArg = nextArgs.length > 0 ? nextArgs[nextArgs.length - 1] : void 0;
|
|
113
|
+
if (isPlainObject(lastArg)) {
|
|
114
|
+
const options = { ...lastArg };
|
|
115
|
+
nextArgs[nextArgs.length - 1] = options;
|
|
116
|
+
return {
|
|
117
|
+
args: nextArgs,
|
|
118
|
+
options
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
const options = {};
|
|
122
|
+
nextArgs.push(options);
|
|
123
|
+
return {
|
|
124
|
+
args: nextArgs,
|
|
125
|
+
options
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function callWithPromise(context, method, args) {
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
const { args: nextArgs, options } = resolveOptionsArg(args);
|
|
131
|
+
let settled = false;
|
|
132
|
+
options.success = (res) => {
|
|
133
|
+
settled = true;
|
|
134
|
+
resolve(res);
|
|
135
|
+
};
|
|
136
|
+
options.fail = (err) => {
|
|
137
|
+
settled = true;
|
|
138
|
+
reject(err);
|
|
139
|
+
};
|
|
140
|
+
options.complete = (res) => {
|
|
141
|
+
if (!settled) resolve(res);
|
|
142
|
+
};
|
|
143
|
+
try {
|
|
144
|
+
method.apply(context, nextArgs);
|
|
145
|
+
} catch (err) {
|
|
146
|
+
reject(err);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
function callMissingApi(methodName, platform, args) {
|
|
151
|
+
const lastArg = args.length > 0 ? args[args.length - 1] : void 0;
|
|
152
|
+
const error = createNotSupportedError(methodName, platform);
|
|
153
|
+
if (hasCallbacks(lastArg)) {
|
|
154
|
+
lastArg.fail?.(error);
|
|
155
|
+
lastArg.complete?.(error);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
return Promise.reject(error);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* @description 创建跨平台 API 实例
|
|
162
|
+
*/
|
|
163
|
+
function createWeapi(options = {}) {
|
|
164
|
+
let adapter = options.adapter;
|
|
165
|
+
let platformName = normalizePlatformName(options.platform);
|
|
166
|
+
const cache = /* @__PURE__ */ new Map();
|
|
167
|
+
const resolveAdapter = () => {
|
|
168
|
+
if (adapter) return adapter;
|
|
169
|
+
const detected = detectGlobalAdapter();
|
|
170
|
+
if (detected.adapter) {
|
|
171
|
+
adapter = detected.adapter;
|
|
172
|
+
platformName = platformName ?? normalizePlatformName(detected.platform);
|
|
173
|
+
}
|
|
174
|
+
return adapter;
|
|
175
|
+
};
|
|
176
|
+
const setAdapter = (nextAdapter, nextPlatform) => {
|
|
177
|
+
adapter = nextAdapter;
|
|
178
|
+
platformName = normalizePlatformName(nextPlatform);
|
|
179
|
+
cache.clear();
|
|
180
|
+
};
|
|
181
|
+
const getAdapter = () => {
|
|
182
|
+
if (!adapter) resolveAdapter();
|
|
183
|
+
return adapter;
|
|
184
|
+
};
|
|
185
|
+
const getPlatform = () => {
|
|
186
|
+
if (!platformName) resolveAdapter();
|
|
187
|
+
return platformName;
|
|
188
|
+
};
|
|
189
|
+
return new Proxy({}, { get(_target, prop) {
|
|
190
|
+
if (prop === Symbol.toStringTag) return "Weapi";
|
|
191
|
+
if (prop === "then") return;
|
|
192
|
+
if (INTERNAL_KEYS.has(prop)) {
|
|
193
|
+
if (prop === "setAdapter") return setAdapter;
|
|
194
|
+
if (prop === "getAdapter") return getAdapter;
|
|
195
|
+
if (prop === "platform") return getPlatform();
|
|
196
|
+
if (prop === "raw") return getAdapter();
|
|
197
|
+
}
|
|
198
|
+
if (cache.has(prop)) return cache.get(prop);
|
|
199
|
+
const currentAdapter = resolveAdapter();
|
|
200
|
+
if (!currentAdapter) {
|
|
201
|
+
if (typeof prop !== "string") return;
|
|
202
|
+
return (...args) => callMissingApi(prop, getPlatform(), args);
|
|
203
|
+
}
|
|
204
|
+
const value = currentAdapter[prop];
|
|
205
|
+
if (typeof value !== "function") {
|
|
206
|
+
if (value === void 0 && typeof prop === "string") {
|
|
207
|
+
const missing = (...args) => callMissingApi(prop, getPlatform(), args);
|
|
208
|
+
cache.set(prop, missing);
|
|
209
|
+
return missing;
|
|
210
|
+
}
|
|
211
|
+
cache.set(prop, value);
|
|
212
|
+
return value;
|
|
213
|
+
}
|
|
214
|
+
const wrapped = (...args) => {
|
|
215
|
+
const runtimeAdapter = resolveAdapter();
|
|
216
|
+
const runtimeMethod = runtimeAdapter ? runtimeAdapter[prop] : void 0;
|
|
217
|
+
if (typeof runtimeMethod !== "function") return callMissingApi(prop, getPlatform(), args);
|
|
218
|
+
if (shouldSkipPromise(prop)) return runtimeMethod.apply(runtimeAdapter, args);
|
|
219
|
+
if (hasCallbacks(args.length > 0 ? args[args.length - 1] : void 0)) return runtimeMethod.apply(runtimeAdapter, args);
|
|
220
|
+
return callWithPromise(runtimeAdapter, runtimeMethod, args);
|
|
221
|
+
};
|
|
222
|
+
cache.set(prop, wrapped);
|
|
223
|
+
return wrapped;
|
|
224
|
+
} });
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region src/index.ts
|
|
9
229
|
/**
|
|
10
|
-
* @description
|
|
230
|
+
* @description 默认跨平台 API 实例(推荐使用)
|
|
11
231
|
*/
|
|
12
|
-
const
|
|
232
|
+
const wpi = createWeapi();
|
|
13
233
|
|
|
14
234
|
//#endregion
|
|
15
|
-
exports.
|
|
16
|
-
exports.
|
|
235
|
+
exports.createWeapi = createWeapi;
|
|
236
|
+
exports.wpi = wpi;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,11 +1,71 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/core/types.d.ts
|
|
2
|
+
type WeapiAdapter = Record<string, any>;
|
|
3
|
+
/**
|
|
4
|
+
* @description 微信小程序 API 原始适配器类型
|
|
5
|
+
*/
|
|
6
|
+
type WeapiWxRawAdapter = WechatMiniprogram.Wx;
|
|
7
|
+
type HasCallbackKey<T> = T extends object ? 'success' extends keyof T ? true : 'fail' extends keyof T ? true : 'complete' extends keyof T ? true : false : false;
|
|
8
|
+
type HasCallbackOption<T> = T extends {
|
|
9
|
+
success: unknown;
|
|
10
|
+
} ? true : T extends {
|
|
11
|
+
fail: unknown;
|
|
12
|
+
} ? true : T extends {
|
|
13
|
+
complete: unknown;
|
|
14
|
+
} ? true : false;
|
|
15
|
+
type ExtractSuccessResult<T> = T extends {
|
|
16
|
+
success?: (...args: infer A) => unknown;
|
|
17
|
+
} ? A[0] : void;
|
|
18
|
+
type PromisifyOptionMethod<Prefix extends any[], Option extends object, Result, IsOptional extends boolean> = IsOptional extends true ? {
|
|
19
|
+
<TOption extends Option>(...args: [...Prefix, TOption]): HasCallbackOption<TOption> extends true ? Result : Promise<ExtractSuccessResult<Option>>;
|
|
20
|
+
(...args: Prefix): Promise<ExtractSuccessResult<Option>>;
|
|
21
|
+
} : {
|
|
22
|
+
<TOption extends Option>(...args: [...Prefix, TOption]): HasCallbackOption<TOption> extends true ? Result : Promise<ExtractSuccessResult<Option>>;
|
|
23
|
+
};
|
|
24
|
+
type PromisifyMethod<TMethod> = TMethod extends ((...args: infer Args) => infer Result) ? Args extends [] ? (...args: Args) => Promise<Result> : Args extends [...infer Prefix, infer Last] ? true extends HasCallbackKey<NonNullable<Last>> ? PromisifyOptionMethod<Prefix, NonNullable<Last>, Result, undefined extends Last ? true : false> : (...args: Args) => Promise<Result> : (...args: Args) => Promise<Result> : TMethod;
|
|
25
|
+
type WeapiPromisify<TAdapter extends WeapiAdapter> = { [Key in keyof TAdapter]: Key extends string ? Key extends `${string}Sync` ? TAdapter[Key] : Key extends `on${Capitalize<string>}` | `off${Capitalize<string>}` ? TAdapter[Key] : PromisifyMethod<TAdapter[Key]> : TAdapter[Key] };
|
|
26
|
+
/**
|
|
27
|
+
* @description 微信小程序 API 适配器类型
|
|
28
|
+
*/
|
|
29
|
+
type WeapiWxAdapter = WeapiPromisify<WeapiWxRawAdapter>;
|
|
30
|
+
interface CreateWeapiOptions<TAdapter extends WeapiAdapter = WeapiWxRawAdapter> {
|
|
31
|
+
/**
|
|
32
|
+
* @description 手动指定平台适配器(优先级高于自动探测)
|
|
33
|
+
*/
|
|
34
|
+
adapter?: TAdapter;
|
|
35
|
+
/**
|
|
36
|
+
* @description 手动指定平台名称
|
|
37
|
+
*/
|
|
38
|
+
platform?: string;
|
|
39
|
+
}
|
|
40
|
+
type WeapiInstance<TAdapter extends WeapiAdapter = WeapiWxRawAdapter> = WeapiPromisify<TAdapter> & {
|
|
41
|
+
/**
|
|
42
|
+
* @description 当前平台标识
|
|
43
|
+
*/
|
|
44
|
+
readonly platform?: string;
|
|
45
|
+
/**
|
|
46
|
+
* @description 获取当前适配器实例
|
|
47
|
+
*/
|
|
48
|
+
getAdapter: () => TAdapter | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* @description 手动替换平台适配器
|
|
51
|
+
*/
|
|
52
|
+
setAdapter: (adapter?: TAdapter, platform?: string) => void;
|
|
53
|
+
/**
|
|
54
|
+
* @description 获取原始平台对象
|
|
55
|
+
*/
|
|
56
|
+
readonly raw?: TAdapter;
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/core/createWeapi.d.ts
|
|
2
60
|
/**
|
|
3
|
-
* @description
|
|
61
|
+
* @description 创建跨平台 API 实例
|
|
4
62
|
*/
|
|
5
|
-
declare function
|
|
63
|
+
declare function createWeapi<TAdapter extends WeapiAdapter = WeapiWxRawAdapter>(options?: CreateWeapiOptions<TAdapter>): WeapiInstance<TAdapter>;
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/index.d.ts
|
|
6
66
|
/**
|
|
7
|
-
* @description
|
|
67
|
+
* @description 默认跨平台 API 实例(推荐使用)
|
|
8
68
|
*/
|
|
9
|
-
declare const
|
|
69
|
+
declare const wpi: WeapiInstance<WechatMiniprogram.Wx>;
|
|
10
70
|
//#endregion
|
|
11
|
-
export {
|
|
71
|
+
export { type CreateWeapiOptions, type WeapiAdapter, type WeapiInstance, type WeapiPromisify, type WeapiWxAdapter, type WeapiWxRawAdapter, createWeapi, wpi };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,11 +1,71 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/core/types.d.ts
|
|
2
|
+
type WeapiAdapter = Record<string, any>;
|
|
3
|
+
/**
|
|
4
|
+
* @description 微信小程序 API 原始适配器类型
|
|
5
|
+
*/
|
|
6
|
+
type WeapiWxRawAdapter = WechatMiniprogram.Wx;
|
|
7
|
+
type HasCallbackKey<T> = T extends object ? 'success' extends keyof T ? true : 'fail' extends keyof T ? true : 'complete' extends keyof T ? true : false : false;
|
|
8
|
+
type HasCallbackOption<T> = T extends {
|
|
9
|
+
success: unknown;
|
|
10
|
+
} ? true : T extends {
|
|
11
|
+
fail: unknown;
|
|
12
|
+
} ? true : T extends {
|
|
13
|
+
complete: unknown;
|
|
14
|
+
} ? true : false;
|
|
15
|
+
type ExtractSuccessResult<T> = T extends {
|
|
16
|
+
success?: (...args: infer A) => unknown;
|
|
17
|
+
} ? A[0] : void;
|
|
18
|
+
type PromisifyOptionMethod<Prefix extends any[], Option extends object, Result, IsOptional extends boolean> = IsOptional extends true ? {
|
|
19
|
+
<TOption extends Option>(...args: [...Prefix, TOption]): HasCallbackOption<TOption> extends true ? Result : Promise<ExtractSuccessResult<Option>>;
|
|
20
|
+
(...args: Prefix): Promise<ExtractSuccessResult<Option>>;
|
|
21
|
+
} : {
|
|
22
|
+
<TOption extends Option>(...args: [...Prefix, TOption]): HasCallbackOption<TOption> extends true ? Result : Promise<ExtractSuccessResult<Option>>;
|
|
23
|
+
};
|
|
24
|
+
type PromisifyMethod<TMethod> = TMethod extends ((...args: infer Args) => infer Result) ? Args extends [] ? (...args: Args) => Promise<Result> : Args extends [...infer Prefix, infer Last] ? true extends HasCallbackKey<NonNullable<Last>> ? PromisifyOptionMethod<Prefix, NonNullable<Last>, Result, undefined extends Last ? true : false> : (...args: Args) => Promise<Result> : (...args: Args) => Promise<Result> : TMethod;
|
|
25
|
+
type WeapiPromisify<TAdapter extends WeapiAdapter> = { [Key in keyof TAdapter]: Key extends string ? Key extends `${string}Sync` ? TAdapter[Key] : Key extends `on${Capitalize<string>}` | `off${Capitalize<string>}` ? TAdapter[Key] : PromisifyMethod<TAdapter[Key]> : TAdapter[Key] };
|
|
26
|
+
/**
|
|
27
|
+
* @description 微信小程序 API 适配器类型
|
|
28
|
+
*/
|
|
29
|
+
type WeapiWxAdapter = WeapiPromisify<WeapiWxRawAdapter>;
|
|
30
|
+
interface CreateWeapiOptions<TAdapter extends WeapiAdapter = WeapiWxRawAdapter> {
|
|
31
|
+
/**
|
|
32
|
+
* @description 手动指定平台适配器(优先级高于自动探测)
|
|
33
|
+
*/
|
|
34
|
+
adapter?: TAdapter;
|
|
35
|
+
/**
|
|
36
|
+
* @description 手动指定平台名称
|
|
37
|
+
*/
|
|
38
|
+
platform?: string;
|
|
39
|
+
}
|
|
40
|
+
type WeapiInstance<TAdapter extends WeapiAdapter = WeapiWxRawAdapter> = WeapiPromisify<TAdapter> & {
|
|
41
|
+
/**
|
|
42
|
+
* @description 当前平台标识
|
|
43
|
+
*/
|
|
44
|
+
readonly platform?: string;
|
|
45
|
+
/**
|
|
46
|
+
* @description 获取当前适配器实例
|
|
47
|
+
*/
|
|
48
|
+
getAdapter: () => TAdapter | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* @description 手动替换平台适配器
|
|
51
|
+
*/
|
|
52
|
+
setAdapter: (adapter?: TAdapter, platform?: string) => void;
|
|
53
|
+
/**
|
|
54
|
+
* @description 获取原始平台对象
|
|
55
|
+
*/
|
|
56
|
+
readonly raw?: TAdapter;
|
|
57
|
+
};
|
|
58
|
+
//#endregion
|
|
59
|
+
//#region src/core/createWeapi.d.ts
|
|
2
60
|
/**
|
|
3
|
-
* @description
|
|
61
|
+
* @description 创建跨平台 API 实例
|
|
4
62
|
*/
|
|
5
|
-
declare function
|
|
63
|
+
declare function createWeapi<TAdapter extends WeapiAdapter = WeapiWxRawAdapter>(options?: CreateWeapiOptions<TAdapter>): WeapiInstance<TAdapter>;
|
|
64
|
+
//#endregion
|
|
65
|
+
//#region src/index.d.ts
|
|
6
66
|
/**
|
|
7
|
-
* @description
|
|
67
|
+
* @description 默认跨平台 API 实例(推荐使用)
|
|
8
68
|
*/
|
|
9
|
-
declare const
|
|
69
|
+
declare const wpi: WeapiInstance<WechatMiniprogram.Wx>;
|
|
10
70
|
//#endregion
|
|
11
|
-
export {
|
|
71
|
+
export { type CreateWeapiOptions, type WeapiAdapter, type WeapiInstance, type WeapiPromisify, type WeapiWxAdapter, type WeapiWxRawAdapter, createWeapi, wpi };
|
package/dist/index.mjs
CHANGED
|
@@ -1,14 +1,233 @@
|
|
|
1
|
-
//#region src/
|
|
1
|
+
//#region src/core/adapter.ts
|
|
2
|
+
const GLOBAL_ADAPTER_KEYS = [
|
|
3
|
+
{
|
|
4
|
+
platform: "wx",
|
|
5
|
+
key: "wx"
|
|
6
|
+
},
|
|
7
|
+
{
|
|
8
|
+
platform: "my",
|
|
9
|
+
key: "my"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
platform: "tt",
|
|
13
|
+
key: "tt"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
platform: "qq",
|
|
17
|
+
key: "qq"
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
platform: "swan",
|
|
21
|
+
key: "swan"
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
platform: "ks",
|
|
25
|
+
key: "ks"
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
platform: "jd",
|
|
29
|
+
key: "jd"
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
platform: "xhs",
|
|
33
|
+
key: "xhs"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
platform: "dd",
|
|
37
|
+
key: "dd"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
platform: "qa",
|
|
41
|
+
key: "qa"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
platform: "qapp",
|
|
45
|
+
key: "qapp"
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
platform: "uni",
|
|
49
|
+
key: "uni"
|
|
50
|
+
}
|
|
51
|
+
];
|
|
52
|
+
function resolveGlobalThis() {
|
|
53
|
+
if (typeof globalThis !== "undefined") return globalThis;
|
|
54
|
+
if (typeof window !== "undefined") return window;
|
|
55
|
+
}
|
|
56
|
+
function isAdapterCandidate(value) {
|
|
57
|
+
return typeof value === "object" || typeof value === "function";
|
|
58
|
+
}
|
|
2
59
|
/**
|
|
3
|
-
* @description
|
|
60
|
+
* @description 侦测当前运行环境的全局 API 对象
|
|
4
61
|
*/
|
|
5
|
-
function
|
|
6
|
-
|
|
62
|
+
function detectGlobalAdapter() {
|
|
63
|
+
const root = resolveGlobalThis();
|
|
64
|
+
if (!root) return {};
|
|
65
|
+
for (const item of GLOBAL_ADAPTER_KEYS) {
|
|
66
|
+
const candidate = root[item.key];
|
|
67
|
+
if (isAdapterCandidate(candidate)) return {
|
|
68
|
+
adapter: candidate,
|
|
69
|
+
platform: item.platform
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
return {};
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/core/utils.ts
|
|
77
|
+
function isPlainObject(value) {
|
|
78
|
+
return Object.prototype.toString.call(value) === "[object Object]";
|
|
7
79
|
}
|
|
80
|
+
function hasCallbacks(value) {
|
|
81
|
+
if (!isPlainObject(value)) return false;
|
|
82
|
+
return typeof value.success === "function" || typeof value.fail === "function" || typeof value.complete === "function";
|
|
83
|
+
}
|
|
84
|
+
function isSyncMethod(name) {
|
|
85
|
+
return name.endsWith("Sync");
|
|
86
|
+
}
|
|
87
|
+
function isEventMethod(name) {
|
|
88
|
+
return /^on[A-Z]/.test(name) || /^off[A-Z]/.test(name);
|
|
89
|
+
}
|
|
90
|
+
function shouldSkipPromise(name) {
|
|
91
|
+
return isSyncMethod(name) || isEventMethod(name);
|
|
92
|
+
}
|
|
93
|
+
function createNotSupportedError(methodName, platform) {
|
|
94
|
+
return { errMsg: `${platform ? `${platform}.${methodName}` : methodName}:fail method not supported` };
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
//#endregion
|
|
98
|
+
//#region src/core/createWeapi.ts
|
|
99
|
+
const INTERNAL_KEYS = new Set([
|
|
100
|
+
"setAdapter",
|
|
101
|
+
"getAdapter",
|
|
102
|
+
"platform",
|
|
103
|
+
"raw"
|
|
104
|
+
]);
|
|
105
|
+
function normalizePlatformName(value) {
|
|
106
|
+
return value || void 0;
|
|
107
|
+
}
|
|
108
|
+
function resolveOptionsArg(args) {
|
|
109
|
+
const nextArgs = args.slice();
|
|
110
|
+
const lastArg = nextArgs.length > 0 ? nextArgs[nextArgs.length - 1] : void 0;
|
|
111
|
+
if (isPlainObject(lastArg)) {
|
|
112
|
+
const options = { ...lastArg };
|
|
113
|
+
nextArgs[nextArgs.length - 1] = options;
|
|
114
|
+
return {
|
|
115
|
+
args: nextArgs,
|
|
116
|
+
options
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
const options = {};
|
|
120
|
+
nextArgs.push(options);
|
|
121
|
+
return {
|
|
122
|
+
args: nextArgs,
|
|
123
|
+
options
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
function callWithPromise(context, method, args) {
|
|
127
|
+
return new Promise((resolve, reject) => {
|
|
128
|
+
const { args: nextArgs, options } = resolveOptionsArg(args);
|
|
129
|
+
let settled = false;
|
|
130
|
+
options.success = (res) => {
|
|
131
|
+
settled = true;
|
|
132
|
+
resolve(res);
|
|
133
|
+
};
|
|
134
|
+
options.fail = (err) => {
|
|
135
|
+
settled = true;
|
|
136
|
+
reject(err);
|
|
137
|
+
};
|
|
138
|
+
options.complete = (res) => {
|
|
139
|
+
if (!settled) resolve(res);
|
|
140
|
+
};
|
|
141
|
+
try {
|
|
142
|
+
method.apply(context, nextArgs);
|
|
143
|
+
} catch (err) {
|
|
144
|
+
reject(err);
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
function callMissingApi(methodName, platform, args) {
|
|
149
|
+
const lastArg = args.length > 0 ? args[args.length - 1] : void 0;
|
|
150
|
+
const error = createNotSupportedError(methodName, platform);
|
|
151
|
+
if (hasCallbacks(lastArg)) {
|
|
152
|
+
lastArg.fail?.(error);
|
|
153
|
+
lastArg.complete?.(error);
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
return Promise.reject(error);
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* @description 创建跨平台 API 实例
|
|
160
|
+
*/
|
|
161
|
+
function createWeapi(options = {}) {
|
|
162
|
+
let adapter = options.adapter;
|
|
163
|
+
let platformName = normalizePlatformName(options.platform);
|
|
164
|
+
const cache = /* @__PURE__ */ new Map();
|
|
165
|
+
const resolveAdapter = () => {
|
|
166
|
+
if (adapter) return adapter;
|
|
167
|
+
const detected = detectGlobalAdapter();
|
|
168
|
+
if (detected.adapter) {
|
|
169
|
+
adapter = detected.adapter;
|
|
170
|
+
platformName = platformName ?? normalizePlatformName(detected.platform);
|
|
171
|
+
}
|
|
172
|
+
return adapter;
|
|
173
|
+
};
|
|
174
|
+
const setAdapter = (nextAdapter, nextPlatform) => {
|
|
175
|
+
adapter = nextAdapter;
|
|
176
|
+
platformName = normalizePlatformName(nextPlatform);
|
|
177
|
+
cache.clear();
|
|
178
|
+
};
|
|
179
|
+
const getAdapter = () => {
|
|
180
|
+
if (!adapter) resolveAdapter();
|
|
181
|
+
return adapter;
|
|
182
|
+
};
|
|
183
|
+
const getPlatform = () => {
|
|
184
|
+
if (!platformName) resolveAdapter();
|
|
185
|
+
return platformName;
|
|
186
|
+
};
|
|
187
|
+
return new Proxy({}, { get(_target, prop) {
|
|
188
|
+
if (prop === Symbol.toStringTag) return "Weapi";
|
|
189
|
+
if (prop === "then") return;
|
|
190
|
+
if (INTERNAL_KEYS.has(prop)) {
|
|
191
|
+
if (prop === "setAdapter") return setAdapter;
|
|
192
|
+
if (prop === "getAdapter") return getAdapter;
|
|
193
|
+
if (prop === "platform") return getPlatform();
|
|
194
|
+
if (prop === "raw") return getAdapter();
|
|
195
|
+
}
|
|
196
|
+
if (cache.has(prop)) return cache.get(prop);
|
|
197
|
+
const currentAdapter = resolveAdapter();
|
|
198
|
+
if (!currentAdapter) {
|
|
199
|
+
if (typeof prop !== "string") return;
|
|
200
|
+
return (...args) => callMissingApi(prop, getPlatform(), args);
|
|
201
|
+
}
|
|
202
|
+
const value = currentAdapter[prop];
|
|
203
|
+
if (typeof value !== "function") {
|
|
204
|
+
if (value === void 0 && typeof prop === "string") {
|
|
205
|
+
const missing = (...args) => callMissingApi(prop, getPlatform(), args);
|
|
206
|
+
cache.set(prop, missing);
|
|
207
|
+
return missing;
|
|
208
|
+
}
|
|
209
|
+
cache.set(prop, value);
|
|
210
|
+
return value;
|
|
211
|
+
}
|
|
212
|
+
const wrapped = (...args) => {
|
|
213
|
+
const runtimeAdapter = resolveAdapter();
|
|
214
|
+
const runtimeMethod = runtimeAdapter ? runtimeAdapter[prop] : void 0;
|
|
215
|
+
if (typeof runtimeMethod !== "function") return callMissingApi(prop, getPlatform(), args);
|
|
216
|
+
if (shouldSkipPromise(prop)) return runtimeMethod.apply(runtimeAdapter, args);
|
|
217
|
+
if (hasCallbacks(args.length > 0 ? args[args.length - 1] : void 0)) return runtimeMethod.apply(runtimeAdapter, args);
|
|
218
|
+
return callWithPromise(runtimeAdapter, runtimeMethod, args);
|
|
219
|
+
};
|
|
220
|
+
cache.set(prop, wrapped);
|
|
221
|
+
return wrapped;
|
|
222
|
+
} });
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
//#endregion
|
|
226
|
+
//#region src/index.ts
|
|
8
227
|
/**
|
|
9
|
-
* @description
|
|
228
|
+
* @description 默认跨平台 API 实例(推荐使用)
|
|
10
229
|
*/
|
|
11
|
-
const
|
|
230
|
+
const wpi = createWeapi();
|
|
12
231
|
|
|
13
232
|
//#endregion
|
|
14
|
-
export {
|
|
233
|
+
export { createWeapi, wpi };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wevu/api",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0
|
|
4
|
+
"version": "0.1.0",
|
|
5
5
|
"description": "tsdown bundler template",
|
|
6
6
|
"author": "ice breaker <1324318532@qq.com>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -17,23 +17,27 @@
|
|
|
17
17
|
"sideEffects": false,
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
|
-
"types": "./
|
|
20
|
+
"types": "./types/index.d.ts",
|
|
21
21
|
"import": {
|
|
22
|
-
"types": "./
|
|
22
|
+
"types": "./types/index.d.ts",
|
|
23
23
|
"default": "./dist/index.mjs"
|
|
24
24
|
},
|
|
25
25
|
"require": {
|
|
26
|
-
"types": "./
|
|
26
|
+
"types": "./types/index.d.ts",
|
|
27
27
|
"default": "./dist/index.cjs"
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
30
|
},
|
|
31
31
|
"main": "./dist/index.cjs",
|
|
32
32
|
"module": "./dist/index.mjs",
|
|
33
|
-
"types": "./
|
|
33
|
+
"types": "./types/index.d.ts",
|
|
34
34
|
"files": [
|
|
35
|
-
"dist"
|
|
35
|
+
"dist",
|
|
36
|
+
"types"
|
|
36
37
|
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"miniprogram-api-typings": "^5.0.0"
|
|
40
|
+
},
|
|
37
41
|
"publishConfig": {
|
|
38
42
|
"access": "public"
|
|
39
43
|
},
|
|
@@ -42,6 +46,7 @@
|
|
|
42
46
|
"build": "tsdown",
|
|
43
47
|
"test": "vitest run",
|
|
44
48
|
"test:dev": "vitest",
|
|
49
|
+
"test:types": "tsd",
|
|
45
50
|
"release": "pnpm publish",
|
|
46
51
|
"lint": "eslint .",
|
|
47
52
|
"lint:fix": "eslint . --fix"
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/// <reference types="miniprogram-api-typings" />
|
|
2
|
+
|
|
3
|
+
// eslint-disable-next-line antfu/no-import-dist
|
|
4
|
+
import type {
|
|
5
|
+
CreateWeapiOptions,
|
|
6
|
+
WeapiAdapter,
|
|
7
|
+
WeapiInstance,
|
|
8
|
+
WeapiPromisify,
|
|
9
|
+
WeapiWxAdapter,
|
|
10
|
+
WeapiWxRawAdapter,
|
|
11
|
+
} from '../dist/index.d.mts'
|
|
12
|
+
|
|
13
|
+
export type {
|
|
14
|
+
CreateWeapiOptions,
|
|
15
|
+
WeapiAdapter,
|
|
16
|
+
WeapiInstance,
|
|
17
|
+
WeapiPromisify,
|
|
18
|
+
WeapiWxAdapter,
|
|
19
|
+
WeapiWxRawAdapter,
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createWeapi<TAdapter extends WeapiAdapter = WeapiWxRawAdapter>(
|
|
23
|
+
options?: CreateWeapiOptions<TAdapter>,
|
|
24
|
+
): WeapiInstance<TAdapter>
|
|
25
|
+
|
|
26
|
+
export const wpi: WeapiInstance<WechatMiniprogram.Wx>
|