@lark-apaas/client-toolkit 1.2.17-alpha.1 → 1.2.17-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (105) hide show
  1. package/lib/antd-table.d.ts +2 -2
  2. package/lib/apis/aily-chat.d.ts +2 -0
  3. package/lib/apis/aily-chat.js +2 -0
  4. package/lib/apis/components/ActiveLink.d.ts +26 -0
  5. package/lib/apis/components/ActiveLink.js +66 -0
  6. package/lib/apis/hooks/useScrollReveal.d.ts +1 -0
  7. package/lib/apis/hooks/useScrollReveal.js +1 -0
  8. package/lib/apis/utils/getEnv.d.ts +1 -0
  9. package/lib/apis/utils/getEnv.js +2 -0
  10. package/lib/apis/utils/resolveAppUrl.d.ts +1 -0
  11. package/lib/apis/utils/resolveAppUrl.js +2 -0
  12. package/lib/apis/utils/scopedStorage.d.ts +1 -0
  13. package/lib/apis/utils/scopedStorage.js +2 -0
  14. package/lib/auth.d.ts +1 -0
  15. package/lib/auth.js +2 -0
  16. package/lib/components/AppContainer/IframeBridge.d.ts +0 -1
  17. package/lib/components/AppContainer/IframeBridge.js +1 -20
  18. package/lib/components/AppContainer/RoutePatternTracker.d.ts +5 -0
  19. package/lib/components/AppContainer/RoutePatternTracker.js +13 -0
  20. package/lib/components/AppContainer/api-proxy/core.js +2 -1
  21. package/lib/components/AppContainer/index.d.ts +9 -2
  22. package/lib/components/AppContainer/index.js +23 -71
  23. package/lib/components/AppContainer/safety.js +5 -2
  24. package/lib/components/AppContainer/utils/childApi.js +1 -0
  25. package/lib/components/AppContainer/utils/getLarkUser.js +4 -2
  26. package/lib/components/AppContainer/utils/observable.js +7 -1
  27. package/lib/components/AppContainer/utils/tea.js +1 -1
  28. package/lib/components/ErrorRender/index.js +5 -11
  29. package/lib/components/User/UserSelect.js +1 -13
  30. package/lib/components/theme/index.d.ts +0 -1
  31. package/lib/components/theme/index.js +0 -1
  32. package/lib/components/theme/util.d.ts +0 -2
  33. package/lib/components/theme/util.js +0 -108
  34. package/lib/components/ui/toast.d.ts +2 -0
  35. package/lib/components/ui/toast.js +53 -0
  36. package/lib/hooks/index.d.ts +1 -0
  37. package/lib/hooks/index.js +1 -0
  38. package/lib/hooks/useCurrentUserProfile.js +22 -29
  39. package/lib/hooks/useLogout.js +2 -17
  40. package/lib/hooks/useScrollReveal.d.ts +61 -0
  41. package/lib/hooks/useScrollReveal.js +37 -0
  42. package/lib/index.js +12 -1
  43. package/lib/integrations/dataloom.d.ts +3 -1
  44. package/lib/integrations/dataloom.js +18 -10
  45. package/lib/integrations/services/DepartmentService.js +3 -2
  46. package/lib/integrations/services/UserProfileService.js +3 -2
  47. package/lib/integrations/services/UserService.js +4 -3
  48. package/lib/integrations/services/types.d.ts +1 -0
  49. package/lib/logger/batch-logger.js +3 -2
  50. package/lib/logger/intercept-global-error.js +34 -25
  51. package/lib/logger/log-types.d.ts +4 -4
  52. package/lib/logger/log-types.js +1 -1
  53. package/lib/logger/selected-logs.js +1 -2
  54. package/lib/runtime/axios.d.ts +5 -0
  55. package/lib/runtime/axios.js +2 -0
  56. package/lib/runtime/dayjs.d.ts +5 -0
  57. package/lib/runtime/dayjs.js +2 -0
  58. package/lib/runtime/iframe-bridge.d.ts +11 -0
  59. package/lib/runtime/iframe-bridge.js +29 -0
  60. package/lib/runtime/index.d.ts +24 -0
  61. package/lib/runtime/index.js +17 -0
  62. package/lib/runtime/observable.d.ts +5 -0
  63. package/lib/runtime/observable.js +2 -0
  64. package/lib/runtime/react-devtools-hook.d.ts +19 -0
  65. package/lib/runtime/react-devtools-hook.js +20 -0
  66. package/lib/runtime/server-log.d.ts +5 -0
  67. package/lib/runtime/server-log.js +41 -0
  68. package/lib/runtime/styles.d.ts +5 -0
  69. package/lib/runtime/styles.js +1 -0
  70. package/lib/theme-layer.css +2 -1
  71. package/lib/utils/apiPath.d.ts +5 -0
  72. package/lib/utils/apiPath.js +5 -0
  73. package/lib/utils/axiosConfig.js +70 -5
  74. package/lib/utils/getAppId.d.ts +2 -4
  75. package/lib/utils/getAppId.js +2 -9
  76. package/lib/utils/getInitialInfo.d.ts +4 -3
  77. package/lib/utils/getInitialInfo.js +17 -8
  78. package/lib/utils/getParentOrigin.js +12 -2
  79. package/lib/utils/getUserProfile.js +4 -12
  80. package/lib/utils/hmr-api.d.ts +39 -0
  81. package/lib/utils/hmr-api.js +36 -0
  82. package/lib/utils/module-hot.d.ts +9 -5
  83. package/lib/utils/module-hot.js +9 -10
  84. package/lib/utils/postMessage.d.ts +0 -1
  85. package/lib/utils/postMessage.js +19 -6
  86. package/lib/utils/requestManager.js +1 -3
  87. package/lib/utils/resolveAppUrl.d.ts +27 -0
  88. package/lib/utils/resolveAppUrl.js +19 -0
  89. package/lib/utils/routePattern.d.ts +10 -0
  90. package/lib/utils/routePattern.js +45 -0
  91. package/lib/utils/scopedStorage.d.ts +5 -0
  92. package/lib/utils/scopedStorage.js +46 -0
  93. package/package.json +9 -8
  94. package/lib/apis/tools/generateImage.d.ts +0 -1
  95. package/lib/apis/tools/generateImage.js +0 -1
  96. package/lib/apis/tools/generateTextStream.d.ts +0 -1
  97. package/lib/apis/tools/generateTextStream.js +0 -1
  98. package/lib/components/AppContainer/utils/listenHot.d.ts +0 -1
  99. package/lib/components/AppContainer/utils/listenHot.js +0 -57
  100. package/lib/components/theme/ui-config.d.ts +0 -1
  101. package/lib/components/theme/ui-config.js +0 -2
  102. package/lib/integrations/generateImage.d.ts +0 -1
  103. package/lib/integrations/generateImage.js +0 -47
  104. package/lib/integrations/generateTextStream.d.ts +0 -21
  105. package/lib/integrations/generateTextStream.js +0 -98
@@ -4,9 +4,7 @@ async function fetchUserProfilesByIds(ids) {
4
4
  try {
5
5
  const dataloom = await getDataloom();
6
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);
7
+ const response = await dataloom.service.user.getByIds(ids);
10
8
  return Array.isArray(response?.data) ? response.data : response?.data?.user_list || [];
11
9
  } catch (error) {
12
10
  console.error(`Failed to fetch profiles for user IDs ${ids.join(', ')}:`, error);
@@ -0,0 +1,27 @@
1
+ /**
2
+ * 解析应用内路径,自动补全 CLIENT_BASE_PATH 前缀,返回完整 URL
3
+ * 适用于生成分享链接、二维码等需要完整 URL 的场景
4
+ *
5
+ * - 相对路径:补全前缀 + 当前域名
6
+ * - 当前域名的完整 URL:修正路径部分,补全前缀
7
+ * - 其他域名的 URL:原样返回,不做处理
8
+ *
9
+ * @param path - 应用内相对路径或完整 URL
10
+ * @returns 完整的 URL 字符串
11
+ *
12
+ * @example
13
+ * // 假设 CLIENT_BASE_PATH = '/app/abc',当前域名为 https://example.com
14
+ *
15
+ * resolveAppUrl('/detail/123')
16
+ * // => 'https://example.com/app/abc/detail/123'
17
+ *
18
+ * resolveAppUrl('https://example.com/detail/123')
19
+ * // => 'https://example.com/app/abc/detail/123'
20
+ *
21
+ * resolveAppUrl('https://example.com/app/abc/detail/123')
22
+ * // => 'https://example.com/app/abc/detail/123' (已有前缀,不重复添加)
23
+ *
24
+ * resolveAppUrl('https://other-site.com/page')
25
+ * // => 'https://other-site.com/page' (非当前域名,原样返回)
26
+ */
27
+ export declare function resolveAppUrl(path: string): string;
@@ -0,0 +1,19 @@
1
+ import { normalizeBasePath } from "./utils.js";
2
+ function ensureBasePath(pathname, basePath) {
3
+ if (!basePath) return pathname;
4
+ if (pathname.startsWith(basePath)) return pathname;
5
+ return `${basePath}${pathname.startsWith('/') ? '' : '/'}${pathname}`;
6
+ }
7
+ function resolveAppUrl(path) {
8
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
9
+ try {
10
+ const url = new URL(path);
11
+ if (url.origin !== window.location.origin) return path;
12
+ url.pathname = ensureBasePath(url.pathname, basePath);
13
+ return url.toString();
14
+ } catch {}
15
+ const normalizedPath = path.startsWith('/') ? path : `/${path}`;
16
+ const resolvedPath = ensureBasePath(normalizedPath, basePath);
17
+ return `${window.location.origin}${resolvedPath}`;
18
+ }
19
+ export { resolveAppUrl };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * 根据当前 pathname 匹配路由模式并更新存储
3
+ * 使用 react-router 的 matchPath 确保匹配逻辑与路由一致
4
+ */
5
+ export declare function updateRoutePattern(pathname: string): Promise<void>;
6
+ /**
7
+ * 获取当前匹配的参数化路由模式
8
+ * 供 axiosConfig 等非 React 上下文使用
9
+ */
10
+ export declare function getCurrentRoutePattern(): string;
@@ -0,0 +1,45 @@
1
+ import { matchPath } from "react-router-dom";
2
+ import { normalizeBasePath } from "./utils.js";
3
+ let currentRoutePattern = '/';
4
+ let routeDefinitions = null;
5
+ async function loadRouteDefinitions() {
6
+ if (routeDefinitions) return routeDefinitions;
7
+ try {
8
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
9
+ const res = await fetch(`${basePath}/routes.json`);
10
+ routeDefinitions = await res.json();
11
+ } catch {
12
+ routeDefinitions = [
13
+ {
14
+ path: '/'
15
+ }
16
+ ];
17
+ }
18
+ return routeDefinitions;
19
+ }
20
+ async function updateRoutePattern(pathname) {
21
+ const routes = await loadRouteDefinitions();
22
+ const basePath = normalizeBasePath(process.env.CLIENT_BASE_PATH);
23
+ let relativePath = pathname;
24
+ if (basePath && pathname.startsWith(basePath)) relativePath = pathname.slice(basePath.length) || '/';
25
+ const sortedRoutes = [
26
+ ...routes
27
+ ].sort((a, b)=>b.path.length - a.path.length);
28
+ for (const route of sortedRoutes){
29
+ let routePath = route.path;
30
+ if (basePath && routePath.startsWith(basePath)) routePath = routePath.slice(basePath.length) || '/';
31
+ const match = matchPath({
32
+ path: routePath,
33
+ end: true
34
+ }, relativePath);
35
+ if (match) {
36
+ currentRoutePattern = routePath;
37
+ return;
38
+ }
39
+ }
40
+ currentRoutePattern = relativePath;
41
+ }
42
+ function getCurrentRoutePattern() {
43
+ return currentRoutePattern;
44
+ }
45
+ export { getCurrentRoutePattern, updateRoutePattern };
@@ -0,0 +1,5 @@
1
+ /**
2
+ * 按 appId 隔离的 localStorage 封装
3
+ * API 与原生 localStorage 保持一致
4
+ */
5
+ export declare const scopedStorage: Storage;
@@ -0,0 +1,46 @@
1
+ import { getAppId } from "./getAppId.js";
2
+ function getPrefix() {
3
+ const appId = getAppId();
4
+ const namespace = appId || '__global__';
5
+ return `__miaoda_${namespace}__:`;
6
+ }
7
+ function getScopedKeys() {
8
+ const prefix = getPrefix();
9
+ const keys = [];
10
+ for(let i = 0; i < localStorage.length; i++){
11
+ const key = localStorage.key(i);
12
+ if (key && key.startsWith(prefix)) keys.push(key.substring(prefix.length));
13
+ }
14
+ return keys;
15
+ }
16
+ const scopedStorage = {
17
+ getItem (key) {
18
+ const prefixedKey = getPrefix() + key;
19
+ return localStorage.getItem(prefixedKey);
20
+ },
21
+ setItem (key, value) {
22
+ const prefixedKey = getPrefix() + key;
23
+ localStorage.setItem(prefixedKey, value);
24
+ },
25
+ removeItem (key) {
26
+ const prefixedKey = getPrefix() + key;
27
+ localStorage.removeItem(prefixedKey);
28
+ },
29
+ clear () {
30
+ const prefix = getPrefix();
31
+ const keysToRemove = [];
32
+ for(let i = 0; i < localStorage.length; i++){
33
+ const key = localStorage.key(i);
34
+ if (key && key.startsWith(prefix)) keysToRemove.push(key);
35
+ }
36
+ keysToRemove.forEach((key)=>localStorage.removeItem(key));
37
+ },
38
+ key (index) {
39
+ const keys = getScopedKeys();
40
+ return keys[index] || null;
41
+ },
42
+ get length () {
43
+ return getScopedKeys().length;
44
+ }
45
+ };
46
+ export { scopedStorage };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lark-apaas/client-toolkit",
3
- "version": "1.2.17-alpha.1",
3
+ "version": "1.2.17-alpha.10",
4
4
  "types": "./lib/index.d.ts",
5
5
  "main": "./lib/index.js",
6
6
  "files": [
@@ -98,12 +98,13 @@
98
98
  "dependencies": {
99
99
  "@ant-design/colors": "^7.2.1",
100
100
  "@ant-design/cssinjs": "^1.24.0",
101
- "@data-loom/js": "0.4.7",
102
- "@lark-apaas/aily-web-sdk": ">=0.0.1",
103
- "@lark-apaas/auth-sdk": "^0.1.0",
104
- "@lark-apaas/client-capability": "^0.1.4",
105
- "@lark-apaas/miaoda-inspector": "^1.0.16",
106
- "@lark-apaas/observable-web": "^1.0.2-alpha.2",
101
+ "@data-loom/js": "0.4.9",
102
+ "@lark-apaas/aily-web-sdk": "^0.0.6",
103
+ "@lark-apaas/auth-sdk": "^0.1.1",
104
+ "@lark-apaas/client-capability": "^0.1.5",
105
+ "@lark-apaas/internal-slardar": ">=0.0.1",
106
+ "@lark-apaas/miaoda-inspector": "^1.0.20",
107
+ "@lark-apaas/observable-web": "^1.0.4",
107
108
  "@radix-ui/react-avatar": "^1.1.10",
108
109
  "@radix-ui/react-popover": "^1.1.15",
109
110
  "@radix-ui/react-slot": "^1.2.3",
@@ -174,4 +175,4 @@
174
175
  "react-router-dom": ">=6.26.2",
175
176
  "styled-jsx": ">=5.0.0"
176
177
  }
177
- }
178
+ }
@@ -1 +0,0 @@
1
- export * from '../../integrations/generateImage';
@@ -1 +0,0 @@
1
- export * from "../../integrations/generateImage.js";
@@ -1 +0,0 @@
1
- export * from '../../integrations/generateTextStream';
@@ -1 +0,0 @@
1
- export * from "../../integrations/generateTextStream.js";
@@ -1 +0,0 @@
1
- export declare function connectDevServer(): WebSocket;
@@ -1,57 +0,0 @@
1
- import sockjs_client from "sockjs-client";
2
- import { submitPostMessage, submitSlardarEvent } from "../../../utils/postMessage.js";
3
- import { getWsPath } from "../../../utils/utils.js";
4
- let hotInited = false;
5
- function handleDevServerMessage(msg) {
6
- if ('hash' === msg.type) {
7
- if (!hotInited) {
8
- hotInited = true;
9
- return;
10
- }
11
- submitPostMessage({
12
- type: 'HmrMessage',
13
- msg: {
14
- type: 'hot'
15
- },
16
- data: null
17
- });
18
- } else if ('errors' === msg.type) submitPostMessage({
19
- type: 'HmrMessage',
20
- msg: {
21
- type: 'errors',
22
- data: JSON.stringify(msg.data)
23
- },
24
- data: null
25
- });
26
- else if ('hmr-timing' === msg.type) {
27
- const { duration, fileCount, fileTotalSize } = msg.data;
28
- submitSlardarEvent({
29
- name: 'runTiming',
30
- metrics: {
31
- duration
32
- },
33
- categories: {
34
- type: 'sandbox-hmr-timing',
35
- fileCount,
36
- fileTotalSize
37
- }
38
- });
39
- }
40
- }
41
- function connectDevServer() {
42
- const sockUrl = getWsPath();
43
- const sock = new sockjs_client(sockUrl);
44
- sock.onopen = ()=>console.log('✅ connect DevServer SockJS');
45
- sock.onmessage = (event)=>{
46
- try {
47
- const msg = JSON.parse(event.data);
48
- console.log('hmr 消息:', msg);
49
- handleDevServerMessage(msg);
50
- } catch (err) {
51
- console.error('解析 hmr 消息失败:', event.data);
52
- }
53
- };
54
- return sock;
55
- }
56
- 'production' !== process.env.NODE_ENV && connectDevServer();
57
- export { connectDevServer };
@@ -1 +0,0 @@
1
- export { defaultUIConfig, type UIComponentConfig, } from '@lark-apaas/miaoda-inspector';
@@ -1,2 +0,0 @@
1
- import { defaultUIConfig } from "@lark-apaas/miaoda-inspector";
2
- export { defaultUIConfig };
@@ -1 +0,0 @@
1
- export declare function generateImage(prompt: string, size?: string, headers?: Record<string, string>): Promise<any>;
@@ -1,47 +0,0 @@
1
- import { getAppId } from "../utils/getAppId.js";
2
- import { getCsrfToken } from "../utils/getCsrfToken.js";
3
- import { getEnvPath } from "../utils/getEnvPath.js";
4
- import { isSparkRuntime } from "../utils/utils.js";
5
- async function generateImage(prompt, size = '1024x1024', headers = {}) {
6
- const appId = getAppId(window.location.pathname);
7
- if (!appId) return {
8
- code: 1,
9
- msg: 'appId is required',
10
- data: {}
11
- };
12
- const defaultHeaders = {
13
- 'Content-Type': 'application/json'
14
- };
15
- const mergedHeaders = {
16
- ...defaultHeaders,
17
- ...headers,
18
- 'X-Kunlun-Token': window.token,
19
- 'x-miaoda-token': window.MIAODA_BUILTIN_TTT,
20
- 'x-lgw-csrf-token': window.lgw_csrf_token,
21
- ...window.CSRF_HEADERS || {}
22
- };
23
- if (isSparkRuntime()) {
24
- mergedHeaders['X-Suda-Csrf-Token'] = getCsrfToken();
25
- const response = await fetch(`${window.location.origin}/spark/b/${appId}/text2image`, {
26
- method: 'POST',
27
- headers: mergedHeaders,
28
- credentials: 'include',
29
- body: JSON.stringify({
30
- prompt,
31
- size
32
- })
33
- });
34
- return await response.json();
35
- }
36
- const response = await fetch(`${window.location.origin}/ai/api/${getEnvPath()}/v1/apps/${appId}/text2image`, {
37
- method: 'POST',
38
- headers: mergedHeaders,
39
- credentials: 'include',
40
- body: JSON.stringify({
41
- prompt,
42
- size
43
- })
44
- });
45
- return await response.json();
46
- }
47
- export { generateImage };
@@ -1,21 +0,0 @@
1
- interface GenerateTextOptions {
2
- text: string;
3
- thinking_type?: 'enabled' | 'disabled';
4
- headers?: Record<string, string>;
5
- }
6
- interface GenerateTextResult {
7
- content: string;
8
- reasoning_content: string;
9
- success: boolean;
10
- error?: string;
11
- }
12
- /**
13
- * 文生文 - 流式版本
14
- * 支持实时接收生成内容的回调
15
- */
16
- export declare function generateTextStream(options: GenerateTextOptions, onChunk?: (chunk: {
17
- content: string;
18
- reasoning_content: string;
19
- finished: boolean;
20
- }) => void): Promise<GenerateTextResult>;
21
- export {};
@@ -1,98 +0,0 @@
1
- import { getAppId } from "../utils/getAppId.js";
2
- import { getCsrfToken } from "../utils/getCsrfToken.js";
3
- import { getEnvPath } from "../utils/getEnvPath.js";
4
- import { isSparkRuntime } from "../utils/utils.js";
5
- async function generateTextStream(options, onChunk) {
6
- const { text, thinking_type = 'disabled', headers = {} } = options;
7
- const appId = getAppId(window.location.pathname);
8
- if (!appId) return {
9
- content: '',
10
- reasoning_content: '',
11
- success: false,
12
- error: 'appId is required'
13
- };
14
- try {
15
- const mergedHeaders = {
16
- 'Content-Type': 'application/json',
17
- ...headers,
18
- 'X-Kunlun-Token': window.token,
19
- 'x-miaoda-token': window.MIAODA_BUILTIN_TTT,
20
- 'x-lgw-csrf-token': window.lgw_csrf_token,
21
- ...window.CSRF_HEADERS || {}
22
- };
23
- let response;
24
- if (isSparkRuntime()) {
25
- mergedHeaders['X-Suda-Csrf-Token'] = getCsrfToken();
26
- response = await fetch(`${window.location.origin}/spark/b/${appId}/text/generate`, {
27
- method: 'POST',
28
- headers: mergedHeaders,
29
- credentials: 'include',
30
- body: JSON.stringify({
31
- text,
32
- thinking_type
33
- })
34
- });
35
- } else response = await fetch(`${window.location.origin}/ai/api/${getEnvPath()}/v1/apps/${appId}/text/generate`, {
36
- method: 'POST',
37
- headers: mergedHeaders,
38
- credentials: 'include',
39
- body: JSON.stringify({
40
- text,
41
- thinking_type
42
- })
43
- });
44
- if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
45
- const reader = response.body?.getReader();
46
- if (!reader) throw new Error('无法获取响应流');
47
- let fullContent = '';
48
- let fullReasoningContent = '';
49
- const decoder = new TextDecoder();
50
- while(true){
51
- const { done, value } = await reader.read();
52
- if (done) break;
53
- const chunk = decoder.decode(value, {
54
- stream: true
55
- });
56
- const lines = chunk.split('\n').filter((line)=>line.trim());
57
- for (const line of lines)if (line.startsWith('data: ')) {
58
- const jsonStr = line.slice(6);
59
- try {
60
- const data = JSON.parse(jsonStr);
61
- if (0 !== data.code) return {
62
- content: '',
63
- reasoning_content: '',
64
- success: false,
65
- error: data.msg || '生成失败'
66
- };
67
- if (data.data.content) fullContent += data.data.content;
68
- if (data.data.reasoning_content) fullReasoningContent += data.data.reasoning_content;
69
- if (onChunk) onChunk({
70
- content: data.data.content || '',
71
- reasoning_content: data.data.reasoning_content || '',
72
- finished: data.finished
73
- });
74
- if (data.finished) return {
75
- content: fullContent,
76
- reasoning_content: fullReasoningContent,
77
- success: true
78
- };
79
- } catch (parseError) {
80
- console.error(`解析JSON失败: ${jsonStr}`);
81
- }
82
- }
83
- }
84
- return {
85
- content: fullContent,
86
- reasoning_content: fullReasoningContent,
87
- success: true
88
- };
89
- } catch (error) {
90
- return {
91
- content: '',
92
- reasoning_content: '',
93
- success: false,
94
- error: error instanceof Error ? error.message : '未知错误'
95
- };
96
- }
97
- }
98
- export { generateTextStream };