@lark-apaas/client-toolkit 1.2.17-alpha.16 → 1.2.17-alpha.18
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/components/AppContainer/index.js +0 -2
- package/lib/components/AppContainer/utils/childApi.js +16 -2
- package/lib/integrations/services/ChatService.d.ts +12 -0
- package/lib/integrations/services/ChatService.js +67 -0
- package/lib/integrations/services/index.d.ts +1 -0
- package/lib/integrations/services/index.js +1 -0
- package/lib/integrations/services/types.d.ts +34 -0
- package/lib/utils/axiosConfig.js +4 -36
- package/package.json +1 -1
- package/lib/components/AppContainer/RoutePatternTracker.d.ts +0 -5
- package/lib/components/AppContainer/RoutePatternTracker.js +0 -13
- package/lib/utils/routePattern.d.ts +0 -13
- package/lib/utils/routePattern.js +0 -63
|
@@ -4,7 +4,6 @@ import { ConfigProvider } from "antd";
|
|
|
4
4
|
import { MiaodaInspector } from "@lark-apaas/miaoda-inspector";
|
|
5
5
|
import zh_CN from "antd/locale/zh_CN";
|
|
6
6
|
import IframeBridge from "./IframeBridge.js";
|
|
7
|
-
import RoutePatternTracker from "./RoutePatternTracker.js";
|
|
8
7
|
import { Toaster } from "./sonner.js";
|
|
9
8
|
import { PageHoc } from "./PageHoc.js";
|
|
10
9
|
import { reportTeaEvent } from "./utils/tea.js";
|
|
@@ -61,7 +60,6 @@ const App = (props)=>{
|
|
|
61
60
|
!disableToaster && true !== appFlags.customToaster && /*#__PURE__*/ jsx(Toaster, {}),
|
|
62
61
|
'production' !== process.env.NODE_ENV && /*#__PURE__*/ jsx(MiaodaInspector, {}),
|
|
63
62
|
'production' !== process.env.NODE_ENV && /*#__PURE__*/ jsx(IframeBridge, {}),
|
|
64
|
-
/*#__PURE__*/ jsx(RoutePatternTracker, {}),
|
|
65
63
|
/*#__PURE__*/ jsx(PageHoc, {
|
|
66
64
|
children: props.children
|
|
67
65
|
})
|
|
@@ -1,6 +1,20 @@
|
|
|
1
1
|
import { normalizeBasePath } from "../../../utils/utils.js";
|
|
2
2
|
import { api_delete, api_get, api_head, api_options, api_patch, api_post, api_put } from "./api-panel.js";
|
|
3
|
-
|
|
3
|
+
async function getRoutes() {
|
|
4
|
+
let routes = [
|
|
5
|
+
{
|
|
6
|
+
path: '/'
|
|
7
|
+
}
|
|
8
|
+
];
|
|
9
|
+
try {
|
|
10
|
+
const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
|
|
11
|
+
const res = await fetch(`${basePath}/routes.json`);
|
|
12
|
+
routes = await res.json();
|
|
13
|
+
} catch (error) {
|
|
14
|
+
console.warn('get routes.json error', error);
|
|
15
|
+
}
|
|
16
|
+
return routes;
|
|
17
|
+
}
|
|
4
18
|
async function getSourceMap() {
|
|
5
19
|
if ('vite' === process.env.BUILD_TOOL) return '';
|
|
6
20
|
let sourceMapContent = '';
|
|
@@ -14,7 +28,7 @@ async function getSourceMap() {
|
|
|
14
28
|
return sourceMapContent;
|
|
15
29
|
}
|
|
16
30
|
const childApi = {
|
|
17
|
-
getRoutes
|
|
31
|
+
getRoutes,
|
|
18
32
|
updateAppInfo: (appInfo)=>{
|
|
19
33
|
dispatchEvent(new CustomEvent('MiaoDaMetaInfoChanged', {
|
|
20
34
|
detail: appInfo
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { BatchGetChatsResponse, SearchChatsParams, SearchChatsResponse } from './types';
|
|
2
|
+
export type ChatServiceConfig = {
|
|
3
|
+
getAppId?: () => string | null | undefined;
|
|
4
|
+
searchChatsUrl?: (appId: string) => string;
|
|
5
|
+
listChatsUrl?: (appId: string) => string;
|
|
6
|
+
};
|
|
7
|
+
export declare class ChatService {
|
|
8
|
+
private config;
|
|
9
|
+
constructor(config?: ChatServiceConfig);
|
|
10
|
+
searchChats(params: SearchChatsParams): Promise<SearchChatsResponse>;
|
|
11
|
+
listChatsByIds(chatIds: string[]): Promise<BatchGetChatsResponse>;
|
|
12
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { getAppId } from "../../utils/getAppId.js";
|
|
2
|
+
const DEFAULT_CONFIG = {
|
|
3
|
+
getAppId: ()=>getAppId(),
|
|
4
|
+
searchChatsUrl: (appId)=>`/app/${appId}/__runtime__/api/v1/account/search`,
|
|
5
|
+
listChatsUrl: (appId)=>`/app/${appId}/__runtime__/api/v1/account/chat/list_chats`
|
|
6
|
+
};
|
|
7
|
+
class ChatService {
|
|
8
|
+
config;
|
|
9
|
+
constructor(config = {}){
|
|
10
|
+
this.config = {
|
|
11
|
+
...DEFAULT_CONFIG,
|
|
12
|
+
...config
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
async searchChats(params) {
|
|
16
|
+
const appId = this.config.getAppId();
|
|
17
|
+
if (!appId) throw new Error('Failed to get appId');
|
|
18
|
+
const response = await fetch(this.config.searchChatsUrl(appId), {
|
|
19
|
+
method: 'POST',
|
|
20
|
+
headers: {
|
|
21
|
+
'Content-Type': 'application/json'
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
query: params.query,
|
|
25
|
+
filters: {
|
|
26
|
+
userParam: {
|
|
27
|
+
commonParam: {
|
|
28
|
+
searchable: false
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
departmentParam: {
|
|
32
|
+
commonParam: {
|
|
33
|
+
searchable: false
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
chatParam: {
|
|
37
|
+
commonParam: {
|
|
38
|
+
searchable: true,
|
|
39
|
+
pageSize: params.pageSize ?? 100,
|
|
40
|
+
offset: params.offset ?? 0
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}),
|
|
45
|
+
credentials: 'include'
|
|
46
|
+
});
|
|
47
|
+
if (!response.ok) throw new Error('Failed to search chats');
|
|
48
|
+
return response.json();
|
|
49
|
+
}
|
|
50
|
+
async listChatsByIds(chatIds) {
|
|
51
|
+
const appId = this.config.getAppId();
|
|
52
|
+
if (!appId) throw new Error('Failed to get appId');
|
|
53
|
+
const response = await fetch(this.config.listChatsUrl(appId), {
|
|
54
|
+
method: 'POST',
|
|
55
|
+
headers: {
|
|
56
|
+
'Content-Type': 'application/json'
|
|
57
|
+
},
|
|
58
|
+
body: JSON.stringify({
|
|
59
|
+
chatIDList: chatIds
|
|
60
|
+
}),
|
|
61
|
+
credentials: 'include'
|
|
62
|
+
});
|
|
63
|
+
if (!response.ok) throw new Error('Failed to fetch chats by ids');
|
|
64
|
+
return response.json();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export { ChatService };
|
|
@@ -62,6 +62,40 @@ export type SearchDepartmentsResponse = {
|
|
|
62
62
|
};
|
|
63
63
|
status_code: string;
|
|
64
64
|
};
|
|
65
|
+
export type ChatInfo = {
|
|
66
|
+
/** 群组 ID */
|
|
67
|
+
chatID: string;
|
|
68
|
+
/** 群组名称(国际化文本) */
|
|
69
|
+
name: I18nText;
|
|
70
|
+
/** 头像:URL 或 16 进制 RGB 颜色 */
|
|
71
|
+
avatar: string;
|
|
72
|
+
/** 是否是外部群 */
|
|
73
|
+
isExternal?: boolean;
|
|
74
|
+
/** 群成员数量(不包括机器人),搜索接口返回,批量查询接口不返回 */
|
|
75
|
+
userCount?: number;
|
|
76
|
+
};
|
|
77
|
+
export type SearchChatsParams = {
|
|
78
|
+
query?: string;
|
|
79
|
+
offset?: number;
|
|
80
|
+
pageSize?: number;
|
|
81
|
+
};
|
|
82
|
+
export type SearchChatsResponse = {
|
|
83
|
+
data: {
|
|
84
|
+
result: {
|
|
85
|
+
chatResult?: {
|
|
86
|
+
total: number;
|
|
87
|
+
items: ChatInfo[];
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
};
|
|
91
|
+
status_code: string;
|
|
92
|
+
};
|
|
93
|
+
export type BatchGetChatsResponse = {
|
|
94
|
+
data: {
|
|
95
|
+
chatInfoMap: Record<string, ChatInfo>;
|
|
96
|
+
};
|
|
97
|
+
status_code: string;
|
|
98
|
+
};
|
|
65
99
|
export type UserProfileAccountStatus = 0 | 1 | 2 | 3 | 4;
|
|
66
100
|
export type SimpleUserProfileInfo = {
|
|
67
101
|
name?: string;
|
package/lib/utils/axiosConfig.js
CHANGED
|
@@ -4,26 +4,6 @@ import { logger } from "../apis/logger.js";
|
|
|
4
4
|
import { getStacktrace } from "../logger/selected-logs.js";
|
|
5
5
|
import { safeStringify } from "./safeStringify.js";
|
|
6
6
|
import { slardar } from "@lark-apaas/internal-slardar";
|
|
7
|
-
import { getCurrentRoutePattern } from "./routePattern.js";
|
|
8
|
-
import { normalizeBasePath } from "./utils.js";
|
|
9
|
-
const APP_CLIENT_API_LOG_TYPE = 'app_client_api_log';
|
|
10
|
-
function getRefererPath() {
|
|
11
|
-
try {
|
|
12
|
-
return getCurrentRoutePattern();
|
|
13
|
-
} catch {
|
|
14
|
-
return '/';
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
function getApiField(method, response, errorResponse, fallbackPath) {
|
|
18
|
-
const matchRoute = response?.headers?.['x-match-route'] || errorResponse?.headers?.['x-match-route'] || '';
|
|
19
|
-
const routePath = matchRoute || fallbackPath;
|
|
20
|
-
return `${method} ${routePath}`;
|
|
21
|
-
}
|
|
22
|
-
function stripBasePath(path) {
|
|
23
|
-
const base = normalizeBasePath(process.env.CLIENT_BASE_PATH);
|
|
24
|
-
if (base && path.startsWith(base)) return path.slice(base.length) || '/';
|
|
25
|
-
return path;
|
|
26
|
-
}
|
|
27
7
|
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;
|
|
28
8
|
async function logResponse(ok, responseOrError) {
|
|
29
9
|
if (isValidResponse(responseOrError)) {
|
|
@@ -159,20 +139,13 @@ function handleSpanEnd(cfg, response, error) {
|
|
|
159
139
|
const errorMessage = error?.message || '未知错误';
|
|
160
140
|
const url = response?.request?.responseURL || errorResponse?.request?.responseURL || cfg.url || "";
|
|
161
141
|
const method = (cfg.method || 'GET').toUpperCase();
|
|
162
|
-
const
|
|
163
|
-
const path = stripBasePath(rawPath);
|
|
164
|
-
const durationMs = startTime ? Date.now() - startTime : void 0;
|
|
165
|
-
const referer_path = getRefererPath();
|
|
166
|
-
const api = getApiField(method, response, errorResponse, path);
|
|
167
|
-
const type = APP_CLIENT_API_LOG_TYPE;
|
|
142
|
+
const path = url.split('?')[0].replace(/^https?:\/\/[^/]+/, '') || '/';
|
|
168
143
|
const logData = {
|
|
169
144
|
method,
|
|
170
145
|
path,
|
|
171
146
|
url,
|
|
172
|
-
duration_ms:
|
|
173
|
-
status: response ? response.status : errorResponse.status || 0
|
|
174
|
-
referer_path,
|
|
175
|
-
type
|
|
147
|
+
duration_ms: startTime ? Date.now() - startTime : void 0,
|
|
148
|
+
status: response ? response.status : errorResponse.status || 0
|
|
176
149
|
};
|
|
177
150
|
if (error) logData.error_message = errorMessage;
|
|
178
151
|
if ('undefined' != typeof navigator) logData.user_agent = navigator.userAgent;
|
|
@@ -185,12 +158,7 @@ function handleSpanEnd(cfg, response, error) {
|
|
|
185
158
|
const responseData = response?.data || errorResponse?.data;
|
|
186
159
|
if (responseData) logData.response = responseData;
|
|
187
160
|
const level = error ? 'ERROR' : 'INFO';
|
|
188
|
-
observable.log(level, safeStringify(logData), {
|
|
189
|
-
referer_path,
|
|
190
|
-
api,
|
|
191
|
-
type,
|
|
192
|
-
duration_ms: durationMs
|
|
193
|
-
}, currentSpan);
|
|
161
|
+
observable.log(level, safeStringify(logData), {}, currentSpan);
|
|
194
162
|
'function' == typeof currentSpan.end && currentSpan.end();
|
|
195
163
|
} catch (e) {
|
|
196
164
|
console.error('[AxiosTrace] Log span failed:', e);
|
package/package.json
CHANGED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { useEffect } from "react";
|
|
2
|
-
import { useLocation } from "react-router-dom";
|
|
3
|
-
import { updateRoutePattern } from "../../utils/routePattern.js";
|
|
4
|
-
function RoutePatternTracker() {
|
|
5
|
-
const location = useLocation();
|
|
6
|
-
useEffect(()=>{
|
|
7
|
-
updateRoutePattern(location.pathname);
|
|
8
|
-
}, [
|
|
9
|
-
location.pathname
|
|
10
|
-
]);
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
export { RoutePatternTracker as default };
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export declare function getRouteDefinitions(): Promise<{
|
|
2
|
-
path: string;
|
|
3
|
-
}[]>;
|
|
4
|
-
/**
|
|
5
|
-
* 根据当前 pathname 匹配路由模式并更新存储
|
|
6
|
-
* 使用 react-router 的 matchPath 确保匹配逻辑与路由一致
|
|
7
|
-
*/
|
|
8
|
-
export declare function updateRoutePattern(pathname: string): Promise<void>;
|
|
9
|
-
/**
|
|
10
|
-
* 获取当前匹配的参数化路由模式
|
|
11
|
-
* 供 axiosConfig 等非 React 上下文使用
|
|
12
|
-
*/
|
|
13
|
-
export declare function getCurrentRoutePattern(): string;
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
import { matchPath } from "react-router-dom";
|
|
2
|
-
import { normalizeBasePath } from "./utils.js";
|
|
3
|
-
let currentRoutePattern = '/';
|
|
4
|
-
let routeDefinitions = null;
|
|
5
|
-
function getInjectedRouteDefinitions() {
|
|
6
|
-
try {
|
|
7
|
-
const raw = process.env.__ROUTE_DEFINITIONS__;
|
|
8
|
-
if (raw) {
|
|
9
|
-
const parsed = JSON.parse(raw);
|
|
10
|
-
if (Array.isArray(parsed) && parsed.length > 0) return parsed;
|
|
11
|
-
}
|
|
12
|
-
} catch {}
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
|
-
async function loadRouteDefinitions() {
|
|
16
|
-
if (routeDefinitions) return routeDefinitions;
|
|
17
|
-
const injected = getInjectedRouteDefinitions();
|
|
18
|
-
if (injected) {
|
|
19
|
-
routeDefinitions = injected;
|
|
20
|
-
return routeDefinitions;
|
|
21
|
-
}
|
|
22
|
-
try {
|
|
23
|
-
const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
|
|
24
|
-
const res = await fetch(`${basePath}/routes.json`);
|
|
25
|
-
routeDefinitions = await res.json();
|
|
26
|
-
} catch {
|
|
27
|
-
routeDefinitions = [
|
|
28
|
-
{
|
|
29
|
-
path: '/'
|
|
30
|
-
}
|
|
31
|
-
];
|
|
32
|
-
}
|
|
33
|
-
return routeDefinitions;
|
|
34
|
-
}
|
|
35
|
-
async function getRouteDefinitions() {
|
|
36
|
-
return loadRouteDefinitions();
|
|
37
|
-
}
|
|
38
|
-
async function updateRoutePattern(pathname) {
|
|
39
|
-
const routes = await loadRouteDefinitions();
|
|
40
|
-
const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
|
|
41
|
-
let relativePath = pathname;
|
|
42
|
-
if (basePath && pathname.startsWith(basePath)) relativePath = pathname.slice(basePath.length) || '/';
|
|
43
|
-
const sortedRoutes = [
|
|
44
|
-
...routes
|
|
45
|
-
].sort((a, b)=>b.path.length - a.path.length);
|
|
46
|
-
for (const route of sortedRoutes){
|
|
47
|
-
let routePath = route.path;
|
|
48
|
-
if (basePath && routePath.startsWith(basePath)) routePath = routePath.slice(basePath.length) || '/';
|
|
49
|
-
const match = matchPath({
|
|
50
|
-
path: routePath,
|
|
51
|
-
end: true
|
|
52
|
-
}, relativePath);
|
|
53
|
-
if (match) {
|
|
54
|
-
currentRoutePattern = routePath;
|
|
55
|
-
return;
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
currentRoutePattern = relativePath;
|
|
59
|
-
}
|
|
60
|
-
function getCurrentRoutePattern() {
|
|
61
|
-
return currentRoutePattern;
|
|
62
|
-
}
|
|
63
|
-
export { getCurrentRoutePattern, getRouteDefinitions, updateRoutePattern };
|