@lark-apaas/client-toolkit 1.1.19 → 1.1.20-alpha.tea.2

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.
@@ -9,8 +9,11 @@ import { findValueByPixel, generateTailwindRadiusToken, themeColorTokenMap, them
9
9
  import { registerDayjsPlugins } from "./dayjsPlugins.js";
10
10
  import "../../index.css";
11
11
  import { initAxiosConfig } from "../../utils/axiosConfig.js";
12
+ import { reportTeaEvent } from "./utils/tea.js";
12
13
  import { useAppInfo } from "../../hooks/index.js";
14
+ import { TrackKey } from "../../types/tea.js";
13
15
  import safety from "./safety.js";
16
+ import { getAppId } from "../../utils/getAppId.js";
14
17
  registerDayjsPlugins();
15
18
  initAxiosConfig();
16
19
  const isMiaodaPreview = window.IS_MIAODA_PREVIEW;
@@ -36,6 +39,16 @@ const App = (props)=>{
36
39
  }, 300);
37
40
  });
38
41
  }, []);
42
+ useEffect(()=>{
43
+ if ('production' === process.env.NODE_ENV) reportTeaEvent({
44
+ trackKey: TrackKey.VIEW,
45
+ trackParams: {
46
+ artifact_uid: getAppId(window.location.pathname),
47
+ agent_id: 'agent_miaoda',
48
+ url: window.location.href
49
+ }
50
+ });
51
+ }, []);
39
52
  return /*#__PURE__*/ jsxs(Fragment, {
40
53
  children: [
41
54
  /*#__PURE__*/ jsx(Toaster, {}),
@@ -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/${getAppId(window.location.pathname)}/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
+ if (!teaInstance) {
42
+ teaInstance = true;
43
+ await createTracker();
44
+ }
45
+ try {
46
+ window.collectEvent(trackKey, trackParams);
47
+ } catch (err) {
48
+ console.error(err);
49
+ }
50
+ };
51
+ export { createTracker, encryptTea, reportTeaEvent };
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
2
  declare const RenderError: React.FC<{
3
3
  error: Error;
4
+ resetErrorBoundary?: () => void;
4
5
  }>;
5
6
  export default RenderError;
@@ -1,10 +1,11 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { useEffect } from "react";
3
3
  import { logger } from "../../logger/index.js";
4
+ import { createApplyHandle, getModuleHot } from "../../utils/module-hot.js";
4
5
  const RenderError = (props)=>{
5
- const { error } = props;
6
+ const { error, resetErrorBoundary } = props;
6
7
  useEffect(()=>{
7
- if (props.error) logger.log({
8
+ if (error) logger.log({
8
9
  level: 'error',
9
10
  args: [
10
11
  'Render Error',
@@ -15,7 +16,22 @@ const RenderError = (props)=>{
15
16
  }
16
17
  });
17
18
  }, [
18
- props.error
19
+ error
20
+ ]);
21
+ useEffect(()=>{
22
+ if (!resetErrorBoundary) return;
23
+ const hot = getModuleHot();
24
+ if (hot) {
25
+ const handler = createApplyHandle((success)=>{
26
+ if (success) resetErrorBoundary();
27
+ });
28
+ hot.addStatusHandler(handler);
29
+ return ()=>{
30
+ hot.removeStatusHandler(handler);
31
+ };
32
+ }
33
+ }, [
34
+ resetErrorBoundary
19
35
  ]);
20
36
  return /*#__PURE__*/ jsx("div", {
21
37
  className: "min-h-screen flex items-center justify-center bg-white",
@@ -1,3 +1,4 @@
1
+ import { createApplyHandle, getModuleHot } from "../utils/module-hot.js";
1
2
  import { submitPostMessage, submitSlardarEvent } from "../utils/postMessage.js";
2
3
  import { levelSchema } from "./log-types.js";
3
4
  import { logger } from "./logger.js";
@@ -61,10 +62,17 @@ function processDevServerLog(log) {
61
62
  });
62
63
  }
63
64
  }
64
- function listenHmrApplyFailed() {
65
- const hot = import.meta.webpackHot || module.hot;
66
- if (hot) hot.addStatusHandler((status)=>{
67
- if ('fail' === status || 'abort' === status) {
65
+ function listenModuleHmr() {
66
+ const hot = getModuleHot();
67
+ if (hot) hot.addStatusHandler(createApplyHandle((success, status)=>{
68
+ if (success) submitPostMessage({
69
+ type: 'DevServerMessage',
70
+ data: {
71
+ type: 'devServer-status',
72
+ status: 'hmr-apply-success'
73
+ }
74
+ });
75
+ else {
68
76
  console.warn('hmr apply failed', status);
69
77
  submitSlardarEvent({
70
78
  name: 'sandbox-devServer',
@@ -74,7 +82,7 @@ function listenHmrApplyFailed() {
74
82
  }
75
83
  });
76
84
  }
77
- });
85
+ }));
78
86
  }
79
87
  function interceptErrors() {
80
88
  window.addEventListener('error', (event)=>{
@@ -83,7 +91,7 @@ function interceptErrors() {
83
91
  window.addEventListener('unhandledrejection', (event)=>{
84
92
  logger.error(event.reason);
85
93
  });
86
- listenHmrApplyFailed();
94
+ listenModuleHmr();
87
95
  const PROXY_CONSOLE_METHOD = [
88
96
  'log',
89
97
  'info',
@@ -41,7 +41,7 @@ export interface HmrMessage extends IframeMessage<Record<string, never>> {
41
41
  /** devServer相关消息 */
42
42
  export interface DevServerMessage extends IframeMessage<{
43
43
  type: 'devServer-status';
44
- status: 'connected' | 'disconnected';
44
+ status: 'connected' | 'disconnected' | 'hmr-apply-success';
45
45
  }> {
46
46
  type: 'DevServerMessage';
47
47
  }
@@ -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 };
@@ -1,3 +1,4 @@
1
+ export declare function getEnv(): 'BOE' | 'PRE' | 'ONLINE';
1
2
  /**
2
3
  * @internal
3
4
  * 获取预览环境父级域名
@@ -1,7 +1,13 @@
1
- function getPreviewParentOrigin() {
1
+ function getEnv() {
2
2
  const { origin } = window.location;
3
- if (origin.includes('feishuapp.cn') || origin.includes('miaoda.feishuapp.net')) return 'https://miaoda.feishu.cn';
4
- if (origin.includes('fsapp.kundou.cn') || origin.includes('miaoda-pre.feishuapp.net')) return 'https://miaoda.feishu-pre.cn';
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
+ }
7
+ function getPreviewParentOrigin() {
8
+ const env = getEnv();
9
+ if ('ONLINE' === env) return 'https://miaoda.feishu.cn';
10
+ if ('PRE' === env) return 'https://miaoda.feishu-pre.cn';
5
11
  return 'https://miaoda.feishu-boe.cn';
6
12
  }
7
- export { getPreviewParentOrigin };
13
+ export { getEnv, getPreviewParentOrigin };
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Module Hot Replacement 状态类型定义
3
+ *
4
+ * - idle: The process is waiting for a call to check
5
+ * - check: The process is checking for updates
6
+ * - prepare: The process is getting ready for the update (e.g. downloading the updated module)
7
+ * - ready: The update is prepared and available
8
+ * - dispose: The process is calling the dispose handlers on the modules that will be replaced
9
+ * - apply: The process is calling the accept handlers and re-executing self-accepted modules
10
+ * - abort: An update was aborted, but the system is still in its previous state
11
+ * - fail: An update has thrown an exception and the system's state has been compromised
12
+ */
13
+ type ModuleHotType = 'idle' | 'check' | 'prepare' | 'ready' | 'dispose' | 'apply' | 'abort' | 'fail';
14
+ interface ModuleHotInstance {
15
+ addStatusHandler: (handler: (status: ModuleHotType) => void) => void;
16
+ removeStatusHandler: (handler: (status: ModuleHotType) => void) => void;
17
+ }
18
+ export declare function getModuleHot(): ModuleHotInstance | null;
19
+ /**
20
+ * 创建模块热更成功处理函数
21
+ * 监听模块热更状态,当状态为apply时,调用回调函数并传入true
22
+ * @param callback 热更成功回调函数,参数为是否成功
23
+ */
24
+ export declare function createApplyHandle(callback: (success: boolean, status: ModuleHotType) => void): (status: ModuleHotType) => void;
25
+ export {};
@@ -0,0 +1,22 @@
1
+ function getModuleHot() {
2
+ if ('production' === process.env.NODE_ENV) return null;
3
+ return import.meta.webpackHot || module.hot;
4
+ }
5
+ function createApplyHandle(callback) {
6
+ let hasApply = false;
7
+ return (status)=>{
8
+ if ('fail' === status || 'abort' === status) {
9
+ hasApply = false;
10
+ return callback(false, status);
11
+ }
12
+ if (hasApply) {
13
+ if ('idle' === status) {
14
+ hasApply = false;
15
+ callback(true, status);
16
+ }
17
+ return;
18
+ }
19
+ hasApply = 'apply' === status;
20
+ };
21
+ }
22
+ export { createApplyHandle, getModuleHot };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-toolkit",
3
- "version": "1.1.19",
3
+ "version": "1.1.20-alpha.tea.2",
4
4
  "types": "./lib/index.d.ts",
5
5
  "main": "./lib/index.js",
6
6
  "files": [
@@ -83,8 +83,10 @@
83
83
  "@radix-ui/react-tooltip": "^1.2.8",
84
84
  "@zumer/snapdom": "^1.9.14",
85
85
  "axios": "^1.12.2",
86
+ "blueimp-md5": "2.10.0",
86
87
  "class-variance-authority": "^0.7.1",
87
88
  "clsx": "~2.0.1",
89
+ "crypto-js": "3.1.9-1",
88
90
  "dayjs": "^1.11.13",
89
91
  "echarts": "^6.0.0",
90
92
  "lodash": "^4.17.21",