@lark-apaas/client-toolkit 1.2.68-alpha.20260826072410 → 1.2.68

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.
@@ -1,15 +1,4 @@
1
1
  import React from 'react';
2
- /**
3
- * 是否豆包来源应用。来源由 coding/canvas 构建链编译期把 MIAODA_APP_SOURCE 注入 process.env
4
- * (define 整体替换 `process.env.MIAODA_APP_SOURCE` 这个 key)。但完整版 toolkit 同时被其它
5
- * 全栈构建链(fullstack-vite/rspack-preset)消费——它们不注入该 key,且浏览器没有 process 全局,
6
- * 此时裸读会抛 `ReferenceError: process is not defined`,把整个宿主应用白屏。故 try/catch 兜底:
7
- * 未注入 → 返回 false(非豆包,回落 Safety),绝不让水印判定拖垮宿主应用。
8
- *
9
- * 注意:只能裸引用完整 key `process.env.MIAODA_APP_SOURCE`(define 替换的就是它);不能写
10
- * `typeof process` 之类——那段不会被 define 替换,注入构建里 process 仍可能未定义,反而误判。
11
- */
12
- export declare const isDoubaoSource: () => boolean;
13
2
  /**
14
3
  * 打开「投诉与举报」页:scene/entity_type 固定,entity_id 取当前妙搭 appId,域名按环境选,
15
4
  * params 整体 encode。appId 为空(异常环境)时直接不跳转,避免带空 entity_id 打开举报中心
@@ -47,7 +36,7 @@ export declare const MenuCard: React.FC<{
47
36
  style?: React.CSSProperties;
48
37
  }>;
49
38
  /**
50
- * 豆包水印:仅当应用来源为豆包时,在视口右下角展示收起态药丸(头像 +「豆包AI」)。
39
+ * 豆包水印:在视口右下角展示收起态药丸(头像 +「豆包AI」)。
51
40
  *
52
41
  * 设计稿:Figma 1582:41560(桌面)/ 1582:41777(移动)。
53
42
  * - 药丸 / 卡片本体用代码画(投影走 CSS box-shadow、图标用无滤镜小 SVG),高分屏清晰。
@@ -55,6 +44,8 @@ export declare const MenuCard: React.FC<{
55
44
  * - 移动端 tap 徽标 → 上方弹卡片(投诉与举报 / 不再展示 / 由飞书妙搭提供支持)。
56
45
  * - 「投诉与举报」点击跳飞书风控举报中心(tns,域名随环境);后端链接未就绪时由 REPORT_ENABLED 整体隐藏。
57
46
  * - 不加 NODE_ENV 判断——预览态与运行态都要展示。
47
+ * - show_badge=false(后端 get_published 接口返回)时不展示。
48
+ * - 用户点击关闭后 localStorage 记忆,刷新不再展示。
58
49
  */
59
50
  declare const Watermark: React.FC;
60
51
  export default Watermark;
@@ -1,18 +1,11 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useRef, useState } from "react";
2
+ import { useEffect, useRef, useState } from "react";
3
3
  import { Content, Portal, Root, Trigger } from "@radix-ui/react-popover";
4
- import { DOUBAO_LOGO_SRC, DOUBAO_PILL_MOBILE_PNG } from "./doubao-watermark-asset.js";
4
+ import { DOUBAO_LOGO_SRC } from "./doubao-watermark-asset.js";
5
5
  import { getAppId } from "../../utils/getAppId.js";
6
6
  import { getEnv } from "../../utils/getParentOrigin.js";
7
+ import { getInitialInfo } from "../../utils/getInitialInfo.js";
7
8
  import { useIsMobile } from "../../hooks/index.js";
8
- const DOUBAO_SOURCE = '5';
9
- const isDoubaoSource = ()=>{
10
- try {
11
- return String(process.env.MIAODA_APP_SOURCE) === DOUBAO_SOURCE;
12
- } catch {
13
- return false;
14
- }
15
- };
16
9
  const REPORT_ENABLED = true;
17
10
  const BRAND_TEXT = '豆包 AI 生成';
18
11
  const POWERED_BY_TEXT = '由飞书妙搭提供支持';
@@ -265,27 +258,11 @@ const MobileWatermark = ({ onDontShow })=>{
265
258
  position: 'fixed',
266
259
  right: 12,
267
260
  bottom: 12,
268
- width: 122,
269
- height: 30,
270
261
  zIndex: 9999,
271
262
  cursor: 'pointer'
272
263
  },
273
- children: /*#__PURE__*/ jsx("img", {
274
- src: DOUBAO_PILL_MOBILE_PNG,
275
- width: 166,
276
- height: 94,
277
- alt: "豆包 AI 生成",
278
- style: {
279
- position: 'absolute',
280
- right: -12,
281
- bottom: -40,
282
- width: 166,
283
- height: 94,
284
- maxWidth: 'none',
285
- maxHeight: 'none',
286
- display: 'block',
287
- pointerEvents: 'none'
288
- }
264
+ children: /*#__PURE__*/ jsx(Pill, {
265
+ variant: "mobile"
289
266
  })
290
267
  })
