@lark-apaas/client-toolkit 1.2.17-alpha.1 → 1.2.17-alpha.10
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/lib/antd-table.d.ts +2 -2
- package/lib/apis/aily-chat.d.ts +2 -0
- package/lib/apis/aily-chat.js +2 -0
- package/lib/apis/components/ActiveLink.d.ts +26 -0
- package/lib/apis/components/ActiveLink.js +66 -0
- package/lib/apis/hooks/useScrollReveal.d.ts +1 -0
- package/lib/apis/hooks/useScrollReveal.js +1 -0
- package/lib/apis/utils/getEnv.d.ts +1 -0
- package/lib/apis/utils/getEnv.js +2 -0
- package/lib/apis/utils/resolveAppUrl.d.ts +1 -0
- package/lib/apis/utils/resolveAppUrl.js +2 -0
- package/lib/apis/utils/scopedStorage.d.ts +1 -0
- package/lib/apis/utils/scopedStorage.js +2 -0
- package/lib/auth.d.ts +1 -0
- package/lib/auth.js +2 -0
- package/lib/components/AppContainer/IframeBridge.d.ts +0 -1
- package/lib/components/AppContainer/IframeBridge.js +1 -20
- package/lib/components/AppContainer/RoutePatternTracker.d.ts +5 -0
- package/lib/components/AppContainer/RoutePatternTracker.js +13 -0
- package/lib/components/AppContainer/api-proxy/core.js +2 -1
- package/lib/components/AppContainer/index.d.ts +9 -2
- package/lib/components/AppContainer/index.js +23 -71
- package/lib/components/AppContainer/safety.js +5 -2
- package/lib/components/AppContainer/utils/childApi.js +1 -0
- package/lib/components/AppContainer/utils/getLarkUser.js +4 -2
- package/lib/components/AppContainer/utils/observable.js +7 -1
- package/lib/components/AppContainer/utils/tea.js +1 -1
- package/lib/components/ErrorRender/index.js +5 -11
- package/lib/components/User/UserSelect.js +1 -13
- package/lib/components/theme/index.d.ts +0 -1
- package/lib/components/theme/index.js +0 -1
- package/lib/components/theme/util.d.ts +0 -2
- package/lib/components/theme/util.js +0 -108
- package/lib/components/ui/toast.d.ts +2 -0
- package/lib/components/ui/toast.js +53 -0
- package/lib/hooks/index.d.ts +1 -0
- package/lib/hooks/index.js +1 -0
- package/lib/hooks/useCurrentUserProfile.js +22 -29
- package/lib/hooks/useLogout.js +2 -17
- package/lib/hooks/useScrollReveal.d.ts +61 -0
- package/lib/hooks/useScrollReveal.js +37 -0
- package/lib/index.js +12 -1
- package/lib/integrations/dataloom.d.ts +3 -1
- package/lib/integrations/dataloom.js +18 -10
- package/lib/integrations/services/DepartmentService.js +3 -2
- package/lib/integrations/services/UserProfileService.js +3 -2
- package/lib/integrations/services/UserService.js +4 -3
- package/lib/integrations/services/types.d.ts +1 -0
- package/lib/logger/batch-logger.js +3 -2
- package/lib/logger/intercept-global-error.js +34 -25
- package/lib/logger/log-types.d.ts +4 -4
- package/lib/logger/log-types.js +1 -1
- package/lib/logger/selected-logs.js +1 -2
- package/lib/runtime/axios.d.ts +5 -0
- package/lib/runtime/axios.js +2 -0
- package/lib/runtime/dayjs.d.ts +5 -0
- package/lib/runtime/dayjs.js +2 -0
- package/lib/runtime/iframe-bridge.d.ts +11 -0
- package/lib/runtime/iframe-bridge.js +29 -0
- package/lib/runtime/index.d.ts +24 -0
- package/lib/runtime/index.js +17 -0
- package/lib/runtime/observable.d.ts +5 -0
- package/lib/runtime/observable.js +2 -0
- package/lib/runtime/react-devtools-hook.d.ts +19 -0
- package/lib/runtime/react-devtools-hook.js +20 -0
- package/lib/runtime/server-log.d.ts +5 -0
- package/lib/runtime/server-log.js +41 -0
- package/lib/runtime/styles.d.ts +5 -0
- package/lib/runtime/styles.js +1 -0
- package/lib/theme-layer.css +2 -1
- package/lib/utils/apiPath.d.ts +5 -0
- package/lib/utils/apiPath.js +5 -0
- package/lib/utils/axiosConfig.js +70 -5
- package/lib/utils/getAppId.d.ts +2 -4
- package/lib/utils/getAppId.js +2 -9
- package/lib/utils/getInitialInfo.d.ts +4 -3
- package/lib/utils/getInitialInfo.js +17 -8
- package/lib/utils/getParentOrigin.js +12 -2
- package/lib/utils/getUserProfile.js +4 -12
- package/lib/utils/hmr-api.d.ts +39 -0
- package/lib/utils/hmr-api.js +36 -0
- package/lib/utils/module-hot.d.ts +9 -5
- package/lib/utils/module-hot.js +9 -10
- package/lib/utils/postMessage.d.ts +0 -1
- package/lib/utils/postMessage.js +19 -6
- package/lib/utils/requestManager.js +1 -3
- package/lib/utils/resolveAppUrl.d.ts +27 -0
- package/lib/utils/resolveAppUrl.js +19 -0
- package/lib/utils/routePattern.d.ts +10 -0
- package/lib/utils/routePattern.js +45 -0
- package/lib/utils/scopedStorage.d.ts +5 -0
- package/lib/utils/scopedStorage.js +46 -0
- package/package.json +9 -8
- package/lib/apis/tools/generateImage.d.ts +0 -1
- package/lib/apis/tools/generateImage.js +0 -1
- package/lib/apis/tools/generateTextStream.d.ts +0 -1
- package/lib/apis/tools/generateTextStream.js +0 -1
- package/lib/components/AppContainer/utils/listenHot.d.ts +0 -1
- package/lib/components/AppContainer/utils/listenHot.js +0 -57
- package/lib/components/theme/ui-config.d.ts +0 -1
- package/lib/components/theme/ui-config.js +0 -2
- package/lib/integrations/generateImage.d.ts +0 -1
- package/lib/integrations/generateImage.js +0 -47
- package/lib/integrations/generateTextStream.d.ts +0 -21
- package/lib/integrations/generateTextStream.js +0 -98
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client Toolkit Runtime
|
|
3
|
+
*
|
|
4
|
+
* 全局初始化逻辑,通过 rspack-plugin 自动注入到用户入口之前
|
|
5
|
+
* 无论用户是否使用 AppContainer,这些基础能力始终可用
|
|
6
|
+
*
|
|
7
|
+
* 执行顺序:
|
|
8
|
+
* 1. 全局样式
|
|
9
|
+
* 2. Dayjs 插件注册
|
|
10
|
+
* 3. Axios 配置
|
|
11
|
+
* 4. 可观测初始化
|
|
12
|
+
* 5. Server Log SSE (开发环境)
|
|
13
|
+
*
|
|
14
|
+
* 兼容性说明:
|
|
15
|
+
* - 使用 __FULLSTACK_RUNTIME_INITIALIZED__ 标志位防止重复初始化
|
|
16
|
+
* - 旧版 AppContainer 和新版 runtime 可以共存
|
|
17
|
+
*/
|
|
18
|
+
import './react-devtools-hook';
|
|
19
|
+
import './styles';
|
|
20
|
+
declare global {
|
|
21
|
+
interface Window {
|
|
22
|
+
__FULLSTACK_RUNTIME_INITIALIZED__?: boolean;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import "./react-devtools-hook.js";
|
|
2
|
+
import "./styles.js";
|
|
3
|
+
import { registerDayjsPlugins } from "./dayjs.js";
|
|
4
|
+
import { initAxiosConfig } from "./axios.js";
|
|
5
|
+
import { initObservable } from "./observable.js";
|
|
6
|
+
import { initServerLog } from "./server-log.js";
|
|
7
|
+
import { initIframeBridge } from "./iframe-bridge.js";
|
|
8
|
+
if (!window.__FULLSTACK_RUNTIME_INITIALIZED__) {
|
|
9
|
+
window.__FULLSTACK_RUNTIME_INITIALIZED__ = true;
|
|
10
|
+
registerDayjsPlugins();
|
|
11
|
+
initAxiosConfig();
|
|
12
|
+
initObservable();
|
|
13
|
+
if ('production' !== process.env.NODE_ENV) {
|
|
14
|
+
initServerLog();
|
|
15
|
+
initIframeBridge();
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inject minimal __REACT_DEVTOOLS_GLOBAL_HOOK__ before React loads.
|
|
3
|
+
* React checks for this hook during module initialization and registers its
|
|
4
|
+
* renderer via hook.inject(). This gives us access to renderer.overrideProps()
|
|
5
|
+
* for live component prop modification in the inspector.
|
|
6
|
+
*
|
|
7
|
+
* Must execute before React's module-level code runs.
|
|
8
|
+
*
|
|
9
|
+
* When react-refresh-runtime runs first (as an rspack runtime module),
|
|
10
|
+
* it may create __REACT_DEVTOOLS_GLOBAL_HOOK__ with an inject() that
|
|
11
|
+
* doesn't populate the renderers Map. We patch the existing hook to
|
|
12
|
+
* ensure renderers are always tracked.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
declare global {
|
|
16
|
+
interface Window {
|
|
17
|
+
__REACT_DEVTOOLS_GLOBAL_HOOK__?: any;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
if ('undefined' != typeof window && 'production' !== process.env.NODE_ENV) if (window.__REACT_DEVTOOLS_GLOBAL_HOOK__) {
|
|
2
|
+
const hook = window.__REACT_DEVTOOLS_GLOBAL_HOOK__;
|
|
3
|
+
if (!(hook.renderers instanceof Map)) hook.renderers = new Map();
|
|
4
|
+
const originalInject = 'function' == typeof hook.inject ? hook.inject.bind(hook) : null;
|
|
5
|
+
hook.inject = function(renderer) {
|
|
6
|
+
const id = originalInject ? originalInject(renderer) : hook.renderers.size + 1;
|
|
7
|
+
if (null != id && !hook.renderers.has(id)) hook.renderers.set(id, renderer);
|
|
8
|
+
return id;
|
|
9
|
+
};
|
|
10
|
+
} else window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = {
|
|
11
|
+
renderers: new Map(),
|
|
12
|
+
supportsFiber: true,
|
|
13
|
+
inject (renderer) {
|
|
14
|
+
const id = this.renderers.size + 1;
|
|
15
|
+
this.renderers.set(id, renderer);
|
|
16
|
+
return id;
|
|
17
|
+
},
|
|
18
|
+
onCommitFiberRoot () {},
|
|
19
|
+
onCommitFiberUnmount () {}
|
|
20
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ServerLogSSEClient } from "../server-log/index.js";
|
|
2
|
+
let client = null;
|
|
3
|
+
function initServerLog() {
|
|
4
|
+
if (window.parent === window) return;
|
|
5
|
+
try {
|
|
6
|
+
const backendUrl = window.location.origin;
|
|
7
|
+
client = new ServerLogSSEClient({
|
|
8
|
+
serverUrl: backendUrl,
|
|
9
|
+
sseEndpoint: '/dev/logs/server-logs/stream',
|
|
10
|
+
debug: true
|
|
11
|
+
});
|
|
12
|
+
client.start();
|
|
13
|
+
console.log('[Runtime] Server log SSE client started');
|
|
14
|
+
document.addEventListener('visibilitychange', handleVisibilityChange);
|
|
15
|
+
window.addEventListener('beforeunload', cleanup);
|
|
16
|
+
window.addEventListener('unload', cleanup);
|
|
17
|
+
} catch (error) {
|
|
18
|
+
console.error('[Runtime] Failed to start server log SSE client:', error);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function handleVisibilityChange() {
|
|
22
|
+
if (!client) return;
|
|
23
|
+
if (document.hidden) {
|
|
24
|
+
client.pause();
|
|
25
|
+
console.log('[Runtime] Tab hidden, SSE paused');
|
|
26
|
+
} else {
|
|
27
|
+
client.resume();
|
|
28
|
+
console.log('[Runtime] Tab visible, SSE resumed');
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function cleanup() {
|
|
32
|
+
if (client) {
|
|
33
|
+
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
34
|
+
window.removeEventListener('beforeunload', cleanup);
|
|
35
|
+
window.removeEventListener('unload', cleanup);
|
|
36
|
+
client.stop();
|
|
37
|
+
client = null;
|
|
38
|
+
console.log('[Runtime] Server log SSE client stopped');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export { initServerLog };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import "../index.css";
|
package/lib/theme-layer.css
CHANGED
package/lib/utils/axiosConfig.js
CHANGED
|
@@ -3,6 +3,21 @@ import { observable } from "@lark-apaas/observable-web";
|
|
|
3
3
|
import { logger } from "../apis/logger.js";
|
|
4
4
|
import { getStacktrace } from "../logger/selected-logs.js";
|
|
5
5
|
import { safeStringify } from "./safeStringify.js";
|
|
6
|
+
import { slardar } from "@lark-apaas/internal-slardar";
|
|
7
|
+
import { getCurrentRoutePattern } from "./routePattern.js";
|
|
8
|
+
const APP_CLIENT_API_LOG_TYPE = 'app_client_api_log';
|
|
9
|
+
function getRefererPath() {
|
|
10
|
+
try {
|
|
11
|
+
return getCurrentRoutePattern();
|
|
12
|
+
} catch {
|
|
13
|
+
return '/';
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function getApiField(method, response, errorResponse, fallbackPath) {
|
|
17
|
+
const matchRoute = response?.headers?.['x-match-route'] || errorResponse?.headers?.['x-match-route'] || '';
|
|
18
|
+
const routePath = matchRoute || fallbackPath;
|
|
19
|
+
return `${method} ${routePath}`;
|
|
20
|
+
}
|
|
6
21
|
const isValidResponse = (resp)=>null != resp && 'object' == typeof resp && 'config' in resp && null !== resp.config && void 0 !== resp.config && 'object' == typeof resp.config && 'status' in resp && 'number' == typeof resp.status && 'data' in resp;
|
|
7
22
|
async function logResponse(ok, responseOrError) {
|
|
8
23
|
if (isValidResponse(responseOrError)) {
|
|
@@ -54,7 +69,7 @@ async function logResponse(ok, responseOrError) {
|
|
|
54
69
|
logTraceID
|
|
55
70
|
};
|
|
56
71
|
if (stacktrace) logMeta.stacktrace = stacktrace;
|
|
57
|
-
logger.
|
|
72
|
+
logger.log({
|
|
58
73
|
level: ok,
|
|
59
74
|
args: [
|
|
60
75
|
parts.join(''),
|
|
@@ -110,7 +125,7 @@ async function logResponse(ok, responseOrError) {
|
|
|
110
125
|
const stacktrace = await requestStacktraceMap.get(requestUUID);
|
|
111
126
|
const logMeta = {};
|
|
112
127
|
if (stacktrace) logMeta.stacktrace = stacktrace;
|
|
113
|
-
logger.
|
|
128
|
+
logger.log({
|
|
114
129
|
level: 'error',
|
|
115
130
|
args: [
|
|
116
131
|
parts.join(''),
|
|
@@ -120,7 +135,7 @@ async function logResponse(ok, responseOrError) {
|
|
|
120
135
|
});
|
|
121
136
|
return;
|
|
122
137
|
}
|
|
123
|
-
logger.
|
|
138
|
+
logger.log({
|
|
124
139
|
level: 'error',
|
|
125
140
|
args: [
|
|
126
141
|
'请求失败:无响应对象或配置信息'
|
|
@@ -139,12 +154,17 @@ function handleSpanEnd(cfg, response, error) {
|
|
|
139
154
|
const url = response?.request?.responseURL || errorResponse?.request?.responseURL || cfg.url || "";
|
|
140
155
|
const method = (cfg.method || 'GET').toUpperCase();
|
|
141
156
|
const path = url.split('?')[0].replace(/^https?:\/\/[^/]+/, '') || '/';
|
|
157
|
+
const referer_path = getRefererPath();
|
|
158
|
+
const api = getApiField(method, response, errorResponse, path);
|
|
159
|
+
const type = APP_CLIENT_API_LOG_TYPE;
|
|
142
160
|
const logData = {
|
|
143
161
|
method,
|
|
144
162
|
path,
|
|
145
163
|
url,
|
|
146
164
|
duration_ms: startTime ? Date.now() - startTime : void 0,
|
|
147
|
-
status: response ? response.status : errorResponse.status || 0
|
|
165
|
+
status: response ? response.status : errorResponse.status || 0,
|
|
166
|
+
referer_path,
|
|
167
|
+
type
|
|
148
168
|
};
|
|
149
169
|
if (error) logData.error_message = errorMessage;
|
|
150
170
|
if ('undefined' != typeof navigator) logData.user_agent = navigator.userAgent;
|
|
@@ -157,7 +177,11 @@ function handleSpanEnd(cfg, response, error) {
|
|
|
157
177
|
const responseData = response?.data || errorResponse?.data;
|
|
158
178
|
if (responseData) logData.response = responseData;
|
|
159
179
|
const level = error ? 'ERROR' : 'INFO';
|
|
160
|
-
observable.log(level, safeStringify(logData), {
|
|
180
|
+
observable.log(level, safeStringify(logData), {
|
|
181
|
+
referer_path,
|
|
182
|
+
api,
|
|
183
|
+
type
|
|
184
|
+
}, currentSpan);
|
|
161
185
|
'function' == typeof currentSpan.end && currentSpan.end();
|
|
162
186
|
} catch (e) {
|
|
163
187
|
console.error('[AxiosTrace] Log span failed:', e);
|
|
@@ -193,6 +217,10 @@ AxiosProto.request = function(configOrUrl, config) {
|
|
|
193
217
|
return response;
|
|
194
218
|
}, (error)=>{
|
|
195
219
|
handleSpanEnd(error.config || finalConfig, null, error);
|
|
220
|
+
slardar.captureException(error, {
|
|
221
|
+
source: 'toolkit',
|
|
222
|
+
module: 'axios-request'
|
|
223
|
+
});
|
|
196
224
|
throw error;
|
|
197
225
|
});
|
|
198
226
|
};
|
|
@@ -234,8 +262,45 @@ function initAxiosConfig(axiosInstance) {
|
|
|
234
262
|
config._startTime = config._startTime || Date.now();
|
|
235
263
|
const csrfToken = window.csrfToken;
|
|
236
264
|
if (csrfToken) config.headers['X-Suda-Csrf-Token'] = csrfToken;
|
|
265
|
+
if ('undefined' != typeof window && window.location?.pathname) config.headers['X-Page-Route'] = window.location.pathname;
|
|
237
266
|
return config;
|
|
238
267
|
}, (error)=>Promise.reject(error));
|
|
268
|
+
instance.interceptors.response.use((response)=>response, (error)=>{
|
|
269
|
+
try {
|
|
270
|
+
if (error.response?.status === 403) {
|
|
271
|
+
const method = (error.config?.method || 'GET').toUpperCase();
|
|
272
|
+
const url = (error.config?.url || '').split('?')[0];
|
|
273
|
+
logger.log({
|
|
274
|
+
level: 'warn',
|
|
275
|
+
args: [
|
|
276
|
+
`请求被拒绝(403):${method} ${url}`,
|
|
277
|
+
{
|
|
278
|
+
状态码: 403,
|
|
279
|
+
返回数据: error.response.data
|
|
280
|
+
}
|
|
281
|
+
],
|
|
282
|
+
meta: {}
|
|
283
|
+
});
|
|
284
|
+
slardar.sendEvent({
|
|
285
|
+
name: 'toolkit_axios_403_downgrade',
|
|
286
|
+
categories: {
|
|
287
|
+
url: String(error.config?.url || ''),
|
|
288
|
+
method: String(error.config?.method || '')
|
|
289
|
+
}
|
|
290
|
+
});
|
|
291
|
+
return error.response;
|
|
292
|
+
}
|
|
293
|
+
} catch (e) {}
|
|
294
|
+
slardar.sendEvent({
|
|
295
|
+
name: 'toolkit_axios_response_error',
|
|
296
|
+
categories: {
|
|
297
|
+
url: String(error.config?.url || ''),
|
|
298
|
+
method: String(error.config?.method || ''),
|
|
299
|
+
status: String(error.response?.status || '')
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
return Promise.reject(error);
|
|
303
|
+
});
|
|
239
304
|
'production' !== process.env.NODE_ENV && instance.interceptors.response.use((response)=>{
|
|
240
305
|
logResponse('success', response);
|
|
241
306
|
return response;
|
package/lib/utils/getAppId.d.ts
CHANGED
package/lib/utils/getAppId.js
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
function getAppId(
|
|
2
|
-
if (window.MIAODA_APP_ID) return window.MIAODA_APP_ID;
|
|
3
|
-
let prefix;
|
|
4
|
-
prefix = path.includes('/ai/feida/runtime/') ? '/ai/feida/runtime/' : path.includes('/spark/r/') ? '/spark/r/' : '/ai/miaoda/';
|
|
1
|
+
function getAppId() {
|
|
5
2
|
const windowAppId = window.appId || null;
|
|
6
|
-
|
|
7
|
-
const remainder = path.substring(prefix.length);
|
|
8
|
-
const nextSlashIndex = remainder.indexOf('/');
|
|
9
|
-
if (-1 === nextSlashIndex) return remainder || windowAppId;
|
|
10
|
-
return remainder.substring(0, nextSlashIndex) || windowAppId;
|
|
3
|
+
return windowAppId;
|
|
11
4
|
}
|
|
12
5
|
export { getAppId };
|
|
@@ -13,9 +13,10 @@ interface AppRuntimePublished {
|
|
|
13
13
|
interface BucketConfig {
|
|
14
14
|
default_bucket_id?: string;
|
|
15
15
|
}
|
|
16
|
-
|
|
17
|
-
export declare function getInitialInfo(refresh?: boolean): Promise<{
|
|
16
|
+
declare let initialInfo: {
|
|
18
17
|
app_info?: AppRuntimePublished;
|
|
19
18
|
app_runtime_extra?: AppRuntimeExtra;
|
|
20
|
-
}
|
|
19
|
+
} | undefined;
|
|
20
|
+
/** 获取应用初始化信息(仅全栈沙箱模式下使用) */
|
|
21
|
+
export declare function getInitialInfo(refresh?: boolean): Promise<typeof initialInfo>;
|
|
21
22
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { getAppId } from "./getAppId.js";
|
|
2
2
|
import { getCsrfToken } from "./getCsrfToken.js";
|
|
3
|
+
import { isNewPathEnabled } from "./apiPath.js";
|
|
3
4
|
async function getAppPublished() {
|
|
4
5
|
try {
|
|
5
6
|
const headers = {
|
|
@@ -8,25 +9,33 @@ async function getAppPublished() {
|
|
|
8
9
|
'x-miaoda-token': window.MIAODA_BUILTIN_TTT,
|
|
9
10
|
'X-Suda-Csrf-Token': getCsrfToken()
|
|
10
11
|
};
|
|
11
|
-
const appId = getAppId(
|
|
12
|
-
const
|
|
12
|
+
const appId = getAppId();
|
|
13
|
+
const path = isNewPathEnabled() ? `/app/${appId}/__runtime__/api/v1/studio/get_published` : `/spark/b/${appId}/get_published`;
|
|
14
|
+
const url = `${window.location.origin}${path}`;
|
|
13
15
|
const response = await fetch(url, {
|
|
14
16
|
method: 'GET',
|
|
15
17
|
headers,
|
|
16
18
|
credentials: 'include'
|
|
17
19
|
});
|
|
18
20
|
const res = await response.json();
|
|
19
|
-
if (0 === res.code) return res.data;
|
|
21
|
+
if (0 === res.code || '0' === res.status_code) return res.data;
|
|
20
22
|
console.error('Error fetching published app info:', res);
|
|
21
23
|
} catch (error) {
|
|
22
24
|
console.error('Error fetching published app info:', error);
|
|
23
25
|
}
|
|
24
26
|
}
|
|
25
27
|
let initialInfo;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
initialInfo
|
|
29
|
-
if (
|
|
30
|
-
|
|
28
|
+
let pendingPromise = null;
|
|
29
|
+
function getInitialInfo(refresh = false) {
|
|
30
|
+
if (initialInfo && !refresh) return Promise.resolve(initialInfo);
|
|
31
|
+
if (pendingPromise && !refresh) return pendingPromise;
|
|
32
|
+
pendingPromise = getAppPublished().then((info)=>{
|
|
33
|
+
initialInfo = info;
|
|
34
|
+
if (initialInfo) window._bucket_id = initialInfo.app_runtime_extra?.bucket?.default_bucket_id;
|
|
35
|
+
return initialInfo;
|
|
36
|
+
}).finally(()=>{
|
|
37
|
+
pendingPromise = null;
|
|
38
|
+
});
|
|
39
|
+
return pendingPromise;
|
|
31
40
|
}
|
|
32
41
|
export { getInitialInfo };
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
function getEnv() {
|
|
2
|
+
switch(globalThis.ENVIRONMENT){
|
|
3
|
+
case 'staging':
|
|
4
|
+
return 'BOE';
|
|
5
|
+
case 'gray':
|
|
6
|
+
return 'PRE';
|
|
7
|
+
case 'online':
|
|
8
|
+
return 'ONLINE';
|
|
9
|
+
default:
|
|
10
|
+
break;
|
|
11
|
+
}
|
|
2
12
|
const { origin } = window.location;
|
|
3
|
-
if (origin.includes('feishuapp.cn') || origin.includes('miaoda.feishuapp.net')) return 'ONLINE';
|
|
4
|
-
if (origin.includes('fsapp.kundou.cn') || origin.includes('miaoda-pre.feishuapp.net')) return 'PRE';
|
|
13
|
+
if (origin.includes('feishuapp.cn') || origin.includes('miaoda.feishuapp.net') || origin.includes('aiforce.cloud') || origin.includes('aiforce.run')) return 'ONLINE';
|
|
14
|
+
if (origin.includes('fsapp.kundou.cn') || origin.includes('miaoda-pre.feishuapp.net') || origin.includes('aiforce-pre.bytedance.net') || origin.includes('aiforce-pre-preview.bytedance.net') || origin.includes('aiforce-pre.cloud') || origin.includes('aiforce-pre.run')) return 'PRE';
|
|
5
15
|
return 'BOE';
|
|
6
16
|
}
|
|
7
17
|
export { getEnv };
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { getAppId } from "./getAppId.js";
|
|
2
2
|
import { getCsrfToken } from "./getCsrfToken.js";
|
|
3
|
-
import {
|
|
4
|
-
import { isSparkRuntime } from "./utils.js";
|
|
3
|
+
import { isNewPathEnabled } from "./apiPath.js";
|
|
5
4
|
async function getUserProfile(request, headers = {}) {
|
|
6
|
-
const appId = getAppId(
|
|
5
|
+
const appId = getAppId();
|
|
7
6
|
if (!appId) return {
|
|
8
7
|
code: 1,
|
|
9
8
|
msg: 'appId is required',
|
|
@@ -15,17 +14,10 @@ async function getUserProfile(request, headers = {}) {
|
|
|
15
14
|
const mergedHeaders = {
|
|
16
15
|
...defaultHeaders,
|
|
17
16
|
...headers,
|
|
18
|
-
'X-Kunlun-Token': window.token,
|
|
19
|
-
'x-miaoda-token': window.MIAODA_BUILTIN_TTT,
|
|
20
|
-
'x-lgw-csrf-token': window.lgw_csrf_token,
|
|
21
17
|
...window.CSRF_HEADERS || {}
|
|
22
18
|
};
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
if (isSparkRuntime()) {
|
|
26
|
-
endpoint = `/spark/b/${appId}/user/profile`;
|
|
27
|
-
mergedHeaders['X-Suda-Csrf-Token'] = getCsrfToken();
|
|
28
|
-
} else endpoint = `/ai/api/${envPath}/v1/apps/${appId}/user/profile`;
|
|
19
|
+
const endpoint = isNewPathEnabled() ? `/app/${appId}/__runtime__/api/v1/studio/user/profile` : `/spark/b/${appId}/user/profile`;
|
|
20
|
+
mergedHeaders['X-Suda-Csrf-Token'] = getCsrfToken();
|
|
29
21
|
const response = await fetch(`${window.location.origin}${endpoint}`, {
|
|
30
22
|
method: 'POST',
|
|
31
23
|
headers: mergedHeaders,
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 统一 HMR API
|
|
3
|
+
*
|
|
4
|
+
* 提供统一的 HMR 成功/失败回调接口,屏蔽 Webpack 和 Vite 的差异。
|
|
5
|
+
*
|
|
6
|
+
* - Webpack/Rspack: 通过 import.meta.webpackHot 或 module.hot
|
|
7
|
+
* - Vite: 通过 error-overlay 注入的 window.__VITE_HMR__
|
|
8
|
+
*
|
|
9
|
+
* @see docs/RFC_HMR_API.md
|
|
10
|
+
*/
|
|
11
|
+
export interface HmrApi {
|
|
12
|
+
/**
|
|
13
|
+
* 注册 HMR 成功回调
|
|
14
|
+
* @param callback 成功回调函数
|
|
15
|
+
* @returns cleanup 函数,用于取消注册
|
|
16
|
+
*/
|
|
17
|
+
onSuccess(callback: () => void): () => void;
|
|
18
|
+
/**
|
|
19
|
+
* 注册 HMR 失败回调
|
|
20
|
+
* @param callback 失败回调函数,参数为错误信息
|
|
21
|
+
* @returns cleanup 函数,用于取消注册
|
|
22
|
+
*/
|
|
23
|
+
onError(callback: (error: unknown) => void): () => void;
|
|
24
|
+
}
|
|
25
|
+
declare global {
|
|
26
|
+
interface Window {
|
|
27
|
+
__VITE_HMR__?: HmrApi;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 获取 HMR API 实例
|
|
32
|
+
*
|
|
33
|
+
* 自动检测当前构建工具(Webpack/Vite)并返回对应实现:
|
|
34
|
+
* - Webpack/Rspack: 使用内置适配器
|
|
35
|
+
* - Vite: 使用 error-overlay 注入的 window.__VITE_HMR__
|
|
36
|
+
*
|
|
37
|
+
* @returns HmrApi 实例,如果不在开发环境或不支持 HMR 则返回 null
|
|
38
|
+
*/
|
|
39
|
+
export declare function getHmrApi(): HmrApi | null;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
function createWebpackHmrApi(hot) {
|
|
2
|
+
return {
|
|
3
|
+
onSuccess (callback) {
|
|
4
|
+
let lastStatus = null;
|
|
5
|
+
const handler = (status)=>{
|
|
6
|
+
if ('idle' === status && 'apply' === lastStatus) try {
|
|
7
|
+
callback();
|
|
8
|
+
} catch (e) {
|
|
9
|
+
console.error('[HMR] Success callback error:', e);
|
|
10
|
+
}
|
|
11
|
+
lastStatus = status;
|
|
12
|
+
};
|
|
13
|
+
hot.addStatusHandler(handler);
|
|
14
|
+
return ()=>hot.removeStatusHandler(handler);
|
|
15
|
+
},
|
|
16
|
+
onError (callback) {
|
|
17
|
+
const handler = (status)=>{
|
|
18
|
+
if ('fail' === status || 'abort' === status) try {
|
|
19
|
+
callback(new Error(`HMR ${status}`));
|
|
20
|
+
} catch (e) {
|
|
21
|
+
console.error('[HMR] Error callback error:', e);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
hot.addStatusHandler(handler);
|
|
25
|
+
return ()=>hot.removeStatusHandler(handler);
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
function getHmrApi() {
|
|
30
|
+
if ('production' === process.env.NODE_ENV) return null;
|
|
31
|
+
if (import.meta.webpackHot) return createWebpackHmrApi(import.meta.webpackHot);
|
|
32
|
+
'undefined' != typeof module && module.hot;
|
|
33
|
+
if (window.__VITE_HMR__) return window.__VITE_HMR__;
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
export { getHmrApi };
|
|
@@ -10,16 +10,20 @@
|
|
|
10
10
|
* - abort: An update was aborted, but the system is still in its previous state
|
|
11
11
|
* - fail: An update has thrown an exception and the system's state has been compromised
|
|
12
12
|
*/
|
|
13
|
-
type ModuleHotType = 'idle' | 'check' | 'prepare' | 'ready' | 'dispose' | 'apply' | 'abort' | 'fail';
|
|
14
|
-
interface ModuleHotInstance {
|
|
13
|
+
export type ModuleHotType = 'idle' | 'check' | 'prepare' | 'ready' | 'dispose' | 'apply' | 'abort' | 'fail';
|
|
14
|
+
export interface ModuleHotInstance {
|
|
15
15
|
addStatusHandler: (handler: (status: ModuleHotType) => void) => void;
|
|
16
16
|
removeStatusHandler: (handler: (status: ModuleHotType) => void) => void;
|
|
17
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* 获取 Webpack HMR 实例
|
|
20
|
+
* 仅支持 Webpack/Rspack 的 HMR API
|
|
21
|
+
*/
|
|
18
22
|
export declare function getModuleHot(): ModuleHotInstance | null;
|
|
19
23
|
/**
|
|
20
24
|
* 创建模块热更成功处理函数
|
|
21
|
-
*
|
|
22
|
-
*
|
|
25
|
+
* 监听模块热更状态,检测 apply -> idle 转换表示热更成功
|
|
26
|
+
*
|
|
27
|
+
* @param callback 热更回调函数,参数为是否成功和当前状态
|
|
23
28
|
*/
|
|
24
29
|
export declare function createApplyHandle(callback: (success: boolean, status: ModuleHotType) => void): (status: ModuleHotType) => void;
|
|
25
|
-
export {};
|
package/lib/utils/module-hot.js
CHANGED
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
function getModuleHot() {
|
|
2
2
|
if ('production' === process.env.NODE_ENV) return null;
|
|
3
|
-
|
|
3
|
+
if (import.meta.webpackHot) return import.meta.webpackHot;
|
|
4
|
+
'undefined' != typeof module && module.hot;
|
|
5
|
+
return null;
|
|
4
6
|
}
|
|
5
7
|
function createApplyHandle(callback) {
|
|
6
|
-
let
|
|
8
|
+
let lastStatus = null;
|
|
7
9
|
return (status)=>{
|
|
8
10
|
if ('fail' === status || 'abort' === status) {
|
|
9
|
-
|
|
11
|
+
lastStatus = status;
|
|
10
12
|
return callback(false, status);
|
|
11
13
|
}
|
|
12
|
-
if (
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
callback(true, status);
|
|
16
|
-
}
|
|
17
|
-
return;
|
|
14
|
+
if ('idle' === status && 'apply' === lastStatus) {
|
|
15
|
+
lastStatus = status;
|
|
16
|
+
return callback(true, status);
|
|
18
17
|
}
|
|
19
|
-
|
|
18
|
+
lastStatus = status;
|
|
20
19
|
};
|
|
21
20
|
}
|
|
22
21
|
export { createApplyHandle, getModuleHot };
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { IncomingMessage, OutgoingMessage } from '../types/iframe-events';
|
|
2
2
|
export declare function resolveParentOrigin(): string;
|
|
3
3
|
export declare function submitPostMessage<T extends OutgoingMessage>(message: T, targetOrigin?: string): void;
|
|
4
|
-
export declare function submitSlardarEvent(event: unknown): void;
|
|
5
4
|
export declare function isOutgoingMessage<T extends OutgoingMessage['type']>(msg: OutgoingMessage, type: T): msg is Extract<OutgoingMessage, {
|
|
6
5
|
type: T;
|
|
7
6
|
}>;
|
package/lib/utils/postMessage.js
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
const PARENT_ORIGIN_KEY = '__parentOrigin';
|
|
2
|
+
function getParentOriginFromParams() {
|
|
3
|
+
try {
|
|
4
|
+
const params = new URLSearchParams(window.location.search);
|
|
5
|
+
const origin = params.get(PARENT_ORIGIN_KEY);
|
|
6
|
+
if (origin) {
|
|
7
|
+
sessionStorage.setItem(PARENT_ORIGIN_KEY, origin);
|
|
8
|
+
return origin;
|
|
9
|
+
}
|
|
10
|
+
} catch {}
|
|
11
|
+
try {
|
|
12
|
+
return sessionStorage.getItem(PARENT_ORIGIN_KEY) || void 0;
|
|
13
|
+
} catch {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
1
17
|
function getLegacyParentOrigin() {
|
|
2
18
|
const { origin } = window.location;
|
|
3
19
|
if (origin.includes('force.feishuapp.net')) return 'https://force.feishu.cn';
|
|
@@ -8,6 +24,8 @@ function getLegacyParentOrigin() {
|
|
|
8
24
|
return 'https://miaoda.feishu-boe.cn';
|
|
9
25
|
}
|
|
10
26
|
function resolveParentOrigin() {
|
|
27
|
+
const paramOrigin = getParentOriginFromParams();
|
|
28
|
+
if (paramOrigin) return paramOrigin;
|
|
11
29
|
return process.env?.FORCE_FRAMEWORK_DOMAIN_MAIN ?? getLegacyParentOrigin();
|
|
12
30
|
}
|
|
13
31
|
function submitPostMessage(message, targetOrigin) {
|
|
@@ -20,15 +38,10 @@ function submitPostMessage(message, targetOrigin) {
|
|
|
20
38
|
console.error('postMessage error', e);
|
|
21
39
|
}
|
|
22
40
|
}
|
|
23
|
-
function submitSlardarEvent(event) {
|
|
24
|
-
const slardar = window.KSlardarWeb;
|
|
25
|
-
if ('function' == typeof slardar) slardar('sendEvent', event);
|
|
26
|
-
else console.warn('hmr listen function not found');
|
|
27
|
-
}
|
|
28
41
|
function isOutgoingMessage(msg, type) {
|
|
29
42
|
return msg.type === type;
|
|
30
43
|
}
|
|
31
44
|
function isIncomingMessage(msg, type) {
|
|
32
45
|
return msg.type === type;
|
|
33
46
|
}
|
|
34
|
-
export { isIncomingMessage, isOutgoingMessage, resolveParentOrigin, submitPostMessage
|
|
47
|
+
export { isIncomingMessage, isOutgoingMessage, resolveParentOrigin, submitPostMessage };
|