@chatbi-v/mocks 2.1.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,92 +1,853 @@
1
- /**
2
- * @file index.ts
3
- * @description Mock 模块入口,导出模拟数据适配器、生成器及静态测试数据
4
- * @author ChatBI Team
5
- */
6
- import { dateUtils } from '@chatbi-v/core';
7
- /**
8
- * Mock 数据模块
9
- * @description 提供前端开发所需的模拟数据适配器和工具
10
- */
11
- export * from './adapter';
12
- export * from './generator';
13
- export * from './interceptor';
14
- export * from './strategies';
15
- export * from './types';
16
- export * from './utils';
17
- /**
18
- * 模拟用户数据
19
- */
20
- export const MOCK_USER = {
21
- id: 'u_001',
22
- name: 'Admin User',
23
- avatar: 'https://api.dicebear.com/7.x/avataaars/svg?seed=Admin',
24
- role: 'admin',
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
25
11
  };
26
- // 保留原有的静态数据导出,以兼容可能直接引用的地方,但建议使用 adapter 自动生成
27
- export const MOCK_SESSIONS = [
28
- { id: 's_001', title: '2024 Q1 销售分析', date: '2024-03-15', lastMessage: '好的,正在为您分析 Q1 销售数据...' },
29
- { id: 's_002', title: '用户增长趋势', date: '2024-03-10', lastMessage: '用户增长曲线显示...' },
30
- { id: 's_003', title: '竞品分析报告', date: '2024-03-08', lastMessage: '主要竞品 A 的市场份额...' },
31
- { id: 's_004', title: '营销活动复盘', date: '2024-03-05', lastMessage: 'ROI 提升了 15%...' },
32
- { id: 's_005', title: '财务报表审计', date: '2024-03-01', lastMessage: '请确认以下财务指标...' },
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ChatStreamStrategy: () => ChatStreamStrategy,
34
+ HistoryStreamStrategy: () => HistoryStreamStrategy,
35
+ JsonStrategy: () => JsonStrategy,
36
+ MOCK_FAVORITES: () => MOCK_FAVORITES,
37
+ MOCK_SCENES: () => MOCK_SCENES,
38
+ MOCK_SESSIONS: () => MOCK_SESSIONS,
39
+ MOCK_USER: () => MOCK_USER,
40
+ MockAdapter: () => MockAdapter,
41
+ MockResponseGenerator: () => MockResponseGenerator,
42
+ SsePageStrategy: () => SsePageStrategy,
43
+ SseStrategy: () => SseStrategy,
44
+ StrategyFactory: () => StrategyFactory,
45
+ createChatStream: () => createChatStream,
46
+ createHistoryStream: () => createHistoryStream,
47
+ eventsToStream: () => eventsToStream,
48
+ flatEvents: () => flatEvents,
49
+ generateMockMessages: () => generateMockMessages,
50
+ installFetchMock: () => installFetchMock,
51
+ installSSEMock: () => installSSEMock,
52
+ mockData: () => mockData,
53
+ processTemplate: () => processTemplate,
54
+ setupMock: () => setupMock,
55
+ sleep: () => sleep
56
+ });
57
+ module.exports = __toCommonJS(index_exports);
58
+ var import_core3 = require("@chatbi-v/core");
59
+
60
+ // src/adapter.ts
61
+ var import_core2 = require("@chatbi-v/core");
62
+ var import_mockjs3 = __toESM(require("mockjs"));
63
+
64
+ // src/strategies.ts
65
+ var import_mockjs2 = __toESM(require("mockjs"));
66
+
67
+ // src/generator.ts
68
+ var import_core = require("@chatbi-v/core");
69
+ var MockResponseGenerator = class {
70
+ events = [];
71
+ sessionId;
72
+ agentName;
73
+ currentTodos = [];
74
+ constructor(agentName = "Assistant", sessionId) {
75
+ this.sessionId = sessionId || "conv_" + import_core.dateUtils.now();
76
+ this.agentName = agentName;
77
+ }
78
+ /**
79
+ * 生成历史消息流
80
+ */
81
+ emitHistory(history) {
82
+ history.forEach((msg) => {
83
+ const data = {
84
+ content: msg.content,
85
+ sessionId: this.sessionId,
86
+ role: msg.role,
87
+ completed: true,
88
+ agentName: this.agentName,
89
+ createTime: msg.createTime
90
+ };
91
+ this.pushEvent("data", data);
92
+ if (msg.todos) {
93
+ this.pushEvent("todos", { items: msg.todos });
94
+ }
95
+ });
96
+ return this;
97
+ }
98
+ /**
99
+ * 初始化执行计划
100
+ * @param steps 计划步骤列表
101
+ */
102
+ initPlan(steps) {
103
+ this.currentTodos = steps.map((step) => ({
104
+ content: step,
105
+ status: "PENDING"
106
+ }));
107
+ this.pushTodos();
108
+ return this;
109
+ }
110
+ /**
111
+ * 更新执行计划状态
112
+ * @param activeIndex 当前正在进行的步骤索引
113
+ */
114
+ updatePlanStatus(activeIndex) {
115
+ this.currentTodos = this.currentTodos.map((todo, index) => {
116
+ if (index < activeIndex) {
117
+ return { ...todo, status: "COMPLETED" };
118
+ } else if (index === activeIndex) {
119
+ return { ...todo, status: "IN_PROGRESS" };
120
+ } else {
121
+ return { ...todo, status: "PENDING" };
122
+ }
123
+ });
124
+ this.pushTodos();
125
+ return this;
126
+ }
127
+ /**
128
+ * 标记所有计划为完成
129
+ */
130
+ completePlan() {
131
+ this.currentTodos = this.currentTodos.map((todo) => ({ ...todo, status: "COMPLETED" }));
132
+ this.pushTodos();
133
+ return this;
134
+ }
135
+ /**
136
+ * 添加日志
137
+ * @param content 日志内容
138
+ * @param type 日志类型
139
+ * @param agentName 可选的 Agent 名称
140
+ */
141
+ addLog(content, type = "info", agentName) {
142
+ this.pushEvent("log", {
143
+ type,
144
+ content,
145
+ agentName: agentName || this.agentName
146
+ });
147
+ return this;
148
+ }
149
+ /**
150
+ * 添加系统错误事件
151
+ * @param errorCode 错误码
152
+ * @param errorMessage 错误信息
153
+ */
154
+ addError(errorCode, errorMessage) {
155
+ this.pushEvent("error", {
156
+ errorCode,
157
+ errorMessage
158
+ });
159
+ return this;
160
+ }
161
+ /**
162
+ * 添加流式内容块
163
+ * @param content 完整内容
164
+ * @param chunkSize 分块大小
165
+ */
166
+ streamContent(content, chunkSize = 20) {
167
+ for (let i = 0; i < content.length; i += chunkSize) {
168
+ const chunk = content.slice(i, i + chunkSize);
169
+ this.pushEvent("data", {
170
+ content: chunk,
171
+ sessionId: this.sessionId,
172
+ completed: false,
173
+ agentName: this.agentName
174
+ });
175
+ }
176
+ return this;
177
+ }
178
+ /**
179
+ * 结束流
180
+ */
181
+ finish() {
182
+ this.pushEvent("data", {
183
+ content: "",
184
+ sessionId: this.sessionId,
185
+ completed: true,
186
+ agentName: this.agentName
187
+ });
188
+ return this;
189
+ }
190
+ /**
191
+ * 生成 A2UI 响应
192
+ * @param component A2UI 组件配置对象
193
+ */
194
+ emitA2UI(component) {
195
+ const content = JSON.stringify(component, null, 2);
196
+ return this.streamContent(content);
197
+ }
198
+ /**
199
+ * 生成最终的响应字符串
200
+ */
201
+ toString() {
202
+ return this.events.join("\n");
203
+ }
204
+ pushTodos() {
205
+ this.pushEvent("todos", { items: this.currentTodos });
206
+ }
207
+ pushEvent(type, data) {
208
+ this.events.push(`event: ${type}
209
+ data: ${JSON.stringify(data)}
210
+ `);
211
+ }
212
+ };
213
+
214
+ // src/utils.ts
215
+ var import_dayjs = __toESM(require("dayjs"));
216
+ var import_mockjs = __toESM(require("mockjs"));
217
+ var sleep = (ms) => new Promise((r) => setTimeout(r, ms));
218
+ function processTemplate(data, context) {
219
+ if (typeof data === "string") {
220
+ if (/^\{\{.*\}\}$/.test(data)) {
221
+ const expression = data.slice(2, -2).trim();
222
+ try {
223
+ const keys = Object.keys(context);
224
+ const values = Object.values(context);
225
+ const fn = new Function(...keys, `return ${expression}`);
226
+ return fn(...values);
227
+ } catch (e) {
228
+ console.warn(`[Mock] Failed to evaluate template: ${data}`, e);
229
+ return data;
230
+ }
231
+ }
232
+ return data;
233
+ }
234
+ if (Array.isArray(data)) {
235
+ return data.map((item) => processTemplate(item, context));
236
+ }
237
+ if (typeof data === "object" && data !== null) {
238
+ const result = {};
239
+ for (const key in data) {
240
+ result[key] = processTemplate(data[key], context);
241
+ }
242
+ return result;
243
+ }
244
+ return data;
245
+ }
246
+ function flatEvents(eventsSchema, requestData = {}) {
247
+ const context = {
248
+ $query: requestData,
249
+ // Backward compatibility
250
+ $body: requestData,
251
+ $param: requestData?.param || requestData
252
+ };
253
+ import_mockjs.default.Random.extend({
254
+ $query: () => context.$query,
255
+ $body: () => context.$body,
256
+ $param: () => context.$param
257
+ });
258
+ const compiled = import_mockjs.default.mock(eventsSchema);
259
+ return Object.values(compiled).flat().map((event) => processTemplate(event, context)).sort((a, b) => {
260
+ const delayA = typeof a.delay === "number" ? a.delay : parseInt(String(a.delay || 0));
261
+ const delayB = typeof b.delay === "number" ? b.delay : parseInt(String(b.delay || 0));
262
+ return delayA - delayB;
263
+ });
264
+ }
265
+ function eventsToStream(events) {
266
+ const encoder = new TextEncoder();
267
+ return new ReadableStream({
268
+ start(ctrl) {
269
+ if (!events || events.length === 0) {
270
+ ctrl.close();
271
+ return;
272
+ }
273
+ (async () => {
274
+ try {
275
+ const startTime = (0, import_dayjs.default)().valueOf();
276
+ for (const eventItem of events) {
277
+ const delay = typeof eventItem.delay === "number" ? eventItem.delay : parseInt(String(eventItem.delay || 0));
278
+ const elapsed = (0, import_dayjs.default)().valueOf() - startTime;
279
+ const remaining = Math.max(0, delay - elapsed);
280
+ if (remaining > 0) {
281
+ await sleep(remaining);
282
+ }
283
+ const payload = `event: ${eventItem.event}
284
+ data: ${JSON.stringify(eventItem.data)}
285
+
286
+ `;
287
+ ctrl.enqueue(encoder.encode(payload));
288
+ }
289
+ ctrl.close();
290
+ } catch (e) {
291
+ ctrl.error(e);
292
+ }
293
+ })();
294
+ }
295
+ });
296
+ }
297
+
298
+ // src/strategies.ts
299
+ var ChatStreamStrategy = class {
300
+ generate(schema) {
301
+ const config = schema;
302
+ const defaultName = config.agentName || "BI\u52A9\u624B";
303
+ const generator = new MockResponseGenerator(defaultName);
304
+ const mockData2 = config.data ? import_mockjs2.default.mock(config.data) : {};
305
+ if (config.plan) {
306
+ generator.initPlan(config.plan);
307
+ }
308
+ if (config.timeline) {
309
+ config.timeline.forEach((step) => {
310
+ if (step.planIndex !== void 0) {
311
+ generator.updatePlanStatus(step.planIndex);
312
+ }
313
+ if (step.log) {
314
+ const logContent = typeof step.log === "string" ? step.log : step.log.content;
315
+ const logLevel = typeof step.log === "object" ? step.log.level : "info";
316
+ const logAgent = typeof step.log === "object" ? step.log.agent : void 0;
317
+ generator.addLog(logContent, logLevel, logAgent);
318
+ }
319
+ });
320
+ }
321
+ let content;
322
+ if (typeof config.content === "function") {
323
+ content = config.content(mockData2);
324
+ } else {
325
+ content = config.content;
326
+ }
327
+ if (typeof content === "object" && content !== null) {
328
+ generator.emitA2UI(content);
329
+ } else {
330
+ generator.streamContent(content);
331
+ }
332
+ generator.completePlan();
333
+ generator.finish();
334
+ return generator.toString().split("\n\n").map((chunk) => chunk + "\n\n");
335
+ }
336
+ };
337
+ var HistoryStreamStrategy = class {
338
+ generate(schema) {
339
+ const config = schema;
340
+ const generator = new MockResponseGenerator("BI\u52A9\u624B");
341
+ const historyMock = import_mockjs2.default.mock(config.template);
342
+ const fullHistory = [...config.prepend || [], ...historyMock.list || historyMock];
343
+ generator.emitHistory(fullHistory);
344
+ return generator.toString().split("\n\n").map((chunk) => chunk + "\n\n");
345
+ }
346
+ };
347
+ var JsonStrategy = class {
348
+ process(config, _requestParams) {
349
+ const jsonConfig = config;
350
+ if (!jsonConfig.responseSchema) return {};
351
+ return import_mockjs2.default.mock(jsonConfig.responseSchema);
352
+ }
353
+ };
354
+ var SseStrategy = class {
355
+ process(config, requestParams = {}) {
356
+ const sseConfig = config;
357
+ if (!sseConfig.responseSchema) return [];
358
+ return flatEvents(sseConfig.responseSchema, requestParams);
359
+ }
360
+ };
361
+ var SsePageStrategy = class {
362
+ process(config, requestParams = {}) {
363
+ const ssePageConfig = config;
364
+ if (!ssePageConfig.responseSchema) return [];
365
+ const events = flatEvents(ssePageConfig.responseSchema, requestParams);
366
+ if (ssePageConfig.pageEvent) {
367
+ const context = {
368
+ $query: requestParams,
369
+ // Backward compatibility
370
+ $body: requestParams,
371
+ $param: requestParams?.param || requestParams
372
+ };
373
+ import_mockjs2.default.Random.extend({
374
+ $query: () => context.$query,
375
+ $body: () => context.$body,
376
+ $param: () => context.$param
377
+ });
378
+ let pageEvent = import_mockjs2.default.mock(ssePageConfig.pageEvent);
379
+ pageEvent = processTemplate(pageEvent, context);
380
+ let maxDelay = 0;
381
+ if (events.length > 0) {
382
+ const lastEvent = events[events.length - 1];
383
+ maxDelay = typeof lastEvent.delay === "number" ? lastEvent.delay : parseInt(String(lastEvent.delay || 0));
384
+ }
385
+ const pageDelay = typeof pageEvent.delay === "number" ? pageEvent.delay : parseInt(String(pageEvent.delay || 0));
386
+ if (pageDelay <= maxDelay) {
387
+ pageEvent.delay = maxDelay + 20;
388
+ }
389
+ events.push(pageEvent);
390
+ }
391
+ const es = events.sort((a, b) => {
392
+ const delayA = typeof a.delay === "number" ? a.delay : parseInt(String(a.delay || 0));
393
+ const delayB = typeof b.delay === "number" ? b.delay : parseInt(String(b.delay || 0));
394
+ return delayA - delayB;
395
+ });
396
+ return es;
397
+ }
398
+ };
399
+ var StrategyFactory = {
400
+ getStrategy(type = "json") {
401
+ switch (type) {
402
+ case "sse":
403
+ return new SseStrategy();
404
+ case "sse-page":
405
+ return new SsePageStrategy();
406
+ case "json":
407
+ default:
408
+ return new JsonStrategy();
409
+ }
410
+ }
411
+ };
412
+
413
+ // src/adapter.ts
414
+ var logger = (0, import_core2.createLogger)("MockAdapter");
415
+ var MockAdapter = class _MockAdapter {
416
+ delay;
417
+ // 遗留策略(为了兼容旧版代码)
418
+ static strategies = {
419
+ chat_stream: new ChatStreamStrategy(),
420
+ history_stream: new HistoryStreamStrategy()
421
+ };
422
+ /**
423
+ * 构造函数
424
+ * @param delay 全局模拟延迟时间(毫秒),默认 300ms
425
+ */
426
+ constructor(delay = 300) {
427
+ this.delay = delay;
428
+ }
429
+ /**
430
+ * 注册自定义 Mock 生成策略
431
+ * @param key 策略唯一标识符 (e.g., 'chat_stream', 'history_stream')
432
+ * @param strategy 实现了 MockGeneratorStrategy 接口的策略实例
433
+ */
434
+ static registerStrategy(key, strategy) {
435
+ this.strategies[key] = strategy;
436
+ }
437
+ /**
438
+ * 处理普通 HTTP 请求(非流式)
439
+ * @param config 请求配置对象
440
+ * @param endpointConfig API 端点配置,包含 responseSchema
441
+ * @returns Promise 返回模拟的响应数据
442
+ */
443
+ async request(config, endpointConfig) {
444
+ const delay = endpointConfig?.delay ?? this.delay;
445
+ return new Promise((resolve, reject) => {
446
+ setTimeout(() => {
447
+ try {
448
+ if (!endpointConfig || !endpointConfig.responseSchema) {
449
+ logger.warn(`\u672A\u627E\u5230\u54CD\u5E94\u67B6\u6784\u914D\u7F6E: ${config.url}`);
450
+ resolve({});
451
+ return;
452
+ }
453
+ let schema = endpointConfig.responseSchema;
454
+ let mockData2;
455
+ if (typeof schema === "function") {
456
+ schema = schema(config);
457
+ }
458
+ const effectiveConfig = {
459
+ type: endpointConfig.type,
460
+ status: endpointConfig.status || 200,
461
+ pageEvent: endpointConfig.pageEvent,
462
+ responseSchema: schema,
463
+ ...typeof schema === "object" ? schema : {}
464
+ };
465
+ if (effectiveConfig.status !== 200) {
466
+ const error = new Error(`Request failed with status code ${effectiveConfig.status}`);
467
+ error.response = {
468
+ status: effectiveConfig.status,
469
+ data: import_mockjs3.default.mock(schema),
470
+ headers: {}
471
+ };
472
+ reject(error);
473
+ return;
474
+ }
475
+ if (typeof schema === "string") {
476
+ mockData2 = schema;
477
+ } else if (this.isLegacySchema(schema)) {
478
+ const strategy = _MockAdapter.strategies[schema._type];
479
+ if (strategy) {
480
+ const chunks = strategy.generate(schema);
481
+ mockData2 = chunks.join("").replace(/event: data\ndata: /g, "").replace(/\n\n/g, "");
482
+ try {
483
+ mockData2 = JSON.parse(mockData2);
484
+ } catch (e) {
485
+ }
486
+ } else {
487
+ logger.warn(`\u672A\u627E\u5230\u5BF9\u5E94\u7684\u7B56\u7565\u7C7B\u578B: ${schema._type}`);
488
+ mockData2 = {};
489
+ }
490
+ } else {
491
+ const type = effectiveConfig.type || "json";
492
+ const strategy = StrategyFactory.getStrategy(type);
493
+ mockData2 = strategy.process(effectiveConfig, config.params || config.data);
494
+ }
495
+ logger.info(`Request: ${config.method} ${config.url}`, config.data || config.params);
496
+ logger.info(`Response:`, mockData2);
497
+ resolve(mockData2);
498
+ } catch (error) {
499
+ reject(error);
500
+ }
501
+ }, delay);
502
+ });
503
+ }
504
+ /**
505
+ * 处理流式请求 (SSE)
506
+ * @param config 请求配置对象
507
+ * @param callbacks 流式回调函数集合 (onMessage, onFinish, onError)
508
+ * @param endpointConfig API 端点配置,包含 responseSchema
509
+ */
510
+ async stream(config, callbacks, endpointConfig) {
511
+ const { onMessage, onFinish, onError } = callbacks;
512
+ const signal = config.signal;
513
+ const delay = endpointConfig?.delay ?? this.delay;
514
+ return new Promise((resolve, reject) => {
515
+ if (signal && signal.aborted) {
516
+ if (onFinish) onFinish();
517
+ resolve();
518
+ return;
519
+ }
520
+ setTimeout(async () => {
521
+ try {
522
+ if (!endpointConfig || !endpointConfig.responseSchema) {
523
+ logger.warn(`\u672A\u627E\u5230\u6D41\u5F0F\u54CD\u5E94\u67B6\u6784: ${config.url}`);
524
+ if (onFinish) onFinish();
525
+ resolve();
526
+ return;
527
+ }
528
+ const requestStart = import_core2.dateUtils.now();
529
+ logger.info(`[SSE Start] Request: ${config.method} ${config.url}`, {
530
+ params: config.data || config.params,
531
+ time: import_core2.dateUtils.dayjs().toISOString()
532
+ });
533
+ let schema = endpointConfig.responseSchema;
534
+ if (typeof schema === "function") {
535
+ schema = schema(config);
536
+ }
537
+ const effectiveConfig = {
538
+ type: endpointConfig.type,
539
+ status: endpointConfig.status || 200,
540
+ pageEvent: endpointConfig.pageEvent,
541
+ responseSchema: schema,
542
+ ...typeof schema === "object" ? schema : {}
543
+ };
544
+ if (effectiveConfig.status !== 200) {
545
+ const response = {
546
+ status: effectiveConfig.status,
547
+ data: import_mockjs3.default.mock(schema),
548
+ headers: {}
549
+ };
550
+ if (callbacks.onResponse) {
551
+ const hijacked = await callbacks.onResponse(response);
552
+ if (hijacked) {
553
+ resolve();
554
+ return;
555
+ }
556
+ }
557
+ const error = new Error(`Stream request failed with status code ${effectiveConfig.status}`);
558
+ error.response = response;
559
+ logger.error(`[SSE Error] Request failed with status ${effectiveConfig.status}`, error);
560
+ if (onError) onError(error);
561
+ reject(error);
562
+ return;
563
+ }
564
+ if (callbacks.onResponse) {
565
+ const hijacked = await callbacks.onResponse({
566
+ status: 200,
567
+ data: null,
568
+ headers: {}
569
+ });
570
+ if (hijacked) {
571
+ resolve();
572
+ return;
573
+ }
574
+ }
575
+ if (this.isNewConfig(effectiveConfig)) {
576
+ const type = effectiveConfig.type || "sse";
577
+ const strategy = StrategyFactory.getStrategy(type);
578
+ const events = strategy.process(
579
+ effectiveConfig,
580
+ config.params || config.data
581
+ );
582
+ if (Array.isArray(events)) {
583
+ const startTime = import_core2.dateUtils.now();
584
+ let eventCount = 0;
585
+ logger.info(
586
+ `[SSE Processing] Generated ${events.length} events for ${type} strategy`
587
+ );
588
+ for (const event of events) {
589
+ if (signal && signal.aborted) {
590
+ logger.info(
591
+ `[SSE Abort] Stream aborted by user after ${import_core2.dateUtils.now() - requestStart}ms`
592
+ );
593
+ break;
594
+ }
595
+ const delay2 = typeof event.delay === "number" ? event.delay : parseInt(String(event.delay || 0));
596
+ const elapsed = import_core2.dateUtils.now() - startTime;
597
+ const remaining = Math.max(0, delay2 - elapsed);
598
+ if (remaining > 0) {
599
+ await sleep(remaining);
600
+ }
601
+ if (signal && signal.aborted) break;
602
+ const chunk = `event: ${event.event}
603
+ data: ${JSON.stringify(event.data)}
604
+
605
+ `;
606
+ if (["error", "todos", "page"].includes(event.event)) {
607
+ logger.info(`[SSE Event] Emitting special event: ${event.event}`, event.data);
608
+ } else if (eventCount === 0 || eventCount === events.length - 1) {
609
+ logger.info(
610
+ `[SSE Event] Emitting ${eventCount === 0 ? "first" : "last"} data event`,
611
+ { preview: JSON.stringify(event.data).slice(0, 50) + "..." }
612
+ );
613
+ }
614
+ if (onMessage) onMessage(chunk);
615
+ eventCount++;
616
+ }
617
+ }
618
+ } else {
619
+ let chunks = [];
620
+ if (typeof schema === "string") {
621
+ chunks = schema.split("\n\n").map((chunk) => chunk + "\n\n");
622
+ } else if (this.isLegacySchema(schema)) {
623
+ chunks = this.generateAdvancedChunks(schema);
624
+ } else {
625
+ const mockData2 = import_mockjs3.default.mock(schema);
626
+ chunks = [`data: ${JSON.stringify(mockData2)}
627
+
628
+ `];
629
+ }
630
+ for (const chunk of chunks) {
631
+ if (signal && signal.aborted) {
632
+ logger.info("[SSE Abort] Stream aborted by user");
633
+ break;
634
+ }
635
+ if (chunk.trim()) {
636
+ if (onMessage) onMessage(chunk);
637
+ await new Promise((r) => setTimeout(r, 200));
638
+ }
639
+ }
640
+ }
641
+ if (!signal || !signal.aborted) {
642
+ logger.info(
643
+ `[SSE Complete] Stream finished successfully in ${import_core2.dateUtils.now() - requestStart}ms`
644
+ );
645
+ if (onFinish) onFinish();
646
+ }
647
+ resolve();
648
+ } catch (error) {
649
+ logger.error(`[SSE Error] Stream processing failed`, error);
650
+ if (onError) onError(error);
651
+ resolve();
652
+ }
653
+ }, delay);
654
+ });
655
+ }
656
+ /**
657
+ * 判断是否为遗留的 schema 格式
658
+ */
659
+ isLegacySchema(schema) {
660
+ return schema && typeof schema === "object" && "_type" in schema;
661
+ }
662
+ /**
663
+ * 判断是否为新版配置格式
664
+ * @description 检查配置对象中是否包含有效的 type 字段
665
+ */
666
+ isNewConfig(config) {
667
+ return config && typeof config === "object" && (["json", "sse", "sse-page"].includes(config.type) || "responseSchema" in config);
668
+ }
669
+ /**
670
+ * 生成遗留的高级 schema 数据块
671
+ */
672
+ generateAdvancedChunks(schema) {
673
+ const strategy = _MockAdapter.strategies[schema._type];
674
+ if (strategy) {
675
+ return strategy.generate(schema);
676
+ }
677
+ logger.warn(`\u672A\u627E\u5230\u5BF9\u5E94\u7684\u7B56\u7565\u7C7B\u578B: ${schema._type}`);
678
+ return [];
679
+ }
680
+ };
681
+
682
+ // src/interceptor.ts
683
+ function installFetchMock(schema) {
684
+ if (!window._originalFetch) {
685
+ window._originalFetch = window.fetch;
686
+ }
687
+ window.fetch = async (input, init = {}) => {
688
+ const url = typeof input === "string" ? input : input instanceof URL ? input.toString() : input.url;
689
+ const method = (init.method || "GET").toUpperCase();
690
+ const rules = Object.values(schema);
691
+ const rule = rules.find((v) => {
692
+ if (!v.url) return false;
693
+ const pattern = v.url.replace(/:[a-zA-Z0-9_]+/g, "([^/]+)");
694
+ const regex = new RegExp(`^${pattern}$`);
695
+ const [path] = url.split("?");
696
+ const ruleMethod = (v.method || "GET").toUpperCase();
697
+ return regex.test(path) && ruleMethod === method;
698
+ });
699
+ if (!rule) {
700
+ return window._originalFetch(input, init);
701
+ }
702
+ console.log(`[Mock] Intercepted ${method} ${url}`, rule);
703
+ const status = rule.status || 200;
704
+ if (status !== 200) {
705
+ await sleep(rule.delay || 0);
706
+ return new Response(JSON.stringify({
707
+ message: `Mock error status ${status}`,
708
+ code: status
709
+ }), {
710
+ status,
711
+ headers: { "Content-Type": "application/json" }
712
+ });
713
+ }
714
+ await sleep(rule.delay || 0);
715
+ const type = rule.type || "json";
716
+ const strategy = StrategyFactory.getStrategy(type);
717
+ const urlObj = new URL(url, window.location.origin);
718
+ const query = Object.fromEntries(urlObj.searchParams);
719
+ const result = strategy.process(rule, query);
720
+ if (type === "json") {
721
+ return new Response(JSON.stringify(result), {
722
+ status,
723
+ headers: { "Content-Type": "application/json" }
724
+ });
725
+ }
726
+ if (type === "sse" || type === "sse-page") {
727
+ const events = result;
728
+ const stream = eventsToStream(events);
729
+ return new Response(stream, {
730
+ status,
731
+ headers: { "Content-Type": "text/event-stream" }
732
+ });
733
+ }
734
+ return window._originalFetch(input, init);
735
+ };
736
+ }
737
+ function installSSEMock() {
738
+ }
739
+ function setupMock(schema) {
740
+ if (typeof window !== "undefined") {
741
+ installFetchMock(schema);
742
+ installSSEMock();
743
+ }
744
+ }
745
+
746
+ // src/types.ts
747
+ function createChatStream(config) {
748
+ return { _type: "chat_stream", ...config };
749
+ }
750
+ function createHistoryStream(config) {
751
+ return { _type: "history_stream", ...config };
752
+ }
753
+
754
+ // src/index.ts
755
+ var MOCK_USER = {
756
+ id: "u_001",
757
+ name: "Admin User",
758
+ avatar: "https://api.dicebear.com/7.x/avataaars/svg?seed=Admin",
759
+ role: "admin"
760
+ };
761
+ var MOCK_SESSIONS = [
762
+ { id: "s_001", title: "2024 Q1 \u9500\u552E\u5206\u6790", date: "2024-03-15", lastMessage: "\u597D\u7684\uFF0C\u6B63\u5728\u4E3A\u60A8\u5206\u6790 Q1 \u9500\u552E\u6570\u636E..." },
763
+ { id: "s_002", title: "\u7528\u6237\u589E\u957F\u8D8B\u52BF", date: "2024-03-10", lastMessage: "\u7528\u6237\u589E\u957F\u66F2\u7EBF\u663E\u793A..." },
764
+ { id: "s_003", title: "\u7ADE\u54C1\u5206\u6790\u62A5\u544A", date: "2024-03-08", lastMessage: "\u4E3B\u8981\u7ADE\u54C1 A \u7684\u5E02\u573A\u4EFD\u989D..." },
765
+ { id: "s_004", title: "\u8425\u9500\u6D3B\u52A8\u590D\u76D8", date: "2024-03-05", lastMessage: "ROI \u63D0\u5347\u4E86 15%..." },
766
+ { id: "s_005", title: "\u8D22\u52A1\u62A5\u8868\u5BA1\u8BA1", date: "2024-03-01", lastMessage: "\u8BF7\u786E\u8BA4\u4EE5\u4E0B\u8D22\u52A1\u6307\u6807..." }
33
767
  ];