291
268
  }),
@@ -309,14 +286,41 @@ const MobileWatermark = ({ onDontShow })=>{
309
286
  });
310
287
  };
311
288
  const Watermark_Watermark = ()=>{
312
- const [closed, setClosed] = useState(false);
289
+ const appId = getAppId();
290
+ const storageKey = `miaoda-creatByMiaodo-has-closed-${appId}`;
291
+ const [closed, setClosed] = useState(()=>{
292
+ try {
293
+ return !!window.localStorage?.getItem(storageKey);
294
+ } catch {
295
+ return false;
296
+ }
297
+ });
298
+ const [showBadge, setShowBadge] = useState(true);
299
+ const [loaded, setLoaded] = useState(false);
313
300
  const [open, setOpen] = useState(false);
314
301
  const timer = useRef(null);
315
302
  const isMobile = useIsMobile();
316
- if (!isDoubaoSource()) return null;
303
+ useEffect(()=>{
304
+ getInitialInfo().then((info)=>{
305
+ const badge = info?.app_info?.show_badge;
306
+ setShowBadge(false !== badge);
307
+ }).catch(()=>{
308
+ setShowBadge(true);
309
+ }).finally(()=>{
310
+ setLoaded(true);
311
+ });
312
+ }, []);
313
+ if (!loaded) return null;
314
+ if (!showBadge) return null;
317
315
  if (closed) return null;
316
+ const handleClose = ()=>{
317
+ setClosed(true);
318
+ try {
319
+ window.localStorage?.setItem(storageKey, 'true');
320
+ } catch {}
321
+ };
318
322
  if (isMobile) return /*#__PURE__*/ jsx(MobileWatermark, {
319
- onDontShow: ()=>setClosed(true)
323
+ onDontShow: handleClose
320
324
  });
321
325
  const enter = ()=>{
322
326
  if (timer.current) clearTimeout(timer.current);
@@ -354,11 +358,11 @@ const Watermark_Watermark = ()=>{
354
358
  }),
355
359
  /*#__PURE__*/ jsx(Pill, {
356
360
  variant: "desktop",
357
- onClose: ()=>setClosed(true),
361
+ onClose: handleClose,
358
362
  showClose: open
359
363
  })
360
364
  ]
361
365
  });
362
366
  };
363
367
  const Watermark = Watermark_Watermark;
364
- export { Avatar, CloseIcon, FeedbackIcon, MenuCard, MenuRow, Pill, Watermark as default, isDoubaoSource, openDoubaoReport };
368
+ export { Avatar, CloseIcon, FeedbackIcon, MenuCard, MenuRow, Pill, Watermark as default, openDoubaoReport };
@@ -2,7 +2,7 @@ import { afterEach, describe, expect, it, vi } from "vitest";
2
2
  import react from "react";
3
3
  import { renderToStaticMarkup } from "react-dom/server";
4
4
  import Watermark, { Avatar, CloseIcon, FeedbackIcon, MenuCard, Pill, openDoubaoReport } from "../Watermark.js";
5
- import { DOUBAO_LOGO_SRC, DOUBAO_PILL_MOBILE_PNG } from "../doubao-watermark-asset.js";
5
+ import { DOUBAO_LOGO_SRC } from "../doubao-watermark-asset.js";
6
6
  const html = ()=>renderToStaticMarkup(/*#__PURE__*/ react.createElement(Watermark));
7
7
  const setViewportWidth = (w)=>Object.defineProperty(window, 'innerWidth', {
8
8
  value: w,
@@ -15,9 +15,8 @@ afterEach(()=>{
15
15
  delete window.appId;
16
16
  setViewportWidth(1024);
17
17
  });
18
- describe('Watermark(豆包来源水印)', ()=>{
19
- it('豆包来源(MIAODA_APP_SOURCE=5)时展示收起态药丸(头像 + 豆包 AI 生成)', ()=>{
20
- vi.stubEnv('MIAODA_APP_SOURCE', '5');
18
+ describe('Watermark(豆包水印·统一改造后)', ()=>{
19
+ it('始终渲染收起态药丸(头像 + 豆包 AI 生成),不再检查来源', ()=>{
21
20
  const out = html();
22
21
  expect(out).toContain('data-custom-element="doubao-watermark"');
23
22
  expect(out).toContain('豆包 AI 生成');
@@ -26,22 +25,14 @@ describe('Watermark(豆包来源水印)', ()=>{
26
25
  expect(out).not.toContain('投诉与举报');
27
26
  expect(out).not.toContain('由飞书妙搭提供支持');
28
27
  });
29
- it('移动端视口(<768)时展示移动端药丸(doubao-watermark-mobile)而非桌面药丸', ()=>{
30
- vi.stubEnv('MIAODA_APP_SOURCE', '5');
28
+ it('移动端视口(<768)时展示移动端药丸', ()=>{
31
29
  setViewportWidth(375);
32
30
  const out = html();
33
31
  expect(out).toContain('data-custom-element="doubao-watermark-mobile"');
34
- expect(out).toContain(DOUBAO_PILL_MOBILE_PNG);
32
+ expect(out).toContain(DOUBAO_LOGO_SRC);
35
33
  expect(out).toContain('豆包 AI 生成');
36
34
  expect(out).not.toContain('aria-label="关闭"');
37
35
  });
38
- it('非豆包来源(其它 enum)时不渲染', ()=>{
39
- vi.stubEnv('MIAODA_APP_SOURCE', '3');
40
- expect(html()).toBe('');
41
- });
42
- it('来源未注入时不渲染(String(undefined) !== "5")', ()=>{
43
- expect(html()).toBe('');
44
- });
45
36
  describe('展开态展示组件(SSR 覆盖)', ()=>{
46
37
  it('Pill 桌面态:头像 + 豆包 AI 生成;关闭叉仅 showClose 时显示', ()=>{
47
38
  const out = renderToStaticMarkup(/*#__PURE__*/ react.createElement(Pill, {
@@ -97,7 +88,7 @@ describe('Watermark(豆包来源水印)', ()=>{
97
88
  }))).toContain(DOUBAO_LOGO_SRC);
98
89
  });
99
90
  });
100
- describe('openDoubaoReport(举报跳转,后端就绪后启用)', ()=>{
91
+ describe('openDoubaoReport(举报跳转)', ()=>{
101
92
  it('按当前环境(getEnv)拼出飞书风控举报中心(tns) URL 并以新窗口打开', ()=>{
102
93
  const openSpy = vi.spyOn(window, 'open').mockReturnValue(null);
103
94
  window.appId = 'app_abc';
@@ -111,7 +102,7 @@ describe('Watermark(豆包来源水印)', ()=>{
111
102
  expect(target).toBe('_blank');
112
103
  expect(features).toBe('noopener,noreferrer');
113
104
  });
114
- it('无 appId 时不跳转(避免带空 entity_id 打开举报中心)', ()=>{
105
+ it('无 appId 时不跳转', ()=>{
115
106
  const openSpy = vi.spyOn(window, 'open').mockReturnValue(null);
116
107
  globalThis.ENVIRONMENT = 'online';
117
108
  openDoubaoReport();
@@ -0,0 +1,36 @@
1
+ import { afterEach, describe, expect, it, vi } from "vitest";
2
+ describe('isStandaloneBuild', ()=>{
3
+ afterEach(()=>{
4
+ delete process.env.MIAODA_BUILD_TARGET;
5
+ vi.resetModules();
6
+ });
7
+ async function load() {
8
+ vi.resetModules();
9
+ return (await import("../standalone.js")).isStandaloneBuild;
10
+ }
11
+ it('MIAODA_BUILD_TARGET=standalone → true', async ()=>{
12
+ process.env.MIAODA_BUILD_TARGET = 'standalone';
13
+ expect((await load())()).toBe(true);
14
+ });
15
+ it('未设置 → false(平台正常构建,徽标照常显示)', async ()=>{
16
+ expect((await load())()).toBe(false);
17
+ });
18
+ it('其它取值 → false(--mode 将来扩展新形态时不误判为 standalone)', async ()=>{
19
+ process.env.MIAODA_BUILD_TARGET = 'something-else';
20
+ expect((await load())()).toBe(false);
21
+ });
22
+ it('精确匹配,不做前缀/包含判断', async ()=>{
23
+ process.env.MIAODA_BUILD_TARGET = 'standalone-v2';
24
+ expect((await load())()).toBe(false);
25
+ });
26
+ it('没有 process 全局时返回 false 而不是抛错', async ()=>{
27
+ const isStandaloneBuild = await load();
28
+ const original = globalThis.process;
29
+ delete globalThis.process;
30
+ try {
31
+ expect(isStandaloneBuild()).toBe(false);
32
+ } finally{
33
+ globalThis.process = original;
34
+ }
35
+ });
36
+ });
@@ -1,2 +1 @@
1
- export declare const DOUBAO_LOGO_SRC = "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/miaoda-ui/setting_voice.svg";
2
- export declare const DOUBAO_PILL_MOBILE_PNG = "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/miaoda-ui/Frame%202147223991%20(3).png";
1
+ export declare const DOUBAO_LOGO_SRC = "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/miaoda-ui/doubao.svg";
@@ -1,4 +1,3 @@
1
1
  const CDN = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/miaoda-ui';
2
- const DOUBAO_LOGO_SRC = `${CDN}/setting_voice.svg`;
3
- const DOUBAO_PILL_MOBILE_PNG = `${CDN}/Frame%202147223991%20(3).png`;
4
- export { DOUBAO_LOGO_SRC, DOUBAO_PILL_MOBILE_PNG };
2
+ const DOUBAO_LOGO_SRC = `${CDN}/doubao.svg`;
3
+ export { DOUBAO_LOGO_SRC };
@@ -1,5 +1,5 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
- import react, { Suspense, useEffect, useMemo, useState } from "react";
2
+ import { useEffect, useMemo, useState } from "react";
3
3
  import { ConfigProvider } from "antd";
4
4
  import { MiaodaInspector } from "@lark-apaas/miaoda-inspector";
5
5
  import zh_CN from "antd/locale/zh_CN";
@@ -11,13 +11,13 @@ import { SafetyErrorBoundary } from "./safety-error-boundary.js";
11
11
  import { useAppInfo } from "../../hooks/index.js";
12
12
  import { TrackKey } from "../../types/tea.js";
13
13
  import { slardar } from "@lark-apaas/internal-slardar";
14
- import Watermark, { isDoubaoSource } from "./Watermark.js";
14
+ import Watermark from "./Watermark.js";
15
+ import { isStandaloneBuild } from "./standalone.js";
15
16
  import { getAppId } from "../../utils/getAppId.js";
16
17
  import { isNewPathEnabled } from "../../utils/apiPath.js";
17
18
  import QueryProvider from "../QueryProvider/index.js";
18
19
  import { AuthProvider } from "@lark-apaas/auth-sdk";
19
20
  import "../../runtime/index.js";
20
- const Safety = /*#__PURE__*/ react.lazy(()=>import("./safety.js"));
21
21
  const isMiaodaPreview = window.IS_MIAODA_PREVIEW;
22
22
  const readAllCssVarColors = ()=>{
23
23
  try {
@@ -200,11 +200,8 @@ const AppContainer_AppContainer = (props)=>{
200
200
  };
201
201
  return /*#__PURE__*/ jsxs(Fragment, {
202
202
  children: [
203
- /*#__PURE__*/ jsx(SafetyErrorBoundary, {
204
- children: isDoubaoSource() ? /*#__PURE__*/ jsx(Watermark, {}) : /*#__PURE__*/ jsx(Suspense, {
205
- fallback: null,
206
- children: /*#__PURE__*/ jsx(Safety, {})
207
- })
203
+ !isStandaloneBuild() && /*#__PURE__*/ jsx(SafetyErrorBoundary, {
204
+ children: /*#__PURE__*/ jsx(Watermark, {})
208
205
  }),
209
206
  /*#__PURE__*/ jsx(QueryProvider, {
210
207
  children: /*#__PURE__*/ jsx(ConfigProvider, {
@@ -0,0 +1,17 @@
1
+ /**
2
+ * 是否为 standalone 导出构建(`miaoda app pack --mode standalone`)。
3
+ *
4
+ * standalone 产物脱离妙搭平台、以 `file://` 离线打开,平台徽标(Safety「由妙搭搭建」/
5
+ * 豆包水印)在这里既无意义也无从校验 —— 它们的显隐判据全是 **fail-open** 的:
6
+ * `showBadge` 拿不到平台数据就默认 true、接口失败也 catch 成 true,于是离线产物里
7
+ * 徽标必然出现,还附带两个必然失败的 `tenant_info` / `get_published` 请求。
8
+ * 所以 gate 在挂载处,让整棵子树不渲染,连 effect 里的请求一起省掉。
9
+ *
10
+ * `MIAODA_BUILD_TARGET` 由构建 preset 在 standalone 模式下 define 注入。
11
+ *
12
+ * **必须 try/catch**:客户端 bundle 里没有 `process` 全局,所有 `process.env.X` 全靠
13
+ * 构建期 define 做字符串替换。若应用升级了本 SDK 却仍用**旧版 preset**(不认识这个 key),
14
+ * 该表达式不会被替换,运行时直接 `ReferenceError: process is not defined` 把整个应用打挂。
15
+ * 防御口径:try/catch 兜底旧 preset 不替换该 key 的场景。
16
+ */
17
+ export declare const isStandaloneBuild: () => boolean;
@@ -0,0 +1,8 @@
1
+ const isStandaloneBuild = ()=>{
2
+ try {
3
+ return 'standalone' === process.env.MIAODA_BUILD_TARGET;
4
+ } catch {
5
+ return false;
6
+ }
7
+ };
8
+ export { isStandaloneBuild };
@@ -1,40 +1,4 @@
1
1
  const messages_messages = {
2
- 'safety.badge.label': {
3
- zh: '妙搭',
4
- en: 'Spark'
5
- },
6
- 'safety.badge.builtWith': {
7
- zh: '由妙搭搭建',
8
- en: 'Built with Spark'
9
- },
10
- 'safety.ai.disclaimer': {
11
- zh: '包含 AI 生成内容,请注意甄别',
12
- en: 'AI-generated content. Use with care.'
13
- },
14
- 'safety.tenant.operated': {
15
- zh: '{name}运营',
16
- en: 'Operated by {name}'
17
- },
18
- 'safety.button.dontShowAgain': {
19
- zh: '不再展示',
20
- en: "Don't show again"
21
- },
22
- 'safety.button.learnMore': {
23
- zh: '了解更多',
24
- en: 'Learn more'
25
- },
26
- 'safety.report': {
27
- zh: '投诉与举报',
28
- en: 'Report'
29
- },
30
- 'safety.cover.pc': {
31
- zh: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/logo/miaodacover.png',
32
- en: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/logo/miaodacover-weben.png'
33
- },
34
- 'safety.cover.mobile': {
35
- zh: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/logo/miaodacover-mobile.png',
36
- en: 'https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/logo/miaodacover-mobileen.png'
37
- },
38
2
  'index.rateLimitError': {
39
3
  zh: '应用额度已耗尽,请联系应用开发者',
40
4
  en: 'Application quota exhausted, please contact the app developer'
@@ -3,6 +3,9 @@ import "../utils/utils.js";
3
3
  import { mappingText } from "./source-map-mappings-wasm.js";
4
4
  import stacktrace_js from "stacktrace-js";
5
5
  import { batchLogInfo } from "./batch-logger.js";
6
+ function getBrowserTransportLevel(level) {
7
+ return 'success' === level ? 'info' : level;
8
+ }
6
9
  function hexToBuffer(hexString) {
7
10
  const hex = hexString.replace(/\s/g, '').toUpperCase();
8
11
  if (!/^[0-9A-F]+$/.test(hex)) throw new Error('Invalid hex string');
@@ -24,9 +27,6 @@ const mapStacktrace = (stacktrace)=>stacktrace.map((frame)=>({
24
27
  lineNumber: frame.lineNumber || 0,
25
28
  columnNumber: frame.columnNumber || 0
26
29
  }));
27
- const getStackTraceOptions = ()=>'development' === process.env.NODE_ENV && 'vite' === process.env.BUILD_TOOL ? {
28
- offline: true
29
- } : void 0;
30
30
  async function sendSelectedLog(logWithoutID) {
31
31
  try {
32
32
  const log = {
@@ -41,7 +41,7 @@ async function sendSelectedLog(logWithoutID) {
41
41
  stack: error.stack
42
42
  };
43
43
  if (!log.meta.stacktrace) try {
44
- const stacktrace = await stacktrace_js.fromError(error, getStackTraceOptions());
44
+ const stacktrace = await stacktrace_js.fromError(error);
45
45
  log.meta.stacktrace = mapStacktrace(stacktrace);
46
46
  } catch (e) {
47
47
  if (window.parent !== window) try {
@@ -95,7 +95,7 @@ async function sendSelectedLog(logWithoutID) {
95
95
  log.meta.duplicateOfId = lastLogInfo.id;
96
96
  const updatedLogJSON = JSON.stringify(log, errorReplacer);
97
97
  try {
98
- batchLogInfo('info', updatedLogJSON);
98
+ batchLogInfo(getBrowserTransportLevel(log.level), updatedLogJSON);
99
99
  } catch (e) {}
100
100
  if (window.parent !== window) try {
101
101
  window.parent.postMessage({
@@ -111,7 +111,7 @@ async function sendSelectedLog(logWithoutID) {
111
111
  count: 1
112
112
  };
113
113
  try {
114
- batchLogInfo('info', logJSON);
114
+ batchLogInfo(getBrowserTransportLevel(log.level), logJSON);
115
115
  } catch (e) {}
116
116
  if (window.parent !== window) try {
117
117
  window.parent.postMessage({
@@ -122,7 +122,7 @@ async function sendSelectedLog(logWithoutID) {
122
122
  } catch (e) {}
123
123
  }
124
124
  async function getStacktrace() {
125
- const stacktrace = await stacktrace_js.get(getStackTraceOptions());
125
+ const stacktrace = await stacktrace_js.get();
126
126
  const frames = mapStacktrace(stacktrace);
127
127
  return frames;
128
128
  }
@@ -9,6 +9,8 @@ interface AppRuntimePublished {
9
9
  js_urls?: string[];
10
10
  app_avatar?: string;
11
11
  app_description?: string;
12
+ /** 是否展示豆包水印徽标;后端缺省视为 true */
13
+ show_badge?: boolean;
12
14
  }
13
15
  interface BucketConfig {
14
16
  default_bucket_id?: string;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-toolkit",
3
- "version": "1.2.68-alpha.20260826072410",
3
+ "version": "1.2.68",
4
4
  "types": "./lib/index.d.ts",
5
5
  "main": "./lib/index.js",
6
6
  "files": [
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- declare const Component: () => React.JSX.Element;
3
- export default Component;
@@ -1,337 +0,0 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
2
- import { useEffect, useRef, useState } from "react";
3
- import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover.js";
4
- import { getAppId } from "../../utils/getAppId.js";
5
- import { getEnv } from "../../utils/getParentOrigin.js";
6
- import { getCsrfToken } from "../../utils/getCsrfToken.js";
7
- import { isNewPathEnabled } from "../../utils/apiPath.js";
8
- import { useIsMobile } from "../../hooks/index.js";
9
- import { X } from "lucide-react";
10
- import { Sheet, SheetContent, SheetTrigger } from "../ui/drawer.js";
11
- import { t } from "../../locales/index.js";
12
- const ICON_FEEDBACK_URL = 'https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/miaoda-ui/icon_feedback_outlined.png';
13
- const REPORT_DOMAIN = {
14
- BOE: 'tns.feishu-boe.cn',
15
- PRE: 'tns.feishu-pre.cn',
16
- ONLINE: 'tns.feishu.cn'
17
- };
18
- const openReport = ()=>{
19
- const appId = getAppId();
20
- if (!appId) return;
21
- const params = JSON.stringify({
22
- scene: 'miaoda_app_report',
23
- entity_id: appId,
24
- entity_type: 'miaoda_app',
25
- extra: ''
26
- });
27
- const domain = REPORT_DOMAIN[getEnv()] ?? REPORT_DOMAIN.ONLINE;
28
- const url = `https://${domain}/cust/lark_report/?type=common&params=${encodeURIComponent(params)}&lang=zh-CN`;
29
- window.open(url, '_blank', 'noopener,noreferrer');
30
- };
31
- const Component = ()=>{
32
- const HasClosedKey = `miaoda-creatByMiaoda-has-closed-${getAppId()}`;
33
- const [visible, setVisible] = useState(!window.localStorage?.getItem(HasClosedKey));
34
- const [open, setOpen] = useState(false);
35
- const isMobile = useIsMobile();
36
- const timeoutRef = useRef(null);
37
- const platformData = window.__platform_data__ || window.__platform__ || {};
38
- const appId = getAppId() || platformData.appId;
39
- const showBadge = false !== platformData.showBadge;
40
- const [tenantName, setTenantName] = useState('');
41
- const [isInternetVisible, setIsInternetVisible] = useState(false);
42
- useEffect(()=>{
43
- if (!showBadge || !visible) return;
44
- const csrfToken = getCsrfToken() ?? '';
45
- const csrfHeaders = {
46
- 'X-Suda-Csrf-Token': csrfToken
47
- };
48
- const tenantInfoUrl = isNewPathEnabled() ? `/app/${appId}/__runtime__/api/v1/studio/tenant_info` : `/spark/b/${appId}/tenant_info`;
49
- fetch(tenantInfoUrl, {
50
- headers: csrfHeaders
51
- }).then((res)=>res.json()).then((data)=>{
52
- if (data?.status_code === '0' || data?.code === 0) {
53
- setTenantName(data?.data?.tenant_info?.name || '');
54
- setIsInternetVisible(data?.data?.is_internet_visible || false);
55
- }
56
- }).catch((e)=>{
57
- console.warn('Failed to fetch tenant info:', e);
58
- });
59
- }, [
60
- appId,
61
- showBadge,
62
- visible
63
- ]);
64
- useEffect(()=>{
65
- if (isMobile) {
66
- const link = document.createElement('link');
67
- link.rel = 'preload';
68
- link.as = 'image';
69
- link.href = t('safety.cover.mobile');
70
- document.head.appendChild(link);
71
- }
72
- }, [
73
- isMobile
74
- ]);
75
- if ('production' !== process.env.NODE_ENV) return null;
76
- if (!showBadge) return null;
77
- if (!visible) return null;
78
- if (isMobile) return /*#__PURE__*/ jsxs(Sheet, {
79
- open: open,
80
- onOpenChange: setOpen,
81
- children: [
82
- /*#__PURE__*/ jsx(SheetTrigger, {
83
- asChild: true,
84
- children: /*#__PURE__*/ jsxs("div", {
85
- 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-[6px] text-[#ebebeb)] font-['PingFang_SC'] text-xs leading-[20px] tracking-[0px] z-[10000000]",
86
- onClick: ()=>{
87
- setOpen(true);
88
- },
89
- children: [
90
- /*#__PURE__*/ jsx("img", {
91
- src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/logo/miaodalogo.svg",
92
- className: "shrink-0 w-[16px] h-[16px]"
93
- }),
94
- /*#__PURE__*/ jsx("p", {
95
- className: "shrink-0 min-w-[28px] m-0! text-[#EBEBEB]",
96
- children: t('safety.badge.label')
97
- })
98
- ]
99
- })
100
- }),
101
- /*#__PURE__*/ jsx(SheetContent, {
102
- side: "bottom",
103
- className: "z-[10000001] border-none bg-transparent outline-0!",
104
- children: /*#__PURE__*/ jsxs("div", {
105
- className: "flex flex-col bg-white overflow-hidden rounded-t-[16px] relative",
106
- children: [
107
- /*#__PURE__*/ jsx(X, {
108
- className: "absolute top-[8px] left-[16px] size-[24px] text-[#2B2F36]",
109
- onClick: ()=>setOpen(false)
110
- }),
111
- /*#__PURE__*/ jsx("img", {
112
- src: t('safety.cover.mobile'),
113
- alt: "",
114
- className: "w-full h-full",
115
- onClick: ()=>{
116
- window.open('https://miaoda.feishu.cn/landing', '_blank');
117
- }
118
- }),
119
- /*#__PURE__*/ jsxs("div", {
120
- 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]",
121
- children: [
122
- /*#__PURE__*/ jsxs("div", {
123
- className: "self-stretch shrink-0 flex flex-col items-start gap-y-[4px]",
124
- children: [
125
- isInternetVisible && /*#__PURE__*/ jsxs("div", {
126
- className: "self-stretch shrink-0 flex items-center gap-x-[6px]",
127
- children: [
128
- /*#__PURE__*/ jsx("img", {
129
- src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/icon/icon_company_outlined.svg",
130
- className: "shrink-0 w-[14px] h-[14px]"
131
- }),
132
- /*#__PURE__*/ jsx("p", {
133
- className: "shrink-0 min-w-[96px] m-0! text-[#646A73] text-sm",
134
- children: t('safety.tenant.operated', {
135
- name: tenantName
136
- })
137
- })
138
- ]
139
- }),
140
- /*#__PURE__*/ jsxs("div", {
141
- className: "self-stretch shrink-0 flex items-center gap-x-[6px]",
142
- children: [
143
- /*#__PURE__*/ jsx("img", {
144
- src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/icon/icon_efficiency-ai_outlined.svg",
145
- className: "shrink-0 w-[14px] h-[14px]"
146
- }),
147
- /*#__PURE__*/ jsx("p", {
148
- className: "shrink-0 min-w-[163px] m-0! text-[#646A73] text-sm",
149
- children: t('safety.ai.disclaimer')
150
- })
151
- ]
152
- }),
153
- /*#__PURE__*/ jsxs("div", {
154
- className: "self-stretch shrink-0 flex items-center gap-x-[6px] cursor-pointer",
155
- "data-custom-element": "safety-report",
156
- onClick: openReport,
157
- children: [
158
- /*#__PURE__*/ jsx("img", {
159
- src: ICON_FEEDBACK_URL,
160
- className: "shrink-0 w-[14px] h-[14px]"
161
- }),
162
- /*#__PURE__*/ jsx("p", {
163
- className: "shrink-0 m-0! text-[#646A73] text-sm underline underline-offset-2",
164
- children: t('safety.report')
165
- })
166
- ]
167
- })
168
- ]
169
- }),
170
- /*#__PURE__*/ jsxs("div", {
171
- className: "self-stretch shrink-0 flex items-start gap-x-[16px]",
172
- children: [
173
- /*#__PURE__*/ jsx("div", {
174
- 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]",
175
- onClick: (e)=>{
176
- e.stopPropagation();
177
- e.preventDefault();
178
- setOpen(false);
179
- setTimeout(()=>setVisible(false), 200);
180
- window.localStorage?.setItem(HasClosedKey, 'true');
181
- },
182
- children: t('safety.button.dontShowAgain')
183
- }),
184
- /*#__PURE__*/ jsx("div", {
185
- 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]",
186
- onClick: ()=>{
187
- window.open('https://miaoda.feishu.cn/landing', '_blank');
188
- },
189
- children: t('safety.button.learnMore')
190
- })
191
- ]
192
- })
193
- ]
194
- })
195
- ]
196
- })
197
- })
198
- ]
199
- });
200
- return /*#__PURE__*/ jsxs(Popover, {
201
- open: open,
202
- onOpenChange: setOpen,
203
- children: [
204
- /*#__PURE__*/ jsx(PopoverTrigger, {
205
- asChild: true,
206
- children: /*#__PURE__*/ jsxs("div", {
207
- 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",
208
- onMouseEnter: ()=>{
209
- clearTimeout(timeoutRef.current);
210
- setOpen(true);
211
- },
212
- onMouseLeave: ()=>{
213
- timeoutRef.current = setTimeout(()=>setOpen(false), 100);
214
- },
215
- children: [
216
- /*#__PURE__*/ jsx("img", {
217
- src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/logo/miaodalogo.svg",
218
- className: "shrink-0 w-[16px] h-[16px]"
219
- }),
220
- /*#__PURE__*/ jsx("p", {
221
- className: "shrink-0 min-w-[60px] m-0! text-[#EBEBEB]",
222
- children: t('safety.badge.builtWith')
223
- })
224
- ]
225
- })
226
- }),
227
- /*#__PURE__*/ jsx(PopoverContent, {
228
- className: "overflow-hidden p-0 m-0 border-0 rounded-[12px]! w-[286px]",
229
- style: {
230
- boxShadow: '0 6px 12px 0 #41444a0a, 0 8px 24px 0 #41444a0a'
231
- },
232
- side: "top",
233
- align: "end",
234
- sideOffset: 8,
235
- onMouseEnter: ()=>{
236
- clearTimeout(timeoutRef.current);
237
- setOpen(true);
238
- },
239
- onMouseLeave: ()=>{
240
- timeoutRef.current = setTimeout(()=>setOpen(false), 100);
241
- },
242
- children: /*#__PURE__*/ jsxs("div", {
243
- className: "flex flex-col bg-[#1A1A1A]",
244
- children: [
245
- /*#__PURE__*/ jsx("img", {
246
- src: t('safety.cover.pc'),
247
- alt: "",
248
- className: "w-[286px] h-[128px] cursor-pointer",
249
- onClick: ()=>{
250
- window.open('https://miaoda.feishu.cn/landing', '_blank');
251
- }
252
- }),
253
- /*#__PURE__*/ jsxs("div", {
254
- 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]",
255
- children: [
256
- /*#__PURE__*/ jsxs("div", {
257
- className: "self-stretch shrink-0 flex flex-col items-start gap-y-[4px]",
258
- children: [
259
- isInternetVisible && /*#__PURE__*/ jsxs("div", {
260
- className: "self-stretch shrink-0 flex items-center gap-x-[6px]",
261
- children: [
262
- /*#__PURE__*/ jsx("img", {
263
- src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/icon/icon_company_outlined.svg",
264
- className: "shrink-0 w-[12px] h-[12px]"
265
- }),
266
- /*#__PURE__*/ jsx("p", {
267
- className: "shrink-0 min-w-[96px] m-0! text-[#a6a6a6]",
268
- children: t('safety.tenant.operated', {
269
- name: tenantName
270
- })
271
- })
272
- ]
273
- }),
274
- /*#__PURE__*/ jsxs("div", {
275
- className: "self-stretch shrink-0 flex items-center gap-x-[6px]",
276
- children: [
277
- /*#__PURE__*/ jsx("img", {
278
- src: "https://lf3-static.bytednsdoc.com/obj/eden-cn/LMfspH/ljhwZthlaukjlkulzlp/icon/icon_efficiency-ai_outlined.svg",
279
- className: "shrink-0 w-[12px] h-[12px]"
280
- }),
281
- /*#__PURE__*/ jsx("p", {
282
- className: "shrink-0 min-w-[163px] m-0! text-[#a6a6a6]",
283
- children: t('safety.ai.disclaimer')
284
- })
285
- ]
286
- }),
287
- /*#__PURE__*/ jsxs("div", {
288
- className: "self-stretch shrink-0 flex items-center gap-x-[6px] cursor-pointer",
289
- "data-custom-element": "safety-report",
290
- onClick: openReport,
291
- children: [
292
- /*#__PURE__*/ jsx("img", {
293
- src: ICON_FEEDBACK_URL,
294
- className: "shrink-0 w-[12px] h-[12px]"
295
- }),
296
- /*#__PURE__*/ jsx("p", {
297
- className: "shrink-0 m-0! text-[#a6a6a6] underline underline-offset-2",
298
- children: t('safety.report')
299
- })
300
- ]
301
- })
302
- ]
303
- }),
304
- /*#__PURE__*/ jsxs("div", {
305
- className: "w-full self-stretch shrink-0 flex items-start gap-x-[8px]",
306
- children: [
307
- /*#__PURE__*/ jsx("div", {
308
- className: "flex-1 flex rounded-[8px] 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]",
309
- "data-custom-element": "safety-close",
310
- onClick: (e)=>{
311
- e.stopPropagation();
312
- e.preventDefault();
313
- setVisible(false);
314
- window.localStorage?.setItem(HasClosedKey, 'true');
315
- },
316
- children: t('safety.button.dontShowAgain')
317
- }),
318
- /*#__PURE__*/ jsx("div", {
319
- className: "flex-1 flex rounded-[8px] 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]",
320
- "data-custom-element": "safety-more",
321
- onClick: ()=>{
322
- window.open('https://miaoda.feishu.cn/landing', '_blank');
323
- },
324
- children: t('safety.button.learnMore')
325
- })
326
- ]
327
- })
328
- ]
329
- })
330
- ]
331
- })
332
- })
333
- ]
334
- });
335
- };
336
- const safety = Component;
337
- export { safety as default };