@lark-apaas/client-toolkit 1.1.21-alpha.auth.dev.5 → 1.1.21-alpha.auth.dev.7

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.
Files changed (35) hide show
  1. package/lib/apis/utils/getAxiosForBackend.d.ts +1 -0
  2. package/lib/apis/utils/getAxiosForBackend.js +1 -0
  3. package/lib/components/AppContainer/index.js +40 -1
  4. package/lib/components/AppContainer/safety.js +16 -16
  5. package/lib/components/AppContainer/utils/getLarkUser.d.ts +1 -0
  6. package/lib/components/AppContainer/utils/getLarkUser.js +17 -0
  7. package/lib/components/AppContainer/utils/tea.d.ts +8 -0
  8. package/lib/components/AppContainer/utils/tea.js +51 -0
  9. package/lib/components/ErrorRender/index.js +17 -10
  10. package/lib/components/User/UserDisplay.d.ts +3 -2
  11. package/lib/components/User/UserDisplay.js +22 -21
  12. package/lib/components/User/index.d.ts +1 -1
  13. package/lib/hooks/useCurrentUserProfile.js +4 -4
  14. package/lib/server-log/index.d.ts +9 -0
  15. package/lib/server-log/index.js +2 -0
  16. package/lib/server-log/poller.d.ts +87 -0
  17. package/lib/server-log/poller.js +135 -0
  18. package/lib/server-log/types.d.ts +166 -0
  19. package/lib/server-log/types.js +0 -0
  20. package/lib/types/index.d.ts +1 -0
  21. package/lib/types/tea.d.ts +7 -0
  22. package/lib/types/tea.js +5 -0
  23. package/lib/utils/deviceType.d.ts +3 -0
  24. package/lib/utils/deviceType.js +13 -0
  25. package/lib/utils/getAxiosForBackend.d.ts +11 -0
  26. package/lib/utils/getAxiosForBackend.js +21 -0
  27. package/lib/utils/getParentOrigin.d.ts +1 -0
  28. package/lib/utils/getParentOrigin.js +7 -1
  29. package/lib/utils/requestManager.d.ts +2 -0
  30. package/lib/utils/requestManager.js +26 -0
  31. package/lib/utils/userProfileCache.d.ts +12 -0
  32. package/lib/utils/userProfileCache.js +26 -0
  33. package/package.json +14 -9
  34. /package/lib/{auth/index.d.ts → auth.d.ts} +0 -0
  35. /package/lib/{auth/index.js → auth.js} +0 -0
@@ -0,0 +1 @@
1
+ export * from '../../utils/getAxiosForBackend';
@@ -0,0 +1 @@
1
+ export * from "../../utils/getAxiosForBackend.js";
@@ -1,5 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import { useEffect, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  import { ConfigProvider } from "antd";
4
4
  import { MiaodaInspector } from "@lark-apaas/miaoda-inspector";
5
5
  import IframeBridge from "./IframeBridge.js";
@@ -10,8 +10,12 @@ import { findValueByPixel, generateTailwindRadiusToken, themeColorTokenMap, them
10
10
  import { registerDayjsPlugins } from "./dayjsPlugins.js";
11
11
  import "../../index.css";
12
12
  import { initAxiosConfig } from "../../utils/axiosConfig.js";
13
+ import { reportTeaEvent } from "./utils/tea.js";
13
14
  import { useAppInfo } from "../../hooks/index.js";
15
+ import { TrackKey } from "../../types/tea.js";
14
16
  import safety from "./safety.js";
17
+ import { getAppId } from "../../utils/getAppId.js";
18
+ import { ServerLogPoller } from "../../server-log/index.js";
15
19
  import { AuthProvider } from "@lark-apaas/auth-sdk";
16
20
  registerDayjsPlugins();
17
21
  initAxiosConfig();
@@ -28,6 +32,7 @@ const readCssVarColor = (varName, fallback)=>{
28
32
  const App = (props)=>{
29
33
  const { themeMeta = {}, enableAuth } = props;
30
34
  useAppInfo();
35
+ const serverLogPollerRef = useRef(null);
31
36
  const { rem } = findValueByPixel(themeMetaOptions.themeRadius, themeMeta.borderRadius) || {
32
37
  rem: '0.625'
33
38
  };
@@ -39,6 +44,30 @@ const App = (props)=>{
39
44
  borderRadius: radiusToken
40
45
  }
41
46
  };
47
+ useEffect(()=>{
48
+ if ('production' !== process.env.NODE_ENV && window.parent !== window) {
49
+ try {
50
+ const backendUrl = window.location.origin;
51
+ serverLogPollerRef.current = new ServerLogPoller({
52
+ serverUrl: backendUrl,
53
+ apiPath: '/dev/logs/server-logs',
54
+ pollInterval: 2000,
55
+ limit: 100,
56
+ debug: true
57
+ });
58
+ serverLogPollerRef.current.start();
59
+ console.log('[AppContainer] Server log poller started');
60
+ } catch (error) {
61
+ console.error('[AppContainer] Failed to start server log poller:', error);
62
+ }
63
+ return ()=>{
64
+ if (serverLogPollerRef.current) {
65
+ serverLogPollerRef.current.stop();
66
+ console.log('[AppContainer] Server log poller stopped');
67
+ }
68
+ };
69
+ }
70
+ }, []);
42
71
  useEffect(()=>{
43
72
  if (isMiaodaPreview) fetch(`${location.origin}/ai/api/feida_preview/csrf`).then(()=>{
44
73
  setTimeout(()=>{
@@ -47,6 +76,16 @@ const App = (props)=>{
47
76
  }, 300);
48
77
  });
49
78
  }, []);
79
+ useEffect(()=>{
80
+ if ('production' === process.env.NODE_ENV) reportTeaEvent({
81
+ trackKey: TrackKey.VIEW,
82
+ trackParams: {
83
+ artifact_uid: getAppId(window.location.pathname),
84
+ agent_id: 'agent_miaoda',
85
+ url: window.location.href
86
+ }
87
+ });
88
+ }, []);
50
89
  return /*#__PURE__*/ jsxs(AuthProvider, {
51
90
  config: {
52
91
  enable: enableAuth
@@ -44,7 +44,7 @@ const Component = ()=>{
44
44
  /*#__PURE__*/ jsx(SheetTrigger, {
45
45
  asChild: true,
46
46
  children: /*#__PURE__*/ jsxs("div", {
47
- className: "fixed right-3 bottom-20 inline-flex items-center gap-x-1 border-solid border-[#ffffff1a] border px-2.5 py-1.5 bg-[#1f2329e5] backdrop-blur-[5px] shadow-[0px_6px_12px_0px_#41444a0a,0px_8px_24px_8px_#41444a0a] rounded-md text-[#ebebeb)] font-['PingFang_SC'] text-xs leading-[20px] tracking-[0px] z-[10000000]",
47
+ className: "fixed right-[12px] bottom-[80px] inline-flex items-center gap-x-1 border-solid border-[#ffffff1a] border px-[10px] py-[6px] bg-[#1f2329e5] backdrop-blur-[5px] shadow-[0px_6px_12px_0px_#41444a0a,0px_8px_24px_8px_#41444a0a] rounded-md text-[#ebebeb)] font-['PingFang_SC'] text-xs leading-[20px] tracking-[0px] z-[10000000]",
48
48
  onClick: ()=>{
49
49
  setOpen(true);
50
50
  },
@@ -64,10 +64,10 @@ const Component = ()=>{
64
64
  side: "bottom",
65
65
  className: "z-[10000001] border-none bg-transparent outline-0!",
66
66
  children: /*#__PURE__*/ jsxs("div", {
67
- className: "flex flex-col bg-white overflow-hidden rounded-t-2xl relative",
67
+ className: "flex flex-col bg-white overflow-hidden rounded-t-[16px] relative",
68
68
  children: [
69
69
  /*#__PURE__*/ jsx(X, {
70
- className: "absolute top-2 left-4 size-6 text-[#2B2F36]",
70
+ className: "absolute top-[8px] left-[16px] size-[24px] text-[#2B2F36]",
71
71
  onClick: ()=>setOpen(false)
72
72
  }),
73
73
  /*#__PURE__*/ jsx("img", {
@@ -79,7 +79,7 @@ const Component = ()=>{
79
79
  }
80
80
  }),
81
81
  /*#__PURE__*/ jsxs("div", {
82
- className: "flex flex-col w-full justify-center items-end gap-y-4 border-solid border-[#ffffff0d] border px-5 pt-4 pb-12 shadow-(--shadow-2xs,0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_4px_0px_var(--shadow-2xs-1-color,#1f232905)) rounded-t-[12px] text-[#a6a6a6] font-['PingFang_SC'] text-[12px] leading-[20px] tracking-[0px]",
82
+ className: "flex flex-col w-full justify-center items-end gap-y-[16px] border-solid border-[#ffffff0d] border px-[20px] pt-[16px] pb-[48px] shadow-(--shadow-2xs,0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_4px_0px_var(--shadow-2xs-1-color,#1f232905)) rounded-t-[12px] text-[#a6a6a6] font-['PingFang_SC'] text-[12px] leading-[20px] tracking-[0px]",
83
83
  children: [
84
84
  /*#__PURE__*/ jsxs("div", {
85
85
  className: "self-stretch shrink-0 flex flex-col items-start gap-y-[4px]",
@@ -89,7 +89,7 @@ const Component = ()=>{
89
89
  children: [
90
90
  /*#__PURE__*/ jsx("img", {
91
91
  src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/icon/icon_company_outlined.svg",
92
- className: "shrink-0 w-3.5 h-3.5"
92
+ className: "shrink-0 w-[14px] h-[14px]"
93
93
  }),
94
94
  /*#__PURE__*/ jsxs("p", {
95
95
  className: "shrink-0 min-w-[96px] m-0! text-[#646A73] text-sm",
@@ -105,7 +105,7 @@ const Component = ()=>{
105
105
  children: [
106
106
  /*#__PURE__*/ jsx("img", {
107
107
  src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/icon/icon_efficiency-ai_outlined.svg",
108
- className: "shrink-0 w-3.5 h-3.5"
108
+ className: "shrink-0 w-[14px] h-[14px]"
109
109
  }),
110
110
  /*#__PURE__*/ jsx("p", {
111
111
  className: "shrink-0 min-w-[163px] m-0! text-[#646A73] text-sm",
@@ -116,10 +116,10 @@ const Component = ()=>{
116
116
  ]
117
117
  }),
118
118
  /*#__PURE__*/ jsxs("div", {
119
- className: "self-stretch shrink-0 flex items-start gap-x-4",
119
+ className: "self-stretch shrink-0 flex items-start gap-x-[16px]",
120
120
  children: [
121
121
  /*#__PURE__*/ jsx("div", {
122
- className: "flex-1 flex rounded-[99px] items-center justify-center border-[0.5px] border-[#D0D3D6] bg-white text-[#1F2329] cursor-pointer text-lg py-3",
122
+ className: "flex-1 flex rounded-[99px] items-center justify-center border-[0.5px] border-[#D0D3D6] bg-white text-[#1F2329] cursor-pointer text-lg py-[12px]",
123
123
  onClick: (e)=>{
124
124
  e.stopPropagation();
125
125
  e.preventDefault();
@@ -130,7 +130,7 @@ const Component = ()=>{
130
130
  children: "不再展示"
131
131
  }),
132
132
  /*#__PURE__*/ jsx("div", {
133
- className: "flex-1 flex rounded-[99px] items-center justify-center border-[0.5px] border-black bg-black text-white cursor-pointer text-lg py-3",
133
+ className: "flex-1 flex rounded-[99px] items-center justify-center border-[0.5px] border-black bg-black text-white cursor-pointer text-lg py-[12px]",
134
134
  onClick: ()=>{
135
135
  window.open('https://miaoda.feishu.cn/landing', '_blank');
136
136
  },
@@ -152,7 +152,7 @@ const Component = ()=>{
152
152
  /*#__PURE__*/ jsx(PopoverTrigger, {
153
153
  asChild: true,
154
154
  children: /*#__PURE__*/ jsxs("div", {
155
- className: "fixed right-3 bottom-3 inline-flex items-center gap-x-1 border-solid border-[#ffffff1a] border px-2.5 py-1.5 bg-[#1f2329e5] backdrop-blur-[5px] shadow-[0px_6px_12px_0px_#41444a0a,0px_8px_24px_8px_#41444a0a] rounded-[6px] text-[#ebebeb)] font-['PingFang_SC'] text-xs leading-[20px] tracking-[0px] z-[10000000] cursor-pointer",
155
+ className: "fixed right-[12px] bottom-[12px] inline-flex items-center gap-x-1 border-solid border-[#ffffff1a] border px-[10px] py-[6px] bg-[#1f2329e5] backdrop-blur-[5px] shadow-[0px_6px_12px_0px_#41444a0a,0px_8px_24px_8px_#41444a0a] rounded-[6px] text-[#ebebeb)] font-['PingFang_SC'] text-xs leading-[20px] tracking-[0px] z-[10000000] cursor-pointer",
156
156
  onMouseEnter: ()=>{
157
157
  clearTimeout(timeoutRef.current);
158
158
  setOpen(true);
@@ -173,7 +173,7 @@ const Component = ()=>{
173
173
  })
174
174
  }),
175
175
  /*#__PURE__*/ jsx(PopoverContent, {
176
- className: "overflow-hidden p-0 m-0 border-0 rounded-[12px]!",
176
+ className: "overflow-hidden p-0 m-0 border-0 rounded-[12px]! w-[286px]",
177
177
  style: {
178
178
  boxShadow: '0 6px 12px 0 #41444a0a, 0 8px 24px 0 #41444a0a'
179
179
  },
@@ -188,18 +188,18 @@ const Component = ()=>{
188
188
  timeoutRef.current = setTimeout(()=>setOpen(false), 100);
189
189
  },
190
190
  children: /*#__PURE__*/ jsxs("div", {
191
- className: "flex flex-col bg-[#1F2021]",
191
+ className: "flex flex-col bg-[#1A1A1A]",
192
192
  children: [
193
193
  /*#__PURE__*/ jsx("img", {
194
194
  src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/logo/miaodacover.png",
195
195
  alt: "",
196
- className: "w-72 h-32 cursor-pointer",
196
+ className: "w-[286px] h-[128px] cursor-pointer",
197
197
  onClick: ()=>{
198
198
  window.open('https://miaoda.feishu.cn/landing', '_blank');
199
199
  }
200
200
  }),
201
201
  /*#__PURE__*/ jsxs("div", {
202
- className: "flex flex-col justify-center items-end gap-y-[12px] border-solid border-[#ffffff0d] border pl-[14px] pr-[15px] pt-[11px] pb-[15px] w-[286px] shadow-(--shadow-2xs,0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_4px_0px_var(--shadow-2xs-1-color,#1f232905)) rounded-t-[12px] text-[#a6a6a6] font-['PingFang_SC'] text-[12px] leading-[20px] tracking-[0px]",
202
+ className: "flex flex-col justify-center items-end gap-y-[12px] border-solid border-[#ffffff0d] border pl-[14px] pr-[15px] pt-[11px] pb-[15px] w-[286px] shadow-(--shadow-2xs,0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_8px_2px_var(--shadow-2xs-1-color,#1f232905),0px_2px_4px_0px_var(--shadow-2xs-1-color,#1f232905)) rounded-t-[12px] text-[#a6a6a6] font-['PingFang_SC'] text-[12px] leading-[20px] tracking-[0px] bg-[#1f2021]",
203
203
  children: [
204
204
  /*#__PURE__*/ jsxs("div", {
205
205
  className: "self-stretch shrink-0 flex flex-col items-start gap-y-[4px]",
@@ -236,10 +236,10 @@ const Component = ()=>{
236
236
  ]
237
237
  }),
238
238
  /*#__PURE__*/ jsxs("div", {
239
- className: "self-stretch shrink-0 flex items-start gap-x-[8px]",
239
+ className: "w-full self-stretch shrink-0 flex items-start gap-x-[8px]",
240
240
  children: [
241
241
  /*#__PURE__*/ jsx("div", {
242
- className: "flex-1 flex rounded-lg h-[34px] items-center justify-center border-[0.5px] bg-transparent border-solid hover:bg-[#ffffff08] text-[#ebebeb99] hover:text-[#ebebebe6] cursor-pointer border-[#ffffff1c]",
242
+ className: "flex-1 flex rounded-lg items-center justify-center h-[34px] border-[0.5px] border-solid border-[#ffffff1c] hover:border-[#ffffff33] bg-[#ffffff08] hover:bg-[#ffffff14] cursor-pointer text-[#ebebeb]",
243
243
  "data-custom-element": "safety-close",
244
244
  onClick: (e)=>{
245
245
  e.stopPropagation();
@@ -0,0 +1 @@
1
+ export declare function getLarkUserInfo(): Promise<any>;
@@ -0,0 +1,17 @@
1
+ import { getAppId } from "../../../utils/getAppId.js";
2
+ import { getCsrfToken } from "../../../utils/getCsrfToken.js";
3
+ async function getLarkUserInfo() {
4
+ const appId = getAppId(window.location.pathname);
5
+ if (!appId) return {
6
+ code: 1,
7
+ msg: 'appId is required',
8
+ data: {}
9
+ };
10
+ const response = await fetch(`/spark/b/${appId}/lark/user_info`, {
11
+ headers: {
12
+ 'X-Suda-Csrf-Token': getCsrfToken()
13
+ }
14
+ });
15
+ return await response.json();
16
+ }
17
+ export { getLarkUserInfo };
@@ -0,0 +1,8 @@
1
+ import { type TrackParams } from '../../../types/tea';
2
+ export declare const encryptTea: (message: any) => string;
3
+ /**
4
+ * 初始化Tea 客户端
5
+ * @export
6
+ */
7
+ export declare function createTracker(): Promise<void>;
8
+ export declare const reportTeaEvent: ({ trackKey, trackParams }: TrackParams) => Promise<void>;
@@ -0,0 +1,51 @@
1
+ import blueimp_md5 from "blueimp-md5";
2
+ import sha1 from "crypto-js/sha1";
3
+ import { isMobile } from "../../../utils/deviceType.js";
4
+ import { getEnv } from "../../../utils/getParentOrigin.js";
5
+ import { getLarkUserInfo } from "./getLarkUser.js";
6
+ const saltA = '08a441';
7
+ const saltB = '42b91e';
8
+ const encryptTea = (message)=>{
9
+ const msgString = String(message);
10
+ return sha1(saltA + blueimp_md5(msgString + saltB)).toString();
11
+ };
12
+ let teaInstance = false;
13
+ async function createTracker() {
14
+ const { data } = await getLarkUserInfo();
15
+ const { tenantID, userID } = data || {};
16
+ const userIDEncrypt = userID && '0' !== userID ? encryptTea(userID) : void 0;
17
+ const tenantIDEncrypt = tenantID && '0' !== tenantID ? encryptTea(tenantID) : void 0;
18
+ window.collectEvent('init', {
19
+ app_id: 672575,
20
+ channel: 'cn',
21
+ disable_auto_pv: false,
22
+ enable_ab_test: false,
23
+ enable_debug: false,
24
+ enable_stay_duration: true,
25
+ reportTime: 1000
26
+ });
27
+ window.collectEvent('config', {
28
+ user_unique_id: userIDEncrypt,
29
+ device_type: isMobile() ? 'mobile' : 'pc',
30
+ evtParams: {
31
+ open_from: new URLSearchParams(window.location.search).get('open-from') ?? void 0,
32
+ env: getEnv(),
33
+ user_id: userIDEncrypt,
34
+ tenant_id: tenantIDEncrypt
35
+ }
36
+ });
37
+ teaInstance = true;
38
+ window.collectEvent('start');
39
+ }
40
+ const reportTeaEvent = async ({ trackKey, trackParams = {} })=>{
41
+ try {
42
+ if (!teaInstance) {
43
+ teaInstance = true;
44
+ await createTracker();
45
+ }
46
+ window.collectEvent(trackKey, trackParams);
47
+ } catch (err) {
48
+ console.error(err);
49
+ }
50
+ };
51
+ export { createTracker, encryptTea, reportTeaEvent };
@@ -2,19 +2,26 @@ import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useEffect } from "react";
3
3
  import { logger } from "../../logger/index.js";
4
4
  import { createApplyHandle, getModuleHot } from "../../utils/module-hot.js";
5
+ import { submitPostMessage } from "../../utils/postMessage.js";
5
6
  const RenderError = (props)=>{
6
7
  const { error, resetErrorBoundary } = props;
7
8
  useEffect(()=>{
8
- if (error) logger.log({
9
- level: 'error',
10
- args: [
11
- 'Render Error',
12
- error
13
- ],
14
- meta: {
15
- type: 'render-error'
16
- }
17
- });
9
+ if (error) {
10
+ submitPostMessage({
11
+ type: 'RenderError',
12
+ data: error
13
+ });
14
+ logger.log({
15
+ level: 'error',
16
+ args: [
17
+ 'Render Error',
18
+ error
19
+ ],
20
+ meta: {
21
+ type: 'render-error'
22
+ }
23
+ });
24
+ }
18
25
  }, [
19
26
  error
20
27
  ]);
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import type { IUserProfile } from '../../apis/udt-types';
3
- export interface UserDisplayProps {
3
+ export interface IUserDisplayProps {
4
4
  /**
5
5
  * 支持传入完整的用户资料(IUserProfile)/ 列表(IUserProfile[])
6
6
  * 或仅传入用户 ID(string)/ 列表(string[])。
@@ -11,5 +11,6 @@ export interface UserDisplayProps {
11
11
  className?: string;
12
12
  style?: React.CSSProperties;
13
13
  showLabel?: boolean;
14
+ showUserProfile?: boolean;
14
15
  }
15
- export declare const UserDisplay: React.FC<UserDisplayProps>;
16
+ export declare const UserDisplay: React.FC<IUserDisplayProps>;
@@ -1,10 +1,11 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo, useState } from "react";
3
- import { getDataloom } from "../../integrations/dataloom.js";
3
+ import { getCachedUserProfiles, setCachedUserProfiles } from "../../utils/userProfileCache.js";
4
4
  import { clsxWithTw } from "../../utils/utils.js";
5
5
  import { UserProfile } from "./UserProfile/index.js";
6
6
  import { UserWithAvatar } from "./UserWithAvatar.js";
7
7
  import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover.js";
8
+ import { fetchWithDeduplication } from "../../utils/requestManager.js";
8
9
  const UserDisplay = ({ users, size, className, style, showLabel = true })=>{
9
10
  const normalizedIds = useMemo(()=>{
10
11
  if (!users) return [];
@@ -71,22 +72,20 @@ const UserDisplay = ({ users, size, className, style, showLabel = true })=>{
71
72
  const fetchProfiles = async ()=>{
72
73
  try {
73
74
  setLoadingProfiles(true);
74
- const dataloom = await getDataloom();
75
- if (!dataloom) throw new Error('dataloom client is unavailable');
76
- const ids = normalizedIds.map((id)=>Number(id)).filter((id)=>Number.isFinite(id));
77
- if (!ids.length) {
78
- setResolvedUsers(normalizedIds.map((id)=>inputProfilesMap.get(id) ?? {
79
- user_id: id,
80
- name: '',
81
- avatar: '',
82
- email: '',
83
- status: 1
84
- }));
85
- setLoadingProfiles(false);
86
- return;
87
- }
88
- const response = await dataloom.service.user.getByIds(ids);
89
- const fetchedList = Array.isArray(response?.data) ? response?.data : Array.isArray(response?.data?.user_list) ? response?.data?.user_list : [];
75
+ const { cachedProfiles, remainingIds } = getCachedUserProfiles(normalizedIds);
76
+ if (cachedProfiles.length > 0) setResolvedUsers((prev)=>{
77
+ const updatedUsers = [
78
+ ...prev
79
+ ];
80
+ cachedProfiles.forEach((cached)=>{
81
+ const index = updatedUsers.findIndex((u)=>u.user_id === cached.user_id);
82
+ if (-1 !== index) updatedUsers[index] = cached;
83
+ });
84
+ return updatedUsers;
85
+ });
86
+ if (0 === remainingIds.length) return void setLoadingProfiles(false);
87
+ const fetchedList = await fetchWithDeduplication(remainingIds);
88
+ if (isCancelled || !fetchedList) return;
90
89
  const fetchedMap = new Map();
91
90
  fetchedList.forEach((profile)=>{
92
91
  const id = String(profile?.user_id ?? '');
@@ -99,13 +98,15 @@ const UserDisplay = ({ users, size, className, style, showLabel = true })=>{
99
98
  status: profile?.status ?? 1
100
99
  });
101
100
  });
101
+ setCachedUserProfiles(fetchedList);
102
102
  const mergedUsers = normalizedIds.map((id)=>{
103
103
  const fetched = fetchedMap.get(id);
104
104
  const given = inputProfilesMap.get(id);
105
- const name = given?.name?.trim() ? given.name : fetched?.name ?? '';
106
- const avatar = given?.avatar || fetched?.avatar || '';
107
- const email = given?.email || fetched?.email || '';
108
- const status = given?.status ?? fetched?.status ?? 1;
105
+ const cached = cachedProfiles.find((p)=>p.user_id === id);
106
+ const name = given?.name?.trim() || fetched?.name || cached?.name || '';
107
+ const avatar = given?.avatar || fetched?.avatar || cached?.avatar || '';
108
+ const email = given?.email || fetched?.email || cached?.email || '';
109
+ const status = given?.status ?? fetched?.status ?? cached?.status ?? 1;
109
110
  return {
110
111
  user_id: id,
111
112
  name,
@@ -1,7 +1,7 @@
1
1
  export { UserSelect } from './UserSelect';
2
2
  export type { UserSelectProps } from './UserSelect';
3
3
  export { UserDisplay } from './UserDisplay';
4
- export type { UserDisplayProps } from './UserDisplay';
4
+ export type { IUserDisplayProps as UserDisplayProps } from './UserDisplay';
5
5
  export { UserWithAvatar } from './UserWithAvatar';
6
6
  export type { UserWithAvatarProps } from './type';
7
7
  export { UserProfile } from './UserProfile';
@@ -19,9 +19,9 @@ const useCurrentUserProfile = ()=>{
19
19
  (async ()=>{
20
20
  const dataloom = await getDataloom();
21
21
  const result = await dataloom.service.session.getUserInfo();
22
- const userInfo = result?.data?.user_info;
22
+ const userInfo = result?.data?.userInfo;
23
23
  setUserInfo({
24
- user_id: userInfo?.user_id?.toString(),
24
+ user_id: userInfo?.userID?.toString(),
25
25
  email: userInfo?.email,
26
26
  name: userInfo?.name?.[0]?.text,
27
27
  avatar: userInfo?.avatar?.image?.large,
@@ -32,9 +32,9 @@ const useCurrentUserProfile = ()=>{
32
32
  handleMetaInfoChanged = async ()=>{
33
33
  const dataloom = await getDataloom();
34
34
  const result = await dataloom.service.session.getUserInfo();
35
- const userInfo = result?.data?.user_info;
35
+ const userInfo = result?.data?.userInfo;
36
36
  const newUserInfo = {
37
- user_id: userInfo?.user_id?.toString(),
37
+ user_id: userInfo?.userID?.toString(),
38
38
  email: userInfo?.email,
39
39
  name: userInfo?.name?.[0]?.text,
40
40
  avatar: userInfo?.avatar?.image?.large,
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Server Log 模块
3
+ *
4
+ * 通过 HTTP 轮询方式获取服务端日志并转发给父窗口
5
+ */
6
+ export { ServerLogPoller } from './poller';
7
+ export type { ServerLogPollerOptions } from './poller';
8
+ export type { ServerLog, ServerLogLevel, ServerLogSource, ServerLogMeta, ServerLogPostMessage, ClientToServerMessage, ServerToClientMessage, } from './types';
9
+ export { ServerLogPoller as default } from './poller';
@@ -0,0 +1,2 @@
1
+ import { ServerLogPoller } from "./poller.js";
2
+ export { ServerLogPoller, ServerLogPoller as default };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Server Log Poller (HTTP 轮询版本)
3
+ *
4
+ * 职责:
5
+ * 1. 定期轮询后端 HTTP API (/dev/logs/server-logs)
6
+ * 2. 获取新的服务端日志
7
+ * 3. 将接收到的日志通过 postMessage 转发给父窗口 (miaoda)
8
+ * 4. 管理连接状态并通知父窗口
9
+ *
10
+ * 与 ServerLogForwarder 的区别:
11
+ * - 使用 HTTP 轮询代替 WebSocket
12
+ * - 无需 socket.io-client 依赖
13
+ * - 更简单、更稳定、更易调试
14
+ */
15
+ export interface ServerLogPollerOptions {
16
+ /**
17
+ * 后端服务器 URL
18
+ * @example 'http://localhost:3000'
19
+ */
20
+ serverUrl: string;
21
+ /**
22
+ * API 路径
23
+ * @default '/dev/logs/server-logs'
24
+ */
25
+ apiPath?: string;
26
+ /**
27
+ * 轮询间隔(毫秒)
28
+ * @default 2000
29
+ */
30
+ pollInterval?: number;
31
+ /**
32
+ * 每次获取的日志数量
33
+ * @default 100
34
+ */
35
+ limit?: number;
36
+ /**
37
+ * 是否启用调试日志
38
+ * @default false
39
+ */
40
+ debug?: boolean;
41
+ }
42
+ type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'error';
43
+ export declare class ServerLogPoller {
44
+ private intervalId;
45
+ private status;
46
+ private lastTimestamp;
47
+ private options;
48
+ private isPolling;
49
+ constructor(options: ServerLogPollerOptions);
50
+ /**
51
+ * 启动轮询器
52
+ */
53
+ start(): void;
54
+ /**
55
+ * 停止轮询器
56
+ */
57
+ stop(): void;
58
+ /**
59
+ * 获取当前连接状态
60
+ */
61
+ getStatus(): ConnectionStatus;
62
+ /**
63
+ * 执行一次轮询
64
+ */
65
+ private poll;
66
+ /**
67
+ * 转发日志到父窗口
68
+ */
69
+ private forwardLog;
70
+ /**
71
+ * 更新连接状态并通知父窗口
72
+ */
73
+ private updateStatus;
74
+ /**
75
+ * 发送消息到父窗口
76
+ */
77
+ private postToParent;
78
+ /**
79
+ * 调试日志
80
+ */
81
+ private log;
82
+ /**
83
+ * 错误日志
84
+ */
85
+ private error;
86
+ }
87
+ export {};
@@ -0,0 +1,135 @@
1
+ class ServerLogPoller {
2
+ intervalId = null;
3
+ status = 'disconnected';
4
+ lastTimestamp = 0;
5
+ options;
6
+ isPolling = false;
7
+ constructor(options){
8
+ this.options = {
9
+ serverUrl: options.serverUrl,
10
+ apiPath: (process.env.CLIENT_BASE_PATH || '') + (options.apiPath || '/dev/logs/server-logs'),
11
+ pollInterval: options.pollInterval || 2000,
12
+ limit: options.limit || 100,
13
+ debug: options.debug ?? false
14
+ };
15
+ }
16
+ start() {
17
+ if (this.isPolling) return void this.log('Poller already started');
18
+ this.isPolling = true;
19
+ this.updateStatus('connecting');
20
+ this.log('Starting server log poller...', {
21
+ serverUrl: this.options.serverUrl,
22
+ apiPath: this.options.apiPath,
23
+ pollInterval: this.options.pollInterval
24
+ });
25
+ this.poll();
26
+ this.intervalId = window.setInterval(()=>{
27
+ this.poll();
28
+ }, this.options.pollInterval);
29
+ }
30
+ stop() {
31
+ if (!this.isPolling) return void this.log('Poller not running');
32
+ this.log('Stopping server log poller...');
33
+ if (null !== this.intervalId) {
34
+ window.clearInterval(this.intervalId);
35
+ this.intervalId = null;
36
+ }
37
+ this.isPolling = false;
38
+ this.updateStatus('disconnected');
39
+ }
40
+ getStatus() {
41
+ return this.status;
42
+ }
43
+ async poll() {
44
+ try {
45
+ const url = `${this.options.serverUrl}${this.options.apiPath}?limit=${this.options.limit}&sources=server,trace,server-std,client-std`;
46
+ this.log('Polling...', {
47
+ url
48
+ });
49
+ const response = await fetch(url, {
50
+ method: 'GET',
51
+ headers: {
52
+ Accept: 'application/json'
53
+ },
54
+ signal: AbortSignal.timeout(5000)
55
+ });
56
+ if (!response.ok) throw new Error(`HTTP ${response.status}: ${response.statusText}`);
57
+ const data = await response.json();
58
+ this.log('Received logs', {
59
+ count: data.logs.length,
60
+ total: data.total,
61
+ hasMore: data.hasMore
62
+ });
63
+ const newLogs = data.logs.filter((log)=>log.timestamp > this.lastTimestamp);
64
+ if (newLogs.length > 0) {
65
+ this.lastTimestamp = Math.max(...newLogs.map((log)=>log.timestamp));
66
+ newLogs.sort((a, b)=>a.timestamp - b.timestamp);
67
+ this.log(`Forwarding ${newLogs.length} new logs`);
68
+ newLogs.forEach((log)=>{
69
+ this.forwardLog(log);
70
+ });
71
+ }
72
+ if ('connected' !== this.status) {
73
+ this.updateStatus('connected');
74
+ if (0 === this.lastTimestamp && data.logs.length > 0) this.lastTimestamp = Math.max(...data.logs.map((log)=>log.timestamp));
75
+ }
76
+ } catch (error) {
77
+ this.error('Poll failed', error);
78
+ if ('error' !== this.status) {
79
+ this.updateStatus('error');
80
+ this.postToParent({
81
+ type: 'SERVER_LOG_CONNECTION',
82
+ status: 'error',
83
+ error: error instanceof Error ? error.message : String(error)
84
+ });
85
+ }
86
+ }
87
+ }
88
+ forwardLog(log) {
89
+ try {
90
+ this.log('Forwarding log to parent window', {
91
+ type: 'SERVER_LOG',
92
+ logId: log.id,
93
+ level: log.level,
94
+ tags: log.tags
95
+ });
96
+ this.postToParent({
97
+ type: 'SERVER_LOG',
98
+ payload: JSON.stringify(log)
99
+ });
100
+ this.log('Log forwarded successfully');
101
+ } catch (e) {
102
+ this.error('Failed to forward log', e);
103
+ }
104
+ }
105
+ updateStatus(status) {
106
+ const previousStatus = this.status;
107
+ this.status = status;
108
+ if (previousStatus !== status) {
109
+ this.log(`Status changed: ${previousStatus} → ${status}`);
110
+ this.postToParent({
111
+ type: 'SERVER_LOG_CONNECTION',
112
+ status
113
+ });
114
+ }
115
+ }
116
+ postToParent(message) {
117
+ if (window.parent === window) return;
118
+ try {
119
+ window.parent.postMessage(message, '*');
120
+ } catch (e) {
121
+ this.error('postMessage error', e);
122
+ }
123
+ }
124
+ log(message, data) {
125
+ const enableLog = 'true' === localStorage.getItem('debug_server_log_poller');
126
+ if (this.options.debug && enableLog) if (data) console.log(`[ServerLogPoller] ${message}`, data);
127
+ else console.log(`[ServerLogPoller] ${message}`);
128
+ }
129
+ error(message, error) {
130
+ const enableLog = 'true' === localStorage.getItem('debug_server_log_poller');
131
+ if (enableLog) if (error) console.error(`[ServerLogPoller] ${message}`, error);
132
+ else console.error(`[ServerLogPoller] ${message}`);
133
+ }
134
+ }
135
+ export { ServerLogPoller };
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Server Log Stream 类型定义
3
+ *
4
+ * 这些类型与 @lark-apaas/nestjs-logger 保持一致
5
+ * 用于 iframe 端的日志转发功能
6
+ */
7
+ /**
8
+ * 后端日志级别
9
+ * 与 NestJS LogLevel 对齐,但增加了 fatal
10
+ */
11
+ export type ServerLogLevel = 'fatal' | 'error' | 'warn' | 'log' | 'debug' | 'verbose';
12
+ /**
13
+ * 日志来源
14
+ */
15
+ export type ServerLogSource = 'server' | 'trace' | 'server-std' | 'client-std' | 'browser';
16
+ /**
17
+ * 日志元数据
18
+ */
19
+ export interface ServerLogMeta {
20
+ pid?: number;
21
+ hostname?: string;
22
+ service?: string;
23
+ path?: string;
24
+ method?: string;
25
+ statusCode?: number;
26
+ durationMs?: number;
27
+ ip?: string;
28
+ requestBody?: any;
29
+ responseBody?: any;
30
+ [key: string]: unknown;
31
+ }
32
+ /**
33
+ * 后端日志对象
34
+ * 用于实时推送给前端展示
35
+ */
36
+ export interface ServerLog {
37
+ /**
38
+ * 唯一标识符(UUID)
39
+ * 用于前端去重和引用
40
+ */
41
+ id: string;
42
+ /**
43
+ * 日志级别
44
+ */
45
+ level: ServerLogLevel;
46
+ /**
47
+ * 时间戳(毫秒)
48
+ */
49
+ timestamp: number;
50
+ /**
51
+ * 日志消息
52
+ */
53
+ message: string;
54
+ /**
55
+ * 日志上下文(如 Controller 名称、Service 名称)
56
+ */
57
+ context?: string;
58
+ /**
59
+ * 请求追踪 ID
60
+ * 用于关联同一个请求的所有日志
61
+ */
62
+ traceId?: string;
63
+ /**
64
+ * 用户 ID
65
+ */
66
+ userId?: string;
67
+ /**
68
+ * 应用 ID
69
+ */
70
+ appId?: string;
71
+ /**
72
+ * 租户 ID
73
+ */
74
+ tenantId?: string;
75
+ /**
76
+ * 错误堆栈(仅 ERROR/FATAL 级别)
77
+ */
78
+ stack?: string;
79
+ /**
80
+ * 额外的元数据
81
+ */
82
+ meta?: ServerLogMeta;
83
+ /**
84
+ * 自定义标签
85
+ * 如 ['server', 'bootstrap'] 或 ['trace', 'http']
86
+ */
87
+ tags?: string[];
88
+ }
89
+ /**
90
+ * WebSocket 消息类型(客户端 → 服务端)
91
+ */
92
+ export type ClientToServerMessage = {
93
+ type: 'SUBSCRIBE';
94
+ payload: {
95
+ levels?: ServerLogLevel[];
96
+ tags?: string[];
97
+ sources?: ServerLogSource[];
98
+ };
99
+ } | {
100
+ type: 'UNSUBSCRIBE';
101
+ } | {
102
+ type: 'GET_HISTORY';
103
+ payload: {
104
+ limit?: number;
105
+ offset?: number;
106
+ levels?: ServerLogLevel[];
107
+ sources?: ServerLogSource[];
108
+ };
109
+ } | {
110
+ type: 'CLEAR_LOGS';
111
+ };
112
+ /**
113
+ * WebSocket 消息类型(服务端 → 客户端)
114
+ */
115
+ export type ServerToClientMessage = {
116
+ type: 'CONNECTED';
117
+ payload: {
118
+ clientId: string;
119
+ timestamp: number;
120
+ };
121
+ } | {
122
+ type: 'LOG';
123
+ payload: ServerLog;
124
+ } | {
125
+ type: 'LOGS_BATCH';
126
+ payload: ServerLog[];
127
+ } | {
128
+ type: 'HISTORY';
129
+ payload: {
130
+ logs: ServerLog[];
131
+ total: number;
132
+ hasMore: boolean;
133
+ };
134
+ } | {
135
+ type: 'LOGS_CLEARED';
136
+ } | {
137
+ type: 'SUBSCRIBED';
138
+ payload: {
139
+ levels?: ServerLogLevel[];
140
+ tags?: string[];
141
+ sources?: ServerLogSource[];
142
+ };
143
+ } | {
144
+ type: 'UNSUBSCRIBED';
145
+ } | {
146
+ type: 'ERROR';
147
+ payload: {
148
+ message: string;
149
+ code?: string;
150
+ };
151
+ };
152
+ /**
153
+ * PostMessage 类型(iframe → parent)
154
+ *
155
+ * iframe 端通过 postMessage 将接收到的 WebSocket 消息转发给父窗口
156
+ */
157
+ export type ServerLogPostMessage = {
158
+ type: 'SERVER_LOG';
159
+ payload: string;
160
+ } | {
161
+ type: 'SERVER_LOG_CONNECTION';
162
+ status: 'connected' | 'disconnected' | 'error' | 'connecting';
163
+ error?: string;
164
+ } | {
165
+ type: 'SERVER_LOG_CLEARED';
166
+ };
File without changes
@@ -10,5 +10,6 @@ declare global {
10
10
  _IS_Spark_RUNTIME?: boolean;
11
11
  _bucket_id?: string;
12
12
  csrfToken?: string;
13
+ collectEvent?: (...args: any[]) => void;
13
14
  }
14
15
  }
@@ -0,0 +1,7 @@
1
+ export interface TrackParams {
2
+ trackKey: TrackKey;
3
+ trackParams?: Record<string, unknown>;
4
+ }
5
+ export declare enum TrackKey {
6
+ VIEW = "aily_agent_artifact_page_view"
7
+ }
@@ -0,0 +1,5 @@
1
+ var tea_TrackKey = /*#__PURE__*/ function(TrackKey) {
2
+ TrackKey["VIEW"] = "aily_agent_artifact_page_view";
3
+ return TrackKey;
4
+ }({});
5
+ export { tea_TrackKey as TrackKey };
@@ -0,0 +1,3 @@
1
+ export declare const isIpad: () => boolean;
2
+ export declare const isMobile: () => boolean;
3
+ export declare const isIOS: () => boolean;
@@ -0,0 +1,13 @@
1
+ const isIpad = ()=>{
2
+ const _isIpad = /iPad|Tab|Tablet/i.test(navigator.userAgent) && navigator.maxTouchPoints && navigator.maxTouchPoints > 1;
3
+ return Boolean(_isIpad);
4
+ };
5
+ const isMobile = ()=>{
6
+ const isPhone = /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone)/i.test(navigator.userAgent);
7
+ return isPhone || isIpad();
8
+ };
9
+ const isIOS = ()=>{
10
+ if (/(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent)) return true;
11
+ return false;
12
+ };
13
+ export { isIOS, isIpad, isMobile };
@@ -0,0 +1,11 @@
1
+ import { AxiosInstance } from 'axios';
2
+ declare module 'axios' {
3
+ interface AxiosRequestConfig {
4
+ meta?: {
5
+ autoJumpToLogin?: boolean;
6
+ };
7
+ }
8
+ }
9
+ /** 获取axios实例 */
10
+ export declare function getAxiosForBackend(): AxiosInstance;
11
+ export declare const axiosForBackend: AxiosInstance;
@@ -0,0 +1,21 @@
1
+ import axios from "axios";
2
+ import { initAxiosConfig } from "./axiosConfig.js";
3
+ let axiosInstance;
4
+ function getAxiosForBackend() {
5
+ if (!axiosInstance) {
6
+ axiosInstance = axios.create({
7
+ baseURL: process.env.CLIENT_BASE_PATH || '/'
8
+ });
9
+ axiosInstance.interceptors.response.use(null, (err)=>{
10
+ if (err.config.meta?.autoJumpToLogin !== false) {
11
+ const loginUrl = err.response?.headers?.['x-login-url'];
12
+ if (loginUrl) window.location.href = loginUrl;
13
+ }
14
+ return Promise.reject(err);
15
+ });
16
+ initAxiosConfig(axiosInstance);
17
+ }
18
+ return axiosInstance;
19
+ }
20
+ const axiosForBackend = getAxiosForBackend();
21
+ export { axiosForBackend, getAxiosForBackend };
@@ -1,3 +1,4 @@
1
+ export declare function getEnv(): 'BOE' | 'PRE' | 'ONLINE';
1
2
  /**
2
3
  * @internal
3
4
  * 获取预览环境父级域名
@@ -1,3 +1,9 @@
1
+ function getEnv() {
2
+ 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';
5
+ return 'BOE';
6
+ }
1
7
  function getPreviewParentOrigin() {
2
8
  const { origin } = window.location;
3
9
  if (origin.includes('force.byted.org')) return 'https://force.feishu-boe.cn';
@@ -5,4 +11,4 @@ function getPreviewParentOrigin() {
5
11
  if (origin.includes('fsapp.kundou.cn') || origin.includes('miaoda-pre.feishuapp.net')) return 'https://miaoda.feishu-pre.cn';
6
12
  return 'https://miaoda.feishu-boe.cn';
7
13
  }
8
- export { getPreviewParentOrigin };
14
+ export { getEnv, getPreviewParentOrigin };
@@ -0,0 +1,2 @@
1
+ import type { IUserProfile } from '../apis/udt-types';
2
+ export declare function fetchWithDeduplication(ids: string[]): Promise<IUserProfile[] | null>;
@@ -0,0 +1,26 @@
1
+ import { getDataloom } from "../integrations/dataloom.js";
2
+ const pendingRequests = new Map();
3
+ async function fetchUserProfilesByIds(ids) {
4
+ try {
5
+ const dataloom = await getDataloom();
6
+ if (!dataloom) throw new Error('Dataloom client is unavailable');
7
+ const numericIds = ids.map(Number).filter(Number.isFinite);
8
+ if (0 === numericIds.length) return [];
9
+ const response = await dataloom.service.user.getByIds(numericIds);
10
+ return Array.isArray(response?.data) ? response.data : response?.data?.user_list || [];
11
+ } catch (error) {
12
+ console.error(`Failed to fetch profiles for user IDs ${ids.join(', ')}:`, error);
13
+ return null;
14
+ }
15
+ }
16
+ function fetchWithDeduplication(ids) {
17
+ const key = ids.sort().join(',');
18
+ if (pendingRequests.has(key)) return pendingRequests.get(key);
19
+ const fetchPromise = fetchUserProfilesByIds(ids);
20
+ pendingRequests.set(key, fetchPromise);
21
+ fetchPromise.finally(()=>{
22
+ pendingRequests.delete(key);
23
+ });
24
+ return fetchPromise;
25
+ }
26
+ export { fetchWithDeduplication };
@@ -0,0 +1,12 @@
1
+ import type { IUserProfile } from '../apis/udt-types';
2
+ export interface ICachedUserProfile {
3
+ profile: IUserProfile;
4
+ timestamp: number;
5
+ }
6
+ export declare const cache: Map<string, ICachedUserProfile>;
7
+ export declare const cacheExpiry: number;
8
+ export declare function setCachedUserProfiles(profiles: IUserProfile[]): void;
9
+ export declare function getCachedUserProfiles(ids: string[]): {
10
+ cachedProfiles: IUserProfile[];
11
+ remainingIds: string[];
12
+ };
@@ -0,0 +1,26 @@
1
+ const cache = new Map();
2
+ const cacheExpiry = 1 / 0;
3
+ function setCachedUserProfiles(profiles) {
4
+ const now = Date.now();
5
+ profiles.forEach((profile)=>{
6
+ if (profile && profile.user_id) cache.set(String(profile.user_id), {
7
+ profile,
8
+ timestamp: now
9
+ });
10
+ });
11
+ }
12
+ function getCachedUserProfiles(ids) {
13
+ const cachedProfiles = [];
14
+ const remainingIds = [];
15
+ const now = Date.now();
16
+ ids.forEach((id)=>{
17
+ const cachedItem = cache.get(id);
18
+ if (cachedItem && now - cachedItem.timestamp < cacheExpiry) cachedProfiles.push(cachedItem.profile);
19
+ else remainingIds.push(id);
20
+ });
21
+ return {
22
+ cachedProfiles,
23
+ remainingIds
24
+ };
25
+ }
26
+ export { cache, cacheExpiry, getCachedUserProfiles, setCachedUserProfiles };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-toolkit",
3
- "version": "1.1.21-alpha.auth.dev.5",
3
+ "version": "1.1.21-alpha.auth.dev.7",
4
4
  "types": "./lib/index.d.ts",
5
5
  "main": "./lib/index.js",
6
6
  "files": [
@@ -61,10 +61,10 @@
61
61
  "require": "./lib/apis/utils/*.js",
62
62
  "types": "./lib/apis/utils/*.d.ts"
63
63
  },
64
- "./auth/*": {
65
- "import": "./lib/auth/index.js",
66
- "require": "./lib/auth/index.js",
67
- "types": "./lib/auth/index.d.ts"
64
+ "./auth": {
65
+ "import": "./lib/auth.js",
66
+ "require": "./lib/auth.js",
67
+ "types": "./lib/auth.d.ts"
68
68
  }
69
69
  },
70
70
  "scripts": {
@@ -85,17 +85,19 @@
85
85
  "dependencies": {
86
86
  "@ant-design/colors": "^7.2.1",
87
87
  "@ant-design/cssinjs": "^1.24.0",
88
- "@data-loom/js": "^0.4.0",
89
- "@lark-apaas/auth-sdk": "0.1.0-alpha.9",
90
- "@lark-apaas/miaoda-inspector": "^1.0.4",
88
+ "@data-loom/js": "0.4.4-auth-alpha.6",
89
+ "@lark-apaas/auth-sdk": "0.1.0-alpha.13",
90
+ "@lark-apaas/miaoda-inspector": "^1.0.5",
91
91
  "@radix-ui/react-avatar": "^1.1.10",
92
92
  "@radix-ui/react-popover": "^1.1.15",
93
93
  "@radix-ui/react-slot": "^1.2.3",
94
94
  "@radix-ui/react-tooltip": "^1.2.8",
95
95
  "@zumer/snapdom": "^1.9.14",
96
96
  "axios": "^1.12.2",
97
+ "blueimp-md5": "2.10.0",
97
98
  "class-variance-authority": "^0.7.1",
98
99
  "clsx": "~2.0.1",
100
+ "crypto-js": "3.1.9-1",
99
101
  "dayjs": "^1.11.13",
100
102
  "echarts": "^6.0.0",
101
103
  "lodash": "^4.17.21",
@@ -128,6 +130,8 @@
128
130
  "@tailwindcss/postcss": "^4.1.0",
129
131
  "@testing-library/jest-dom": "^6.6.4",
130
132
  "@testing-library/react": "^16.3.0",
133
+ "@types/blueimp-md5": "^2.18.2",
134
+ "@types/crypto-js": "^4.2.2",
131
135
  "@types/lodash": "^4.17.20",
132
136
  "@types/node": "^22.10.2",
133
137
  "@types/react": "^18.3.23",
@@ -153,6 +157,7 @@
153
157
  "antd": ">=5.26.6",
154
158
  "react": ">=16.14.0",
155
159
  "react-dom": ">=16.14.0",
156
- "react-router-dom": ">=6.26.2"
160
+ "react-router-dom": ">=6.26.2",
161
+ "styled-jsx": ">=5.0.0"
157
162
  }
158
163
  }
File without changes
File without changes