@mearl/client 2.22.0 → 3.0.0-beta.1
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/LICENSE +201 -0
- package/README.md +43 -52
- package/dist/actionTimeouts.js +1 -1
- package/dist/artifacts.d.ts +1 -1
- package/dist/autoUpdate.js +1 -2
- package/dist/browserRegistry.d.ts +1 -1
- package/dist/check.d.ts +1 -1
- package/dist/check.js +4 -3
- package/dist/commands.d.ts +12 -12
- package/dist/commands.js +15 -14
- package/dist/index.d.ts +4 -7
- package/dist/index.js +1 -1
- package/dist/local.d.ts +3 -1
- package/dist/local.js +2 -1
- package/dist/nativeHost.d.ts +2 -2
- package/dist/nativeHost.js +2 -4
- package/dist/pageEvalArguments.d.ts +1 -1
- package/dist/pageEvalArguments.js +1 -1
- package/dist/plugin.d.ts +1 -0
- package/dist/plugin.js +1 -0
- package/dist/pluginModelSessionWorker.d.ts +2 -2
- package/dist/plugins/clients/pluginHostConnection.d.ts +1 -1
- package/dist/plugins/clients/pluginHostConnection.js +1 -1
- package/dist/plugins/clients/pluginModels.d.ts +3 -3
- package/dist/plugins/clients/pluginPages.d.ts +2 -2
- package/dist/plugins/clients/pluginState.d.ts +2 -2
- package/dist/plugins/clients/pluginTasks.d.ts +3 -3
- package/dist/plugins/clients/pluginTasks.js +1 -1
- package/dist/plugins/officialPluginCatalog.d.ts +18 -21
- package/dist/plugins/officialPluginCatalog.js +120 -24
- package/dist/plugins/officialPluginInstaller.js +6 -1
- package/dist/plugins/pluginRegistry.d.ts +1 -1
- package/dist/plugins/pluginRegistry.js +2 -2
- package/dist/plugins/pluginTaskProtocol.d.ts +1 -1
- package/dist/plugins/runtime/pluginDiagnostics.d.ts +3 -3
- package/dist/plugins/runtime/pluginDiagnostics.js +2 -2
- package/dist/plugins/runtime/pluginExecution.d.ts +2 -2
- package/dist/plugins/runtime/pluginExecutor.d.ts +1 -1
- package/dist/plugins/runtime/pluginExecutorProtocol.d.ts +2 -2
- package/dist/plugins/runtime/pluginHost.d.ts +2 -2
- package/dist/plugins/runtime/pluginHostServer.js +1 -1
- package/dist/plugins/runtime/pluginModelCatalog.d.ts +1 -1
- package/dist/plugins/runtime/pluginPageManager.d.ts +3 -3
- package/dist/plugins/runtime/pluginPageManager.js +2 -2
- package/dist/plugins/runtime/pluginRevision.js +2 -1
- package/dist/plugins/runtime/pluginStateManager.d.ts +1 -1
- package/dist/plugins/runtime/pluginStateStore.d.ts +1 -1
- package/dist/plugins/runtime/pluginTaskManager.d.ts +10 -10
- package/dist/plugins/runtime/pluginTaskManager.js +1 -1
- package/dist/plugins/runtime/pluginTaskStore.d.ts +3 -3
- package/dist/plugins/runtime/pluginTaskStore.js +1 -1
- package/dist/plugins/runtime/pythonPlugin.d.ts +1 -1
- package/dist/plugins/sdk/plugin.d.ts +9 -12
- package/dist/plugins/sdk/plugin.js +4 -7
- package/dist/plugins/sdk/pluginAppProfiles.d.ts +1 -1
- package/dist/plugins/sdk/pluginAppProfiles.js +1 -1
- package/dist/plugins/sdk/pluginModelDefinition.d.ts +1 -1
- package/dist/plugins/sdk/pluginPageDefinition.d.ts +1 -1
- package/dist/plugins/sdk/pluginPageDefinition.js +1 -1
- package/dist/plugins/sdk/pluginRecoveryDefinition.d.ts +1 -1
- package/dist/plugins/sdk/pluginStateDefinition.d.ts +2 -2
- package/dist/plugins/skillManifest.d.ts +10 -0
- package/dist/plugins/skillManifest.js +56 -0
- package/dist/socket.d.ts +2 -0
- package/dist/socket.js +13 -3
- package/dist/unified.d.ts +1 -1
- package/dist/unified.js +1 -1
- package/package.json +14 -8
- package/dist/generated/app-profile-definition.d.ts +0 -130
- package/dist/generated/app-profile-definition.js +0 -458
- package/dist/generated/app-profile-runtime-types.d.ts +0 -213
- package/dist/generated/app-profile-runtime-types.js +0 -1
- package/dist/generated/browser-action-protocol.d.ts +0 -1147
- package/dist/generated/browser-action-protocol.js +0 -283
- package/dist/generated/plugin-diagnostics.d.ts +0 -110
- package/dist/generated/plugin-diagnostics.js +0 -1
- package/dist/generated/plugin-execution.d.ts +0 -27
- package/dist/generated/plugin-execution.js +0 -1
- package/dist/generated/plugin-models.d.ts +0 -64
- package/dist/generated/plugin-models.js +0 -1
- package/dist/generated/plugin-pages.d.ts +0 -76
- package/dist/generated/plugin-pages.js +0 -59
- package/dist/generated/plugin-recovery.d.ts +0 -32
- package/dist/generated/plugin-recovery.js +0 -1
- package/dist/generated/plugin-state.d.ts +0 -50
- package/dist/generated/plugin-state.js +0 -1
- package/dist/generated/plugin-tasks.d.ts +0 -74
- package/dist/generated/plugin-tasks.js +0 -7
- package/dist/generated/toolbox-icon.d.ts +0 -10
- package/dist/generated/toolbox-icon.js +0 -37
|
@@ -1,130 +0,0 @@
|
|
|
1
|
-
import type { BrowserDevicePresetName, AppBridgeConfig } from './browser-action-protocol.js';
|
|
2
|
-
import type { AppBridgeSpec, AppImagePickerConfig, AppLayerUrlProxyConfig, AppMiniProgramConfig, AppNativeBackConfig, AppOverlayConfig, AppSchemeRule, AppTitleBarHostStyle, BridgeActionMap } from './app-profile-runtime-types.js';
|
|
3
|
-
export interface AppProfilePolicies {
|
|
4
|
-
titleBar?: 'default' | 'taobao' | 'fliggy' | 'alipay' | 'wechat';
|
|
5
|
-
navigatorLanguage?: boolean;
|
|
6
|
-
networkResult?: 'default' | 'alipay';
|
|
7
|
-
languages?: string[];
|
|
8
|
-
defaultLanguage?: string;
|
|
9
|
-
}
|
|
10
|
-
export interface AppProfileSetting {
|
|
11
|
-
id: string;
|
|
12
|
-
label: string;
|
|
13
|
-
type: 'select' | 'boolean' | 'number' | 'text' | 'json';
|
|
14
|
-
target: {
|
|
15
|
-
option: 'language';
|
|
16
|
-
} | {
|
|
17
|
-
method: string;
|
|
18
|
-
field?: string;
|
|
19
|
-
};
|
|
20
|
-
choices?: Array<{
|
|
21
|
-
label: string;
|
|
22
|
-
value: string;
|
|
23
|
-
}>;
|
|
24
|
-
minimum?: number;
|
|
25
|
-
maximum?: number;
|
|
26
|
-
}
|
|
27
|
-
export interface AppProfileOptions {
|
|
28
|
-
/** Keep this definition across document navigations until explicitly refreshed. */
|
|
29
|
-
lockDefinition?: boolean;
|
|
30
|
-
os?: 'ios' | 'android';
|
|
31
|
-
appVersion?: string;
|
|
32
|
-
language?: string;
|
|
33
|
-
deviceModel?: string;
|
|
34
|
-
devicePreset?: BrowserDevicePresetName;
|
|
35
|
-
orientation?: 'portrait' | 'landscape';
|
|
36
|
-
bridgeConfig?: AppBridgeConfig;
|
|
37
|
-
}
|
|
38
|
-
export interface AppProfileBinding {
|
|
39
|
-
version: 1;
|
|
40
|
-
revision: string;
|
|
41
|
-
definition: AppProfileDefinition;
|
|
42
|
-
options: AppProfileOptions;
|
|
43
|
-
/** Explicit scalar choices; method overrides are always explicit and live in options.bridgeConfig. */
|
|
44
|
-
explicitOptions?: Omit<AppProfileOptions, 'bridgeConfig'>;
|
|
45
|
-
}
|
|
46
|
-
export interface AppProfileContribution {
|
|
47
|
-
version: 1;
|
|
48
|
-
profiles: AppProfileDefinition[];
|
|
49
|
-
}
|
|
50
|
-
export interface AppProfileCatalogEntry {
|
|
51
|
-
id: string;
|
|
52
|
-
label: string;
|
|
53
|
-
source: 'builtin' | 'plugin';
|
|
54
|
-
available?: boolean;
|
|
55
|
-
plugin?: string;
|
|
56
|
-
revision: string;
|
|
57
|
-
definition: AppProfileDefinition;
|
|
58
|
-
}
|
|
59
|
-
/** 单容器档案(纯数据) */
|
|
60
|
-
export interface AppProfileDefinition {
|
|
61
|
-
name: string;
|
|
62
|
-
label: string;
|
|
63
|
-
/** 容器的应用标识,如 LX / TB / AP / WeChat */
|
|
64
|
-
appName: string;
|
|
65
|
-
defaultAppVersion: string;
|
|
66
|
-
/** UA 主体格式;默认使用 AliApp(appName/version) */
|
|
67
|
-
uaFamily?: 'aliapp' | 'wechatMiniProgram';
|
|
68
|
-
uaTemplate?: {
|
|
69
|
-
ios: string;
|
|
70
|
-
android: string;
|
|
71
|
-
};
|
|
72
|
-
policies?: AppProfilePolicies;
|
|
73
|
-
settings?: AppProfileSetting[];
|
|
74
|
-
settingsGroup?: 'fliggy' | 'alipay';
|
|
75
|
-
/** AliApp UA 主体之后追加的 token,{v} 占位会被替换为 appVersion */
|
|
76
|
-
uaTokens: string[];
|
|
77
|
-
/** 额外注入到 window 的变量(公共变量由 resolve 统一生成) */
|
|
78
|
-
globals: Record<string, string>;
|
|
79
|
-
bridges: AppBridgeSpec[];
|
|
80
|
-
/** 页面回到前台时分发到 document 的事件名(如 WV.Event.APP.Active) */
|
|
81
|
-
activeEvents: string[];
|
|
82
|
-
actions: BridgeActionMap;
|
|
83
|
-
schemes: AppSchemeRule[];
|
|
84
|
-
/** 小程序原生页面与 WebView 通信规则。 */
|
|
85
|
-
miniProgram?: AppMiniProgramConfig;
|
|
86
|
-
/** 原生图片页 scheme 的浏览器选图与上传配置 */
|
|
87
|
-
imagePicker?: AppImagePickerConfig;
|
|
88
|
-
geolocation?: {
|
|
89
|
-
reverseGeocodeApi: string;
|
|
90
|
-
version: string;
|
|
91
|
-
};
|
|
92
|
-
/**
|
|
93
|
-
* 地址栏借位同步的可选 host 白名单:容器栈顶 URL 的 host 命中时,地址栏借 top
|
|
94
|
-
* 域名同步其 path+query+hash(pushState 同源约束下保持域名不变只改 path);
|
|
95
|
-
* 不配置则同步所有 HTTP(S) 业务层 URL。
|
|
96
|
-
*/
|
|
97
|
-
urlSyncHostSuffixes?: string[];
|
|
98
|
-
/** URL / pageParams 浮层协议 */
|
|
99
|
-
overlay?: AppOverlayConfig;
|
|
100
|
-
/** URL 参数为真时以新 WebView 替换当前业务层。 */
|
|
101
|
-
popBeforeOpenParam?: string;
|
|
102
|
-
/** 跨 WebView 消息抵达 opener 时分发的 document 事件。 */
|
|
103
|
-
messageEvent?: string;
|
|
104
|
-
/** 原生返回键的页面接管协议。 */
|
|
105
|
-
nativeBack?: AppNativeBackConfig;
|
|
106
|
-
/** 开发代理 origin 下的业务层 URL 映射 */
|
|
107
|
-
layerUrlProxy?: AppLayerUrlProxyConfig;
|
|
108
|
-
/** App 框架的根 WebView 与自绘标题栏协议。 */
|
|
109
|
-
rootContainer?: {
|
|
110
|
-
statusBarHeightCookie?: {
|
|
111
|
-
name: string;
|
|
112
|
-
domain?: string;
|
|
113
|
-
path?: string;
|
|
114
|
-
};
|
|
115
|
-
};
|
|
116
|
-
/** 页面自行绘制导航区域时,不渲染模拟标题栏。 */
|
|
117
|
-
titleBarHiddenPathnames?: string[];
|
|
118
|
-
/** 页面级状态栏背景色,key 为业务 pathname。 */
|
|
119
|
-
statusBarBackgroundColors?: Record<string, string>;
|
|
120
|
-
/** 按业务根域配置标题栏与状态栏样式。 */
|
|
121
|
-
titleBarHostStyles?: AppTitleBarHostStyle[];
|
|
122
|
-
/** 桥存在时仍将 MTOP 传输固定在浏览器 H5 通道 */
|
|
123
|
-
forceH5Mtop?: boolean;
|
|
124
|
-
}
|
|
125
|
-
export declare const APP_BRIDGE_BEHAVIORS: readonly ["navigate", "closeAll", "closeBackData", "postMessage", "notifySubscribe", "notifyUnsubscribe", "notifyPost", "sharedFileRead", "sharedFileWrite", "sharedDataGet", "sharedDataSet", "legacyBroadcastCreate", "legacyBroadcastPost", "legacyBroadcastClose", "memoryGet", "memorySet", "memoryDelete", "availabilityMap", "userInfo", "authCode", "networkInfo", "geolocation", "permission", "imagePicker", "prefetch", "fptTrack", "mtopStream", "previewFile", "toast", "unsupportedNativeInput", "payment", "userTrack", "calendar", "networkQualityMonitor", "beaconRequest", "voiceRecognition"];
|
|
126
|
-
/** Validate plain data before registration or compiling a document-start configuration. */
|
|
127
|
-
export declare function validateAppProfileDefinition(value: unknown): AppProfileDefinition;
|
|
128
|
-
export declare function validateAppProfileContribution(value: unknown): AppProfileContribution | undefined;
|
|
129
|
-
/** Deterministic identity for immutable definitions; this identifier grants no host permissions. */
|
|
130
|
-
export declare function appProfileRevision(definition: AppProfileDefinition): string;
|
|
@@ -1,458 +0,0 @@
|
|
|
1
|
-
const BRIDGE_STYLES = new Set([
|
|
2
|
-
'windvane',
|
|
3
|
-
'fliggy',
|
|
4
|
-
'alipay',
|
|
5
|
-
'callback',
|
|
6
|
-
'btrip',
|
|
7
|
-
'invoke',
|
|
8
|
-
'callHandler',
|
|
9
|
-
'amap',
|
|
10
|
-
'didi',
|
|
11
|
-
'easybikeNative',
|
|
12
|
-
'mega',
|
|
13
|
-
'wechat',
|
|
14
|
-
'wechatMiniProgram',
|
|
15
|
-
]);
|
|
16
|
-
export const APP_BRIDGE_BEHAVIORS = [
|
|
17
|
-
'navigate',
|
|
18
|
-
'closeAll',
|
|
19
|
-
'closeBackData',
|
|
20
|
-
'postMessage',
|
|
21
|
-
'notifySubscribe',
|
|
22
|
-
'notifyUnsubscribe',
|
|
23
|
-
'notifyPost',
|
|
24
|
-
'sharedFileRead',
|
|
25
|
-
'sharedFileWrite',
|
|
26
|
-
'sharedDataGet',
|
|
27
|
-
'sharedDataSet',
|
|
28
|
-
'legacyBroadcastCreate',
|
|
29
|
-
'legacyBroadcastPost',
|
|
30
|
-
'legacyBroadcastClose',
|
|
31
|
-
'memoryGet',
|
|
32
|
-
'memorySet',
|
|
33
|
-
'memoryDelete',
|
|
34
|
-
'availabilityMap',
|
|
35
|
-
'userInfo',
|
|
36
|
-
'authCode',
|
|
37
|
-
'networkInfo',
|
|
38
|
-
'geolocation',
|
|
39
|
-
'permission',
|
|
40
|
-
'imagePicker',
|
|
41
|
-
'prefetch',
|
|
42
|
-
'fptTrack',
|
|
43
|
-
'mtopStream',
|
|
44
|
-
'previewFile',
|
|
45
|
-
'toast',
|
|
46
|
-
'unsupportedNativeInput',
|
|
47
|
-
'payment',
|
|
48
|
-
'userTrack',
|
|
49
|
-
'calendar',
|
|
50
|
-
'networkQualityMonitor',
|
|
51
|
-
'beaconRequest',
|
|
52
|
-
'voiceRecognition',
|
|
53
|
-
];
|
|
54
|
-
const BEHAVIORS = new Set(APP_BRIDGE_BEHAVIORS);
|
|
55
|
-
function record(value) {
|
|
56
|
-
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
57
|
-
}
|
|
58
|
-
function invalid(path) {
|
|
59
|
-
throw new Error(`Invalid app profile: ${path}`);
|
|
60
|
-
}
|
|
61
|
-
function text(value) {
|
|
62
|
-
return (typeof value === 'string' &&
|
|
63
|
-
value.length <= 4096 &&
|
|
64
|
-
Array.from(value).every(character => character.charCodeAt(0) > 8));
|
|
65
|
-
}
|
|
66
|
-
function strings(value) {
|
|
67
|
-
return Array.isArray(value) && value.length <= 200 && value.every(text);
|
|
68
|
-
}
|
|
69
|
-
function fields(value, required, optional, path) {
|
|
70
|
-
if (!record(value) ||
|
|
71
|
-
required.some(key => !Object.hasOwn(value, key)) ||
|
|
72
|
-
Object.keys(value).some(key => !required.includes(key) && !optional.includes(key)))
|
|
73
|
-
invalid(path);
|
|
74
|
-
}
|
|
75
|
-
function stringMap(value) {
|
|
76
|
-
return record(value) && Object.keys(value).length <= 200 && Object.values(value).every(text);
|
|
77
|
-
}
|
|
78
|
-
function json(value, depth = 0) {
|
|
79
|
-
if (depth > 25)
|
|
80
|
-
return false;
|
|
81
|
-
if (value === null || typeof value === 'boolean' || text(value))
|
|
82
|
-
return true;
|
|
83
|
-
if (typeof value === 'number')
|
|
84
|
-
return Number.isFinite(value);
|
|
85
|
-
if (Array.isArray(value))
|
|
86
|
-
return value.length <= 1000 && value.every(item => json(item, depth + 1));
|
|
87
|
-
return (record(value) &&
|
|
88
|
-
Object.entries(value).every(([key, item]) => !['__proto__', 'prototype', 'constructor'].includes(key) && json(item, depth + 1)));
|
|
89
|
-
}
|
|
90
|
-
function validateActions(value) {
|
|
91
|
-
const arrays = [
|
|
92
|
-
'open',
|
|
93
|
-
'close',
|
|
94
|
-
'title',
|
|
95
|
-
'navigationBar',
|
|
96
|
-
'statusBar',
|
|
97
|
-
'systemInfo',
|
|
98
|
-
'mtop',
|
|
99
|
-
'kvGet',
|
|
100
|
-
'kvSet',
|
|
101
|
-
'kvDelete',
|
|
102
|
-
'pageContext',
|
|
103
|
-
'noop',
|
|
104
|
-
'silent',
|
|
105
|
-
];
|
|
106
|
-
fields(value, ['open', 'close', 'title', 'systemInfo', 'mtop', 'noop'], [...arrays, 'responses', 'behaviors'], 'actions');
|
|
107
|
-
for (const key of arrays)
|
|
108
|
-
if (value[key] !== undefined && !strings(value[key]))
|
|
109
|
-
invalid(`actions.${key}`);
|
|
110
|
-
if (value.responses !== undefined && !record(value.responses))
|
|
111
|
-
invalid('actions.responses');
|
|
112
|
-
if (value.behaviors !== undefined &&
|
|
113
|
-
(!stringMap(value.behaviors) ||
|
|
114
|
-
!Object.values(value.behaviors).every(item => BEHAVIORS.has(item))))
|
|
115
|
-
invalid('actions.behaviors');
|
|
116
|
-
}
|
|
117
|
-
/** Validate plain data before registration or compiling a document-start configuration. */
|
|
118
|
-
export function validateAppProfileDefinition(value) {
|
|
119
|
-
if (!json(value))
|
|
120
|
-
invalid('JSON');
|
|
121
|
-
if (JSON.stringify(value).length > 65_536)
|
|
122
|
-
invalid('definition exceeds 64 KiB');
|
|
123
|
-
const required = [
|
|
124
|
-
'name',
|
|
125
|
-
'label',
|
|
126
|
-
'appName',
|
|
127
|
-
'defaultAppVersion',
|
|
128
|
-
'uaTokens',
|
|
129
|
-
'globals',
|
|
130
|
-
'bridges',
|
|
131
|
-
'activeEvents',
|
|
132
|
-
'actions',
|
|
133
|
-
'schemes',
|
|
134
|
-
];
|
|
135
|
-
const optional = [
|
|
136
|
-
'uaFamily',
|
|
137
|
-
'uaTemplate',
|
|
138
|
-
'policies',
|
|
139
|
-
'settings',
|
|
140
|
-
'settingsGroup',
|
|
141
|
-
'miniProgram',
|
|
142
|
-
'imagePicker',
|
|
143
|
-
'geolocation',
|
|
144
|
-
'urlSyncHostSuffixes',
|
|
145
|
-
'overlay',
|
|
146
|
-
'popBeforeOpenParam',
|
|
147
|
-
'messageEvent',
|
|
148
|
-
'nativeBack',
|
|
149
|
-
'layerUrlProxy',
|
|
150
|
-
'rootContainer',
|
|
151
|
-
'titleBarHiddenPathnames',
|
|
152
|
-
'statusBarBackgroundColors',
|
|
153
|
-
'titleBarHostStyles',
|
|
154
|
-
'forceH5Mtop',
|
|
155
|
-
];
|
|
156
|
-
fields(value, required, optional, 'definition');
|
|
157
|
-
for (const key of ['name', 'label', 'appName', 'defaultAppVersion'])
|
|
158
|
-
if (!text(value[key]) || !value[key])
|
|
159
|
-
invalid(key);
|
|
160
|
-
if (!/^[a-z][a-z0-9-]*(?:\/[a-z][a-z0-9-]*)?$/.test(value.name))
|
|
161
|
-
invalid('name');
|
|
162
|
-
for (const key of [
|
|
163
|
-
'uaTokens',
|
|
164
|
-
'activeEvents',
|
|
165
|
-
'urlSyncHostSuffixes',
|
|
166
|
-
'titleBarHiddenPathnames',
|
|
167
|
-
]) {
|
|
168
|
-
if (value[key] !== undefined && !strings(value[key]))
|
|
169
|
-
invalid(key);
|
|
170
|
-
}
|
|
171
|
-
if (!stringMap(value.globals))
|
|
172
|
-
invalid('globals');
|
|
173
|
-
if (!Array.isArray(value.bridges) || value.bridges.length > 20)
|
|
174
|
-
invalid('bridges');
|
|
175
|
-
const globals = new Set();
|
|
176
|
-
for (const bridge of value.bridges) {
|
|
177
|
-
fields(bridge, ['global', 'style'], ['persistent'], 'bridges');
|
|
178
|
-
if (!text(bridge.global) ||
|
|
179
|
-
!/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*$/.test(bridge.global) ||
|
|
180
|
-
bridge.global
|
|
181
|
-
.split('.')
|
|
182
|
-
.some(part => ['__proto__', 'prototype', 'constructor'].includes(part)) ||
|
|
183
|
-
globals.has(bridge.global) ||
|
|
184
|
-
!BRIDGE_STYLES.has(bridge.style) ||
|
|
185
|
-
(bridge.persistent !== undefined && typeof bridge.persistent !== 'boolean'))
|
|
186
|
-
invalid('bridge');
|
|
187
|
-
globals.add(bridge.global);
|
|
188
|
-
}
|
|
189
|
-
validateActions(value.actions);
|
|
190
|
-
if (value.settingsGroup !== undefined &&
|
|
191
|
-
!['fliggy', 'alipay'].includes(value.settingsGroup))
|
|
192
|
-
invalid('settingsGroup');
|
|
193
|
-
if (value.uaFamily !== undefined &&
|
|
194
|
-
!['aliapp', 'wechatMiniProgram'].includes(value.uaFamily))
|
|
195
|
-
invalid('uaFamily');
|
|
196
|
-
if (value.uaTemplate !== undefined) {
|
|
197
|
-
fields(value.uaTemplate, ['ios', 'android'], [], 'uaTemplate');
|
|
198
|
-
if (!text(value.uaTemplate.ios) || !text(value.uaTemplate.android))
|
|
199
|
-
invalid('uaTemplate');
|
|
200
|
-
}
|
|
201
|
-
if (value.policies !== undefined) {
|
|
202
|
-
fields(value.policies, [], ['titleBar', 'navigatorLanguage', 'networkResult', 'languages', 'defaultLanguage'], 'policies');
|
|
203
|
-
const p = value.policies;
|
|
204
|
-
if (p.titleBar !== undefined &&
|
|
205
|
-
!['default', 'taobao', 'fliggy', 'alipay', 'wechat'].includes(p.titleBar))
|
|
206
|
-
invalid('policies.titleBar');
|
|
207
|
-
if (p.networkResult !== undefined && !['default', 'alipay'].includes(p.networkResult))
|
|
208
|
-
invalid('policies.networkResult');
|
|
209
|
-
if (p.navigatorLanguage !== undefined && typeof p.navigatorLanguage !== 'boolean')
|
|
210
|
-
invalid('policies.navigatorLanguage');
|
|
211
|
-
if (p.languages !== undefined && (!strings(p.languages) || !p.languages.length))
|
|
212
|
-
invalid('policies.languages');
|
|
213
|
-
if (p.defaultLanguage !== undefined &&
|
|
214
|
-
(!text(p.defaultLanguage) ||
|
|
215
|
-
(p.languages && !p.languages.includes(p.defaultLanguage))))
|
|
216
|
-
invalid('policies.defaultLanguage');
|
|
217
|
-
}
|
|
218
|
-
if (!Array.isArray(value.schemes) || value.schemes.length > 100)
|
|
219
|
-
invalid('schemes');
|
|
220
|
-
for (const rule of value.schemes) {
|
|
221
|
-
fields(rule, ['match'], [
|
|
222
|
-
'hostSuffixes',
|
|
223
|
-
'param',
|
|
224
|
-
'useCurrentOrigin',
|
|
225
|
-
'targetPath',
|
|
226
|
-
'targetHostPrefix',
|
|
227
|
-
'targetParams',
|
|
228
|
-
], 'scheme');
|
|
229
|
-
for (const key of ['match', 'param', 'targetPath', 'targetHostPrefix'])
|
|
230
|
-
if (rule[key] !== undefined && !text(rule[key]))
|
|
231
|
-
invalid(`scheme.${key}`);
|
|
232
|
-
if (rule.hostSuffixes !== undefined && !strings(rule.hostSuffixes))
|
|
233
|
-
invalid('scheme.hostSuffixes');
|
|
234
|
-
if (rule.useCurrentOrigin !== undefined && typeof rule.useCurrentOrigin !== 'boolean')
|
|
235
|
-
invalid('scheme.useCurrentOrigin');
|
|
236
|
-
if (rule.targetParams !== undefined && !stringMap(rule.targetParams))
|
|
237
|
-
invalid('scheme.targetParams');
|
|
238
|
-
}
|
|
239
|
-
if (value.settings !== undefined) {
|
|
240
|
-
if (!Array.isArray(value.settings) || value.settings.length > 30)
|
|
241
|
-
invalid('settings');
|
|
242
|
-
const ids = new Set();
|
|
243
|
-
for (const setting of value.settings) {
|
|
244
|
-
fields(setting, ['id', 'label', 'type', 'target'], ['choices', 'minimum', 'maximum'], 'setting');
|
|
245
|
-
if (!text(setting.id) ||
|
|
246
|
-
!/^[a-z][a-zA-Z0-9-]*$/.test(setting.id) ||
|
|
247
|
-
ids.has(setting.id) ||
|
|
248
|
-
!text(setting.label) ||
|
|
249
|
-
!['select', 'boolean', 'number', 'text', 'json'].includes(setting.type))
|
|
250
|
-
invalid('setting');
|
|
251
|
-
ids.add(setting.id);
|
|
252
|
-
if (record(setting.target) && setting.target.option !== undefined) {
|
|
253
|
-
fields(setting.target, ['option'], [], 'setting.target');
|
|
254
|
-
if (setting.target.option !== 'language')
|
|
255
|
-
invalid('setting.target.option');
|
|
256
|
-
}
|
|
257
|
-
else {
|
|
258
|
-
fields(setting.target, ['method'], ['field'], 'setting.target');
|
|
259
|
-
if (!text(setting.target.method) ||
|
|
260
|
-
!setting.target.method ||
|
|
261
|
-
['__proto__', 'prototype', 'constructor'].includes(setting.target.method) ||
|
|
262
|
-
(setting.target.field !== undefined &&
|
|
263
|
-
(!text(setting.target.field) ||
|
|
264
|
-
['__proto__', 'prototype', 'constructor'].includes(setting.target.field))))
|
|
265
|
-
invalid('setting.target.method');
|
|
266
|
-
const method = setting.target.method;
|
|
267
|
-
if ([
|
|
268
|
-
'open',
|
|
269
|
-
'close',
|
|
270
|
-
'title',
|
|
271
|
-
'navigationBar',
|
|
272
|
-
'statusBar',
|
|
273
|
-
'systemInfo',
|
|
274
|
-
'mtop',
|
|
275
|
-
'kvGet',
|
|
276
|
-
'kvSet',
|
|
277
|
-
'kvDelete',
|
|
278
|
-
'pageContext',
|
|
279
|
-
].some(key => value.actions[key]?.includes(method)))
|
|
280
|
-
invalid('setting targets a structural method');
|
|
281
|
-
}
|
|
282
|
-
if (setting.choices !== undefined &&
|
|
283
|
-
(!Array.isArray(setting.choices) ||
|
|
284
|
-
!setting.choices.length ||
|
|
285
|
-
setting.choices.some(choice => !record(choice) || !text(choice.label) || !text(choice.value))))
|
|
286
|
-
invalid('setting.choices');
|
|
287
|
-
for (const key of ['minimum', 'maximum'])
|
|
288
|
-
if (setting[key] !== undefined && typeof setting[key] !== 'number')
|
|
289
|
-
invalid(`setting.${key}`);
|
|
290
|
-
if (setting.type === 'select' && !Array.isArray(setting.choices))
|
|
291
|
-
invalid('setting.choices required');
|
|
292
|
-
if (setting.minimum !== undefined &&
|
|
293
|
-
setting.maximum !== undefined &&
|
|
294
|
-
setting.minimum > setting.maximum)
|
|
295
|
-
invalid('setting range');
|
|
296
|
-
if ('option' in setting.target && !['select', 'text'].includes(setting.type))
|
|
297
|
-
invalid('setting.option type');
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
for (const key of ['forceH5Mtop'])
|
|
301
|
-
if (value[key] !== undefined && typeof value[key] !== 'boolean')
|
|
302
|
-
invalid(key);
|
|
303
|
-
for (const key of ['popBeforeOpenParam', 'messageEvent'])
|
|
304
|
-
if (value[key] !== undefined && !text(value[key]))
|
|
305
|
-
invalid(key);
|
|
306
|
-
if (value.statusBarBackgroundColors !== undefined && !stringMap(value.statusBarBackgroundColors))
|
|
307
|
-
invalid('statusBarBackgroundColors');
|
|
308
|
-
validateStructuredOptions(value);
|
|
309
|
-
return JSON.parse(JSON.stringify(value));
|
|
310
|
-
}
|
|
311
|
-
function validateStructuredOptions(value) {
|
|
312
|
-
const shapes = {
|
|
313
|
-
nativeBack: [[], ['event', 'controlFunction', 'handler']],
|
|
314
|
-
geolocation: [['reverseGeocodeApi', 'version'], []],
|
|
315
|
-
layerUrlProxy: [
|
|
316
|
-
['sourceHostPrefix', 'pathPrefix', 'targetHostSuffixes'],
|
|
317
|
-
['defaultTargetHost'],
|
|
318
|
-
],
|
|
319
|
-
imagePicker: [
|
|
320
|
-
['schemes', 'api', 'version', 'fcId', 'fcGroup', 'uploadUrlFunction', 'prefix', 'region'],
|
|
321
|
-
[],
|
|
322
|
-
],
|
|
323
|
-
overlay: [
|
|
324
|
-
[
|
|
325
|
-
'enabledParam',
|
|
326
|
-
'topRatioParam',
|
|
327
|
-
'radiusParam',
|
|
328
|
-
'maskAlphaParam',
|
|
329
|
-
'tapCloseParam',
|
|
330
|
-
'defaultTopRatio',
|
|
331
|
-
'defaultRadius',
|
|
332
|
-
'defaultMaskAlpha',
|
|
333
|
-
'defaultTapClose',
|
|
334
|
-
],
|
|
335
|
-
[
|
|
336
|
-
'heightRatioParam',
|
|
337
|
-
'tapCloseSelectors',
|
|
338
|
-
'silentTapClose',
|
|
339
|
-
'maxWidthPx',
|
|
340
|
-
'maxWidthMinAppVersion',
|
|
341
|
-
],
|
|
342
|
-
],
|
|
343
|
-
};
|
|
344
|
-
for (const [key, [required, optional]] of Object.entries(shapes)) {
|
|
345
|
-
if (value[key] === undefined)
|
|
346
|
-
continue;
|
|
347
|
-
fields(value[key], required, optional, key);
|
|
348
|
-
for (const [field, item] of Object.entries(value[key])) {
|
|
349
|
-
const valid = field === 'maxWidthPx'
|
|
350
|
-
? typeof item === 'number' && Number.isFinite(item) && item > 0
|
|
351
|
-
: field === 'maxWidthMinAppVersion'
|
|
352
|
-
? typeof item === 'string' && /^\d+(?:\.\d+)*$/.test(item)
|
|
353
|
-
: field.startsWith('default') && field !== 'defaultTargetHost'
|
|
354
|
-
? field === 'defaultTapClose'
|
|
355
|
-
? typeof item === 'boolean'
|
|
356
|
-
: typeof item === 'number'
|
|
357
|
-
: field === 'silentTapClose'
|
|
358
|
-
? typeof item === 'boolean'
|
|
359
|
-
: ['schemes', 'targetHostSuffixes', 'tapCloseSelectors'].includes(field)
|
|
360
|
-
? strings(item)
|
|
361
|
-
: text(item);
|
|
362
|
-
if (!valid)
|
|
363
|
-
invalid(`${key}.${field}`);
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
if (value.rootContainer !== undefined) {
|
|
367
|
-
fields(value.rootContainer, [], ['statusBarHeightCookie'], 'rootContainer');
|
|
368
|
-
if (value.rootContainer.statusBarHeightCookie !== undefined) {
|
|
369
|
-
fields(value.rootContainer.statusBarHeightCookie, ['name'], ['domain', 'path'], 'rootContainer.statusBarHeightCookie');
|
|
370
|
-
if (!Object.values(value.rootContainer.statusBarHeightCookie).every(text))
|
|
371
|
-
invalid('rootContainer.statusBarHeightCookie');
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
if (value.titleBarHostStyles !== undefined &&
|
|
375
|
-
(!Array.isArray(value.titleBarHostStyles) ||
|
|
376
|
-
value.titleBarHostStyles.some(rule => {
|
|
377
|
-
fields(rule, ['hostSuffix'], ['titleBarBackgroundColor', 'statusBarBackgroundColor'], 'titleBarHostStyle');
|
|
378
|
-
return !Object.values(rule).every(text);
|
|
379
|
-
})))
|
|
380
|
-
invalid('titleBarHostStyles');
|
|
381
|
-
if (value.miniProgram !== undefined) {
|
|
382
|
-
fields(value.miniProgram, [], ['paymentRoutes', 'nativeRoutes', 'messageRules'], 'miniProgram');
|
|
383
|
-
const shapes = {
|
|
384
|
-
paymentRoutes: [
|
|
385
|
-
['pathname', 'paymentParamsParam', 'successUrlParams', 'failureUrlParams'],
|
|
386
|
-
['hostSuffixes', 'successResultParam', 'forwardParams', 'useCurrentOrigin'],
|
|
387
|
-
],
|
|
388
|
-
nativeRoutes: [['pathname', 'actions'], ['hostSuffixes']],
|
|
389
|
-
messageRules: [['type', 'action'], ['hostSuffixes']],
|
|
390
|
-
};
|
|
391
|
-
for (const [key, list] of Object.entries(value.miniProgram)) {
|
|
392
|
-
if (!Array.isArray(list) || list.length > 100)
|
|
393
|
-
invalid(`miniProgram.${key}`);
|
|
394
|
-
for (const rule of list) {
|
|
395
|
-
fields(rule, ...shapes[key], `miniProgram.${key}`);
|
|
396
|
-
for (const [field, item] of Object.entries(rule)) {
|
|
397
|
-
if ([
|
|
398
|
-
'hostSuffixes',
|
|
399
|
-
'successUrlParams',
|
|
400
|
-
'failureUrlParams',
|
|
401
|
-
'forwardParams',
|
|
402
|
-
'actions',
|
|
403
|
-
].includes(field)
|
|
404
|
-
? !strings(item)
|
|
405
|
-
: field === 'useCurrentOrigin'
|
|
406
|
-
? typeof item !== 'boolean'
|
|
407
|
-
: !text(item))
|
|
408
|
-
invalid(`miniProgram.${key}.${field}`);
|
|
409
|
-
}
|
|
410
|
-
if (key === 'messageRules' &&
|
|
411
|
-
!['stageBackData', 'closeAll'].includes(rule.action))
|
|
412
|
-
invalid('miniProgram.messageRules.action');
|
|
413
|
-
if (key === 'nativeRoutes' &&
|
|
414
|
-
!rule.actions.every(action => ['navigateMiniProgram', 'subscribeMessage'].includes(action)))
|
|
415
|
-
invalid('miniProgram.nativeRoutes.actions');
|
|
416
|
-
}
|
|
417
|
-
}
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
export function validateAppProfileContribution(value) {
|
|
421
|
-
if (value === undefined)
|
|
422
|
-
return undefined;
|
|
423
|
-
fields(value, ['version', 'profiles'], [], 'contribution');
|
|
424
|
-
if (value.version !== 1 ||
|
|
425
|
-
!Array.isArray(value.profiles) ||
|
|
426
|
-
!value.profiles.length ||
|
|
427
|
-
value.profiles.length > 20)
|
|
428
|
-
invalid('contribution');
|
|
429
|
-
const profiles = value.profiles.map(validateAppProfileDefinition);
|
|
430
|
-
if (JSON.stringify(profiles).length > 256_000)
|
|
431
|
-
invalid('contribution exceeds 256 KiB');
|
|
432
|
-
if (profiles.some(profile => profile.name.includes('/')))
|
|
433
|
-
invalid('contribution names must be local identifiers');
|
|
434
|
-
if (new Set(profiles.map(profile => profile.name)).size !== profiles.length)
|
|
435
|
-
invalid('duplicate profile name');
|
|
436
|
-
return { version: 1, profiles };
|
|
437
|
-
}
|
|
438
|
-
/** Deterministic identity for immutable definitions; this identifier grants no host permissions. */
|
|
439
|
-
export function appProfileRevision(definition) {
|
|
440
|
-
const canonical = (value) => {
|
|
441
|
-
if (Array.isArray(value))
|
|
442
|
-
return `[${value.map(canonical).join(',')}]`;
|
|
443
|
-
if (record(value))
|
|
444
|
-
return `{${Object.keys(value)
|
|
445
|
-
.sort()
|
|
446
|
-
.map(key => `${JSON.stringify(key)}:${canonical(value[key])}`)
|
|
447
|
-
.join(',')}}`;
|
|
448
|
-
return JSON.stringify(value);
|
|
449
|
-
};
|
|
450
|
-
const source = canonical(definition);
|
|
451
|
-
let left = 2166136261;
|
|
452
|
-
let right = 5381;
|
|
453
|
-
for (let i = 0; i < source.length; i++) {
|
|
454
|
-
left = Math.imul(left ^ source.charCodeAt(i), 16777619);
|
|
455
|
-
right = Math.imul(right, 33) ^ source.charCodeAt(i);
|
|
456
|
-
}
|
|
457
|
-
return `v1-${(left >>> 0).toString(16).padStart(8, '0')}${(right >>> 0).toString(16).padStart(8, '0')}`;
|
|
458
|
-
}
|