34
- export const MOCK_FAVORITES = [
35
- { id: 'fav-1', title: '季度销售总结', date: '2025/12/15' },
36
- { id: 'fav-2', title: '年度预算规划', date: '2025/12/10' },
37
- { id: 'fav-3', title: '核心指标监控', date: '2025/11/20' },
768
+ var MOCK_FAVORITES = [
769
+ { id: "fav-1", title: "\u5B63\u5EA6\u9500\u552E\u603B\u7ED3", date: "2025/12/15" },
770
+ { id: "fav-2", title: "\u5E74\u5EA6\u9884\u7B97\u89C4\u5212", date: "2025/12/10" },
771
+ { id: "fav-3", title: "\u6838\u5FC3\u6307\u6807\u76D1\u63A7", date: "2025/11/20" }
38
772
  ];
39
- export const MOCK_SCENES = [
40
- {
41
- id: '1',
42
- name: '销售数据分析',
43
- description: '全方位分析销售业绩,包括区域、产品、时间维度',
44
- code: 'SALES_001',
45
- creator: '管理员',
46
- createTime: '2023-01-01',
47
- tableCount: 5,
48
- kbCount: 2,
49
- qaCount: 10,
50
- cover: 'https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&q=80',
51
- },
52
- {
53
- id: '2',
54
- name: '人力资源概览',
55
- description: '员工入职、离职、绩效分布与培训情况分析',
56
- code: 'HR_001',
57
- creator: 'HR 经理',
58
- createTime: '2023-02-15',
59
- tableCount: 3,
60
- kbCount: 1,
61
- qaCount: 5,
62
- cover: 'https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80',
63
- },
64
- {
65
- id: '3',
66
- name: '供应链优化',
67
- description: '库存周转、物流成本与供应商绩效评估',
68
- code: 'SCM_001',
69
- creator: '供应链总监',
70
- createTime: '2023-03-20',
71
- tableCount: 8,
72
- kbCount: 0,
73
- qaCount: 15,
74
- cover: 'https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=800&q=80',
75
- },
773
+ var MOCK_SCENES = [
774
+ {
775
+ id: "1",
776
+ name: "\u9500\u552E\u6570\u636E\u5206\u6790",
777
+ description: "\u5168\u65B9\u4F4D\u5206\u6790\u9500\u552E\u4E1A\u7EE9\uFF0C\u5305\u62EC\u533A\u57DF\u3001\u4EA7\u54C1\u3001\u65F6\u95F4\u7EF4\u5EA6",
778
+ code: "SALES_001",
779
+ creator: "\u7BA1\u7406\u5458",
780
+ createTime: "2023-01-01",
781
+ tableCount: 5,
782
+ kbCount: 2,
783
+ qaCount: 10,
784
+ cover: "https://images.unsplash.com/photo-1551288049-bebda4e38f71?w=800&q=80"
785
+ },
786
+ {
787
+ id: "2",
788
+ name: "\u4EBA\u529B\u8D44\u6E90\u6982\u89C8",
789
+ description: "\u5458\u5DE5\u5165\u804C\u3001\u79BB\u804C\u3001\u7EE9\u6548\u5206\u5E03\u4E0E\u57F9\u8BAD\u60C5\u51B5\u5206\u6790",
790
+ code: "HR_001",
791
+ creator: "HR \u7ECF\u7406",
792
+ createTime: "2023-02-15",
793
+ tableCount: 3,
794
+ kbCount: 1,
795
+ qaCount: 5,
796
+ cover: "https://images.unsplash.com/photo-1460925895917-afdab827c52f?w=800&q=80"
797
+ },
798
+ {
799
+ id: "3",
800
+ name: "\u4F9B\u5E94\u94FE\u4F18\u5316",
801
+ description: "\u5E93\u5B58\u5468\u8F6C\u3001\u7269\u6D41\u6210\u672C\u4E0E\u4F9B\u5E94\u5546\u7EE9\u6548\u8BC4\u4F30",
802
+ code: "SCM_001",
803
+ creator: "\u4F9B\u5E94\u94FE\u603B\u76D1",
804
+ createTime: "2023-03-20",
805
+ tableCount: 8,
806
+ kbCount: 0,
807
+ qaCount: 15,
808
+ cover: "https://images.unsplash.com/photo-1586528116311-ad8dd3c8310d?w=800&q=80"
809
+ }
76
810
  ];
77
- export const generateMockMessages = (sessionId) => [
78
- {
79
- key: `msg_${sessionId}_1`,
80
- role: 'assistant',
81
- content: `您好!我是您的智能助手。当前会话 ID: ${sessionId}。请问有什么可以帮您?`,
82
- time: dateUtils.dayjs(dateUtils.now() - 10000).toISOString(),
83
- },
811
+ var generateMockMessages = (sessionId) => [
812
+ {
813
+ key: `msg_${sessionId}_1`,
814
+ role: "assistant",
815
+ content: `\u60A8\u597D\uFF01\u6211\u662F\u60A8\u7684\u667A\u80FD\u52A9\u624B\u3002\u5F53\u524D\u4F1A\u8BDD ID: ${sessionId}\u3002\u8BF7\u95EE\u6709\u4EC0\u4E48\u53EF\u4EE5\u5E2E\u60A8\uFF1F`,
816
+ time: import_core3.dateUtils.dayjs(import_core3.dateUtils.now() - 1e4).toISOString()
817
+ }
84
818
  ];
85
- export const mockData = {
86
- user: MOCK_USER,
87
- sessions: MOCK_SESSIONS,
88
- favorites: MOCK_FAVORITES,
89
- scenes: MOCK_SCENES,
90
- favoritesList: MOCK_FAVORITES, // Alias for compatibility if needed
819
+ var mockData = {
820
+ user: MOCK_USER,
821
+ sessions: MOCK_SESSIONS,
822
+ favorites: MOCK_FAVORITES,
823
+ scenes: MOCK_SCENES,
824
+ favoritesList: MOCK_FAVORITES
825
+ // Alias for compatibility if needed
91
826
  };
827
+ // Annotate the CommonJS export names for ESM import in node:
828
+ 0 && (module.exports = {
829
+ ChatStreamStrategy,
830
+ HistoryStreamStrategy,
831
+ JsonStrategy,
832
+ MOCK_FAVORITES,
833
+ MOCK_SCENES,
834
+ MOCK_SESSIONS,
835
+ MOCK_USER,
836
+ MockAdapter,
837
+ MockResponseGenerator,
838
+ SsePageStrategy,
839
+ SseStrategy,
840
+ StrategyFactory,
841
+ createChatStream,
842
+ createHistoryStream,
843
+ eventsToStream,
844
+ flatEvents,
845
+ generateMockMessages,
846
+ installFetchMock,
847
+ installSSEMock,
848
+ mockData,
849
+ processTemplate,
850
+ setupMock,
851
+ sleep
852
+ });
92
853
  //# sourceMappingURL=index.js.map