@composy/chat-core 0.0.1 → 0.0.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.
- package/README.md +187 -123
- package/dist/index.js +2018 -1035
- package/dist/index.js.map +1 -1
- package/dist/index.min.js +1370 -1644
- package/dist/index.min.js.map +1 -0
- package/es/.dts-output-manifest.json +1 -0
- package/es/.dts.tsbuildinfo +1 -0
- package/es/constants/dom.d.ts +3 -19
- package/es/constants/dom.js +4 -4
- package/es/constants/dom.js.map +1 -1
- package/es/core/chat-manager.d.ts +33 -22
- package/es/core/chat-manager.js +174 -50
- package/es/core/chat-manager.js.map +1 -1
- package/es/core/event-emitter.d.ts +0 -1
- package/es/core/event-emitter.js +14 -7
- package/es/core/event-emitter.js.map +1 -1
- package/es/core/mention-engine.d.ts +1 -2
- package/es/core/mention-engine.js +9 -9
- package/es/core/mention-engine.js.map +1 -1
- package/es/core/message-schema.d.ts +19 -0
- package/es/core/message-schema.js +197 -0
- package/es/core/message-schema.js.map +1 -0
- package/es/core/outbox.d.ts +63 -0
- package/es/core/outbox.js +160 -0
- package/es/core/outbox.js.map +1 -0
- package/es/core/transport.d.ts +79 -0
- package/es/core/transport.js +102 -0
- package/es/core/transport.js.map +1 -0
- package/es/index.d.ts +12 -7
- package/es/index.js +167 -36
- package/es/index.js.map +1 -1
- package/es/renderer/dom-renderer.d.ts +16 -4
- package/es/renderer/dom-renderer.js +316 -61
- package/es/renderer/dom-renderer.js.map +1 -1
- package/es/renderer/style-manager.d.ts +14 -38
- package/es/renderer/style-manager.js +92 -63
- package/es/renderer/style-manager.js.map +1 -1
- package/es/theme/theme-manager.d.ts +4 -3
- package/es/theme/theme-manager.js +19 -9
- package/es/theme/theme-manager.js.map +1 -1
- package/es/theme/tokens.d.ts +0 -1
- package/es/theme/tokens.js +92 -92
- package/es/theme/tokens.js.map +1 -1
- package/es/types/index.d.ts +104 -24
- package/es/types/index.js +8 -3
- package/es/types/index.js.map +1 -0
- package/esm/constants/dom.d.ts +3 -19
- package/esm/constants/dom.js +4 -4
- package/esm/constants/dom.js.map +1 -1
- package/esm/core/chat-manager.d.ts +33 -22
- package/esm/core/chat-manager.js +174 -50
- package/esm/core/chat-manager.js.map +1 -1
- package/esm/core/event-emitter.d.ts +0 -1
- package/esm/core/event-emitter.js +14 -7
- package/esm/core/event-emitter.js.map +1 -1
- package/esm/core/mention-engine.d.ts +1 -2
- package/esm/core/mention-engine.js +9 -9
- package/esm/core/mention-engine.js.map +1 -1
- package/esm/core/message-schema.d.ts +19 -0
- package/esm/core/message-schema.js +197 -0
- package/esm/core/message-schema.js.map +1 -0
- package/esm/core/outbox.d.ts +63 -0
- package/esm/core/outbox.js +160 -0
- package/esm/core/outbox.js.map +1 -0
- package/esm/core/transport.d.ts +79 -0
- package/esm/core/transport.js +102 -0
- package/esm/core/transport.js.map +1 -0
- package/esm/index.d.ts +12 -7
- package/esm/index.js +169 -38
- package/esm/index.js.map +1 -1
- package/esm/renderer/dom-renderer.d.ts +16 -4
- package/esm/renderer/dom-renderer.js +316 -61
- package/esm/renderer/dom-renderer.js.map +1 -1
- package/esm/renderer/style-manager.d.ts +14 -38
- package/esm/renderer/style-manager.js +92 -63
- package/esm/renderer/style-manager.js.map +1 -1
- package/esm/theme/theme-manager.d.ts +4 -3
- package/esm/theme/theme-manager.js +19 -9
- package/esm/theme/theme-manager.js.map +1 -1
- package/esm/theme/tokens.d.ts +0 -1
- package/esm/theme/tokens.js +92 -92
- package/esm/theme/tokens.js.map +1 -1
- package/esm/types/index.d.ts +104 -24
- package/esm/types/index.js +8 -3
- package/esm/types/index.js.map +1 -0
- package/lib/constants/dom.cjs +4 -4
- package/lib/constants/dom.cjs.map +1 -1
- package/lib/constants/dom.d.cts +25 -0
- package/lib/constants/dom.d.ts +3 -19
- package/lib/core/chat-manager.cjs +174 -50
- package/lib/core/chat-manager.cjs.map +1 -1
- package/lib/core/chat-manager.d.cts +45 -0
- package/lib/core/chat-manager.d.ts +33 -22
- package/lib/core/event-emitter.cjs +14 -7
- package/lib/core/event-emitter.cjs.map +1 -1
- package/lib/core/event-emitter.d.cts +47 -0
- package/lib/core/event-emitter.d.ts +0 -1
- package/lib/core/mention-engine.cjs +9 -9
- package/lib/core/mention-engine.cjs.map +1 -1
- package/lib/core/mention-engine.d.cts +40 -0
- package/lib/core/mention-engine.d.ts +1 -2
- package/lib/core/message-schema.cjs +202 -0
- package/lib/core/message-schema.cjs.map +1 -0
- package/lib/core/message-schema.d.cts +19 -0
- package/lib/core/message-schema.d.ts +19 -0
- package/lib/core/outbox.cjs +162 -0
- package/lib/core/outbox.cjs.map +1 -0
- package/lib/core/outbox.d.cts +63 -0
- package/lib/core/outbox.d.ts +63 -0
- package/lib/core/transport.cjs +103 -0
- package/lib/core/transport.cjs.map +1 -0
- package/lib/core/transport.d.cts +79 -0
- package/lib/core/transport.d.ts +79 -0
- package/lib/index.cjs +175 -35
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.cts +33 -0
- package/lib/index.d.ts +12 -7
- package/lib/renderer/dom-renderer.cjs +316 -61
- package/lib/renderer/dom-renderer.cjs.map +1 -1
- package/lib/renderer/dom-renderer.d.cts +91 -0
- package/lib/renderer/dom-renderer.d.ts +16 -4
- package/lib/renderer/style-manager.cjs +92 -62
- package/lib/renderer/style-manager.cjs.map +1 -1
- package/lib/renderer/style-manager.d.cts +34 -0
- package/lib/renderer/style-manager.d.ts +14 -38
- package/lib/theme/theme-manager.cjs +19 -9
- package/lib/theme/theme-manager.cjs.map +1 -1
- package/lib/theme/theme-manager.d.cts +34 -0
- package/lib/theme/theme-manager.d.ts +4 -3
- package/lib/theme/tokens.cjs +92 -92
- package/lib/theme/tokens.cjs.map +1 -1
- package/lib/theme/tokens.d.cts +56 -0
- package/lib/theme/tokens.d.ts +0 -1
- package/lib/types/index.cjs +8 -3
- package/lib/types/index.cjs.map +1 -0
- package/lib/types/index.d.cts +284 -0
- package/lib/types/index.d.ts +104 -24
- package/package.json +16 -13
- package/es/constants/dom.d.ts.map +0 -1
- package/es/core/chat-manager.d.ts.map +0 -1
- package/es/core/event-emitter.d.ts.map +0 -1
- package/es/core/mention-engine.d.ts.map +0 -1
- package/es/index.d.ts.map +0 -1
- package/es/renderer/dom-renderer.d.ts.map +0 -1
- package/es/renderer/style-manager.d.ts.map +0 -1
- package/es/theme/theme-manager.d.ts.map +0 -1
- package/es/theme/tokens.d.ts.map +0 -1
- package/es/types/index.d.ts.map +0 -1
- package/esm/constants/dom.d.ts.map +0 -1
- package/esm/core/chat-manager.d.ts.map +0 -1
- package/esm/core/event-emitter.d.ts.map +0 -1
- package/esm/core/mention-engine.d.ts.map +0 -1
- package/esm/index.d.ts.map +0 -1
- package/esm/renderer/dom-renderer.d.ts.map +0 -1
- package/esm/renderer/style-manager.d.ts.map +0 -1
- package/esm/theme/theme-manager.d.ts.map +0 -1
- package/esm/theme/tokens.d.ts.map +0 -1
- package/esm/types/index.d.ts.map +0 -1
- package/lib/constants/dom.d.ts.map +0 -1
- package/lib/core/chat-manager.d.ts.map +0 -1
- package/lib/core/event-emitter.d.ts.map +0 -1
- package/lib/core/mention-engine.d.ts.map +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/renderer/dom-renderer.d.ts.map +0 -1
- package/lib/renderer/style-manager.d.ts.map +0 -1
- package/lib/theme/theme-manager.d.ts.map +0 -1
- package/lib/theme/tokens.d.ts.map +0 -1
- package/lib/types/index.d.ts.map +0 -1
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* ***********************************
|
|
3
|
+
* @composy/chat-core v0.0.2 *
|
|
4
|
+
* Built with rollup *
|
|
5
|
+
* Build time: 2024-10-12 21:52:18 *
|
|
6
|
+
* Build mode: production *
|
|
7
|
+
* Minified: No *
|
|
8
|
+
* ***********************************
|
|
9
|
+
*/
|
|
10
|
+
//#region src/core/transport.ts
|
|
11
|
+
var ChatTransportController = class {
|
|
12
|
+
constructor(transport, options = {}) {
|
|
13
|
+
this.status = "idle";
|
|
14
|
+
this.unsubscribeEvents = null;
|
|
15
|
+
this.unsubscribeStatus = null;
|
|
16
|
+
this.destroyed = false;
|
|
17
|
+
this.connectPromise = null;
|
|
18
|
+
this.lifecycle = 0;
|
|
19
|
+
this.transport = transport;
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.cursor = options.cursor;
|
|
22
|
+
}
|
|
23
|
+
getStatus() {
|
|
24
|
+
return this.status;
|
|
25
|
+
}
|
|
26
|
+
getCursor() {
|
|
27
|
+
return this.cursor;
|
|
28
|
+
}
|
|
29
|
+
async connect(signal) {
|
|
30
|
+
if (this.destroyed) throw new Error("Chat transport controller is disposed.");
|
|
31
|
+
if (this.status === "connected") return;
|
|
32
|
+
if (this.connectPromise) return this.connectPromise;
|
|
33
|
+
const lifecycle = ++this.lifecycle;
|
|
34
|
+
this.setStatus("connecting");
|
|
35
|
+
this.connectPromise = (async () => {
|
|
36
|
+
this.unsubscribeEvents?.();
|
|
37
|
+
this.unsubscribeStatus?.();
|
|
38
|
+
this.unsubscribeEvents = this.transport.subscribe((event) => this.handleEvent(event));
|
|
39
|
+
this.unsubscribeStatus = this.transport.onStatusChange?.((status) => this.setStatus(status)) ?? null;
|
|
40
|
+
try {
|
|
41
|
+
await this.transport.connect({
|
|
42
|
+
conversationId: this.options.conversationId,
|
|
43
|
+
cursor: this.cursor,
|
|
44
|
+
signal
|
|
45
|
+
});
|
|
46
|
+
if (this.destroyed || lifecycle !== this.lifecycle) return;
|
|
47
|
+
this.setStatus("connected");
|
|
48
|
+
} catch (error) {
|
|
49
|
+
if (!this.destroyed && lifecycle === this.lifecycle) this.setStatus("error");
|
|
50
|
+
throw error;
|
|
51
|
+
} finally {
|
|
52
|
+
this.connectPromise = null;
|
|
53
|
+
}
|
|
54
|
+
})();
|
|
55
|
+
return this.connectPromise;
|
|
56
|
+
}
|
|
57
|
+
async disconnect() {
|
|
58
|
+
if (this.destroyed) return;
|
|
59
|
+
this.lifecycle += 1;
|
|
60
|
+
this.connectPromise = null;
|
|
61
|
+
try {
|
|
62
|
+
await this.transport.disconnect();
|
|
63
|
+
} finally {
|
|
64
|
+
this.setStatus("disconnected");
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
async send(message, options = {}) {
|
|
68
|
+
if (this.destroyed) throw new Error("Chat transport controller is disposed.");
|
|
69
|
+
if (this.status !== "connected") throw new Error(`Chat transport is not connected: ${this.status}`);
|
|
70
|
+
const result = await this.transport.send(message, options);
|
|
71
|
+
if (result && result.cursor) this.cursor = result.cursor;
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
dispose() {
|
|
75
|
+
if (this.destroyed) return;
|
|
76
|
+
this.destroyed = true;
|
|
77
|
+
this.lifecycle += 1;
|
|
78
|
+
this.unsubscribeEvents?.();
|
|
79
|
+
this.unsubscribeStatus?.();
|
|
80
|
+
this.unsubscribeEvents = null;
|
|
81
|
+
this.unsubscribeStatus = null;
|
|
82
|
+
this.connectPromise = null;
|
|
83
|
+
Promise.resolve(this.transport.disconnect()).catch(() => void 0);
|
|
84
|
+
this.setStatus("disconnected");
|
|
85
|
+
}
|
|
86
|
+
handleEvent(event) {
|
|
87
|
+
if (this.destroyed) return;
|
|
88
|
+
if ("cursor" in event && event.cursor) this.cursor = event.cursor;
|
|
89
|
+
if (event.type === "ack" && event.ack.cursor) this.cursor = event.ack.cursor;
|
|
90
|
+
if (event.type === "error" && !event.recoverable) this.setStatus("error");
|
|
91
|
+
this.options.onEvent?.(event);
|
|
92
|
+
}
|
|
93
|
+
setStatus(status) {
|
|
94
|
+
if (this.status === status) return;
|
|
95
|
+
this.status = status;
|
|
96
|
+
this.options.onStatusChange?.(status);
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
//#endregion
|
|
100
|
+
export { ChatTransportController };
|
|
101
|
+
/*! End of @composy/chat-core | Powered by @composy/builder */
|
|
102
|
+
//# sourceMappingURL=transport.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transport.js","names":[],"sources":["../../src/core/transport.ts"],"sourcesContent":["import type { ChatMessage } from '../types'\n\n/** transport 连接状态。 */\nexport type ChatTransportStatus =\n 'idle' | 'connecting' | 'connected' | 'disconnected' | 'error'\n\n/** 建立 transport 时传入的同步上下文。 */\nexport interface ChatTransportContext {\n conversationId?: string\n cursor?: string\n signal?: AbortSignal\n}\n\n/** transport ack,可携带服务端补全后的消息和同步序号。 */\nexport interface ChatTransportAck {\n clientMessageId: string\n message?: Partial<ChatMessage>\n sequence?: number\n cursor?: string\n}\n\n/** transport 推送的统一事件协议。 */\nexport type ChatTransportEvent =\n | {\n type: 'message'\n message: ChatMessage\n sequence?: number\n cursor?: string\n }\n | { type: 'ack'; ack: ChatTransportAck }\n | { type: 'cursor'; cursor: string }\n | { type: 'error'; error: unknown; recoverable?: boolean }\n\n/** 可由 HTTP/SSE/WebSocket/原生 App bridge 实现的最小 transport 协议。 */\nexport interface ChatTransport {\n connect: (context?: ChatTransportContext) => void | Promise<void>\n disconnect: () => void | Promise<void>\n send: (\n message: ChatMessage,\n options?: { signal?: AbortSignal; clientMessageId?: string }\n ) => Promise<ChatTransportAck | void>\n subscribe: (listener: (event: ChatTransportEvent) => void) => () => void\n onStatusChange?: (\n listener: (status: ChatTransportStatus) => void\n ) => () => void\n}\n\nexport interface ChatTransportControllerOptions {\n conversationId?: string\n cursor?: string\n onEvent?: (event: ChatTransportEvent) => void\n onStatusChange?: (status: ChatTransportStatus) => void\n}\n\n/**\n * 连接生命周期、游标和外部 transport 事件的统一控制器。\n *\n * Controller 不假设网络实现,负责避免重复 connect、转发状态、保存 cursor,\n * 并在 dispose 后拒绝迟到的异步结果。\n */\nexport class ChatTransportController {\n private readonly transport: ChatTransport\n private readonly options: ChatTransportControllerOptions\n private status: ChatTransportStatus = 'idle'\n private cursor?: string\n private unsubscribeEvents: (() => void) | null = null\n private unsubscribeStatus: (() => void) | null = null\n private destroyed = false\n private connectPromise: Promise<void> | null = null\n private lifecycle = 0\n\n constructor(\n transport: ChatTransport,\n options: ChatTransportControllerOptions = {}\n ) {\n this.transport = transport\n this.options = options\n this.cursor = options.cursor\n }\n\n getStatus(): ChatTransportStatus {\n return this.status\n }\n\n getCursor(): string | undefined {\n return this.cursor\n }\n\n async connect(signal?: AbortSignal): Promise<void> {\n if (this.destroyed)\n throw new Error('Chat transport controller is disposed.')\n if (this.status === 'connected') return\n if (this.connectPromise) return this.connectPromise\n\n const lifecycle = ++this.lifecycle\n this.setStatus('connecting')\n this.connectPromise = (async () => {\n this.unsubscribeEvents?.()\n this.unsubscribeStatus?.()\n this.unsubscribeEvents = this.transport.subscribe(event =>\n this.handleEvent(event)\n )\n this.unsubscribeStatus =\n this.transport.onStatusChange?.(status => this.setStatus(status)) ??\n null\n try {\n await this.transport.connect({\n conversationId: this.options.conversationId,\n cursor: this.cursor,\n signal,\n })\n if (this.destroyed || lifecycle !== this.lifecycle) return\n this.setStatus('connected')\n } catch (error) {\n if (!this.destroyed && lifecycle === this.lifecycle) {\n this.setStatus('error')\n }\n throw error\n } finally {\n this.connectPromise = null\n }\n })()\n\n return this.connectPromise\n }\n\n async disconnect(): Promise<void> {\n if (this.destroyed) return\n this.lifecycle += 1\n this.connectPromise = null\n try {\n await this.transport.disconnect()\n } finally {\n this.setStatus('disconnected')\n }\n }\n\n async send(\n message: ChatMessage,\n options: { signal?: AbortSignal; clientMessageId?: string } = {}\n ): Promise<ChatTransportAck | void> {\n if (this.destroyed)\n throw new Error('Chat transport controller is disposed.')\n if (this.status !== 'connected') {\n throw new Error(`Chat transport is not connected: ${this.status}`)\n }\n const result = await this.transport.send(message, options)\n if (result && result.cursor) this.cursor = result.cursor\n return result\n }\n\n dispose(): void {\n if (this.destroyed) return\n this.destroyed = true\n this.lifecycle += 1\n this.unsubscribeEvents?.()\n this.unsubscribeStatus?.()\n this.unsubscribeEvents = null\n this.unsubscribeStatus = null\n this.connectPromise = null\n void Promise.resolve(this.transport.disconnect()).catch(() => undefined)\n this.setStatus('disconnected')\n }\n\n private handleEvent(event: ChatTransportEvent): void {\n if (this.destroyed) return\n if ('cursor' in event && event.cursor) this.cursor = event.cursor\n if (event.type === 'ack' && event.ack.cursor) {\n this.cursor = event.ack.cursor\n }\n if (event.type === 'error' && !event.recoverable) this.setStatus('error')\n this.options.onEvent?.(event)\n }\n\n private setStatus(status: ChatTransportStatus): void {\n if (this.status === status) return\n this.status = status\n this.options.onStatusChange?.(status)\n }\n}\n"],"mappings":";;;;;;;;;;AA4DO,IAAM,0BAAN,MAA8B;CAWnC,YACE,WACA,UAA0C,CAAC,GAC3C;EAXF,KAAQ,SAA8B;EAEtC,KAAQ,oBAAyC;EACjD,KAAQ,oBAAyC;EACjD,KAAQ,YAAY;EACpB,KAAQ,iBAAuC;EAC/C,KAAQ,YAAY;EAMlB,KAAK,YAAY;EACjB,KAAK,UAAU;EACf,KAAK,SAAS,QAAQ;CACxB;CAEA,YAAiC;EAC/B,OAAO,KAAK;CACd;CAEA,YAAgC;EAC9B,OAAO,KAAK;CACd;CAEA,MAAM,QAAQ,QAAqC;EACjD,IAAI,KAAK,WACP,MAAM,IAAI,MAAM,wCAAwC;EAC1D,IAAI,KAAK,WAAW,aAAa;EACjC,IAAI,KAAK,gBAAgB,OAAO,KAAK;EAErC,MAAM,YAAY,EAAE,KAAK;EACzB,KAAK,UAAU,YAAY;EAC3B,KAAK,kBAAkB,YAAY;GACjC,KAAK,oBAAoB;GACzB,KAAK,oBAAoB;GACzB,KAAK,oBAAoB,KAAK,UAAU,WAAU,UAChD,KAAK,YAAY,KAAK,CACxB;GACA,KAAK,oBACH,KAAK,UAAU,kBAAiB,WAAU,KAAK,UAAU,MAAM,CAAC,KAChE;GACF,IAAI;IACF,MAAM,KAAK,UAAU,QAAQ;KAC3B,gBAAgB,KAAK,QAAQ;KAC7B,QAAQ,KAAK;KACb;IACF,CAAC;IACD,IAAI,KAAK,aAAa,cAAc,KAAK,WAAW;IACpD,KAAK,UAAU,WAAW;GAC5B,SAAS,OAAO;IACd,IAAI,CAAC,KAAK,aAAa,cAAc,KAAK,WACxC,KAAK,UAAU,OAAO;IAExB,MAAM;GACR,UAAE;IACA,KAAK,iBAAiB;GACxB;EACF,EAAA,CAAG;EAEH,OAAO,KAAK;CACd;CAEA,MAAM,aAA4B;EAChC,IAAI,KAAK,WAAW;EACpB,KAAK,aAAa;EAClB,KAAK,iBAAiB;EACtB,IAAI;GACF,MAAM,KAAK,UAAU,WAAW;EAClC,UAAE;GACA,KAAK,UAAU,cAAc;EAC/B;CACF;CAEA,MAAM,KACJ,SACA,UAA8D,CAAC,GAC7B;EAClC,IAAI,KAAK,WACP,MAAM,IAAI,MAAM,wCAAwC;EAC1D,IAAI,KAAK,WAAW,aAClB,MAAM,IAAI,MAAM,oCAAoC,KAAK,QAAQ;EAEnE,MAAM,SAAS,MAAM,KAAK,UAAU,KAAK,SAAS,OAAO;EACzD,IAAI,UAAU,OAAO,QAAQ,KAAK,SAAS,OAAO;EAClD,OAAO;CACT;CAEA,UAAgB;EACd,IAAI,KAAK,WAAW;EACpB,KAAK,YAAY;EACjB,KAAK,aAAa;EAClB,KAAK,oBAAoB;EACzB,KAAK,oBAAoB;EACzB,KAAK,oBAAoB;EACzB,KAAK,oBAAoB;EACzB,KAAK,iBAAiB;EACtB,QAAa,QAAQ,KAAK,UAAU,WAAW,CAAC,CAAA,CAAE,YAAY,KAAA,CAAS;EACvE,KAAK,UAAU,cAAc;CAC/B;CAEQ,YAAY,OAAiC;EACnD,IAAI,KAAK,WAAW;EACpB,IAAI,YAAY,SAAS,MAAM,QAAQ,KAAK,SAAS,MAAM;EAC3D,IAAI,MAAM,SAAS,SAAS,MAAM,IAAI,QACpC,KAAK,SAAS,MAAM,IAAI;EAE1B,IAAI,MAAM,SAAS,WAAW,CAAC,MAAM,aAAa,KAAK,UAAU,OAAO;EACxE,KAAK,QAAQ,UAAU,KAAK;CAC9B;CAEQ,UAAU,QAAmC;EACnD,IAAI,KAAK,WAAW,QAAQ;EAC5B,KAAK,SAAS;EACd,KAAK,QAAQ,iBAAiB,MAAM;CACtC;AACF"}
|
package/es/index.d.ts
CHANGED
|
@@ -10,19 +10,24 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import type { ChatConfig, ChatInstance } from './types';
|
|
12
12
|
export declare const version = "0.1.0";
|
|
13
|
-
export
|
|
14
|
-
export { EventEmitter } from './core/event-emitter';
|
|
13
|
+
export { COMPONENT_CSS_VAR_PREFIX, cx, DEFAULT_CLASS_PREFIX, getStyleElementId, normalizeClassPrefix, STYLE_ELEMENT_ID, } from './constants/dom';
|
|
15
14
|
export { ChatManager } from './core/chat-manager';
|
|
15
|
+
export type { MessageMergeOptions, MessageMergeResult, StreamAppendOptions, } from './core/chat-manager';
|
|
16
|
+
export { EventEmitter } from './core/event-emitter';
|
|
16
17
|
export { MentionEngine } from './core/mention-engine';
|
|
17
18
|
export type { MentionState } from './core/mention-engine';
|
|
19
|
+
export { cloneChatMessage, compareChatMessages, normalizeChatContentBlocks, normalizeChatMessage, normalizeChatMessages, } from './core/message-schema';
|
|
20
|
+
export { ChatOutbox, MemoryChatOutboxStorage } from './core/outbox';
|
|
21
|
+
export type { ChatOutboxEntry, ChatOutboxFlushOptions, ChatOutboxFlushResult, ChatOutboxOptions, ChatOutboxStorage, } from './core/outbox';
|
|
22
|
+
export { ChatTransportController } from './core/transport';
|
|
23
|
+
export type { ChatTransport, ChatTransportAck, ChatTransportContext, ChatTransportControllerOptions, ChatTransportEvent, ChatTransportStatus, } from './core/transport';
|
|
24
|
+
export { DOMRenderer } from './renderer/dom-renderer';
|
|
25
|
+
export { cls, clsx, injectStyles, removeStyles, updateStyles, } from './renderer/style-manager';
|
|
18
26
|
export { ThemeManager } from './theme/theme-manager';
|
|
19
27
|
export type { ThemeTokens } from './theme/tokens';
|
|
20
|
-
export {
|
|
21
|
-
export
|
|
22
|
-
export { injectStyles, updateStyles, removeStyles, cls, clsx } from './renderer/style-manager';
|
|
23
|
-
export { DEFAULT_CLASS_PREFIX, COMPONENT_CSS_VAR_PREFIX, STYLE_ELEMENT_ID, getStyleElementId, normalizeClassPrefix, cx, } from './constants/dom';
|
|
28
|
+
export { darkTokens, lightTokens } from './theme/tokens';
|
|
29
|
+
export * from './types';
|
|
24
30
|
/**
|
|
25
31
|
* 创建聊天实例
|
|
26
32
|
*/
|
|
27
33
|
export declare function createChat(config: ChatConfig): ChatInstance;
|
|
28
|
-
//# sourceMappingURL=index.d.ts.map
|
package/es/index.js
CHANGED
|
@@ -1,25 +1,34 @@
|
|
|
1
1
|
/*!
|
|
2
2
|
* ***********************************
|
|
3
|
-
* @composy/chat-core v0.0.
|
|
3
|
+
* @composy/chat-core v0.0.2 *
|
|
4
4
|
* Built with rollup *
|
|
5
|
-
* Build time: 2024-
|
|
5
|
+
* Build time: 2024-10-12 21:52:18 *
|
|
6
6
|
* Build mode: production *
|
|
7
7
|
* Minified: No *
|
|
8
8
|
* ***********************************
|
|
9
9
|
*/
|
|
10
10
|
import { COMPONENT_CSS_VAR_PREFIX, DEFAULT_CLASS_PREFIX, STYLE_ELEMENT_ID, cx, getStyleElementId, normalizeClassPrefix } from "./constants/dom.js";
|
|
11
|
+
import { CHAT_MESSAGE_SCHEMA_VERSION } from "./types/index.js";
|
|
12
|
+
import { cloneChatMessage, compareChatMessages, normalizeChatContentBlocks, normalizeChatMessage, normalizeChatMessages } from "./core/message-schema.js";
|
|
11
13
|
import { ChatManager } from "./core/chat-manager.js";
|
|
12
14
|
import { EventEmitter } from "./core/event-emitter.js";
|
|
13
15
|
import { MentionEngine } from "./core/mention-engine.js";
|
|
16
|
+
import { ChatOutbox, MemoryChatOutboxStorage } from "./core/outbox.js";
|
|
17
|
+
import { ChatTransportController } from "./core/transport.js";
|
|
18
|
+
import { cls, clsx, injectStyles, removeStyles, updateStyles } from "./renderer/style-manager.js";
|
|
19
|
+
import { DOMRenderer } from "./renderer/dom-renderer.js";
|
|
14
20
|
import { darkTokens, lightTokens } from "./theme/tokens.js";
|
|
15
21
|
import { ThemeManager } from "./theme/theme-manager.js";
|
|
16
|
-
import { DOMRenderer } from "./renderer/dom-renderer.js";
|
|
17
|
-
import { cls, clsx, injectStyles, removeStyles, updateStyles } from "./renderer/style-manager.js";
|
|
18
22
|
//#region src/index.ts
|
|
19
23
|
const version = "0.1.0";
|
|
20
24
|
function createChat(config) {
|
|
21
|
-
|
|
25
|
+
let container;
|
|
26
|
+
if (typeof config.container === "string") {
|
|
27
|
+
if (typeof document === "undefined") throw new Error("[Chat] A browser Document is required to resolve a container selector.");
|
|
28
|
+
container = document.querySelector(config.container);
|
|
29
|
+
} else container = config.container;
|
|
22
30
|
if (!container) throw new Error(`[Chat] Container not found: ${config.container}`);
|
|
31
|
+
const ownerDocument = container.ownerDocument;
|
|
23
32
|
const prefix = normalizeClassPrefix(config.classPrefix ?? "ldesign-chat");
|
|
24
33
|
const normalizedConfig = {
|
|
25
34
|
...config,
|
|
@@ -28,23 +37,70 @@ function createChat(config) {
|
|
|
28
37
|
const emitter = new EventEmitter();
|
|
29
38
|
const chatManager = new ChatManager(emitter, normalizedConfig.messages);
|
|
30
39
|
const mentionEngine = new MentionEngine(emitter, normalizedConfig.mentionMembers);
|
|
31
|
-
const themeManager = new ThemeManager(emitter, normalizedConfig.theme ?? "light");
|
|
40
|
+
const themeManager = new ThemeManager(emitter, normalizedConfig.theme ?? "light", ownerDocument.defaultView);
|
|
32
41
|
const renderer = new DOMRenderer(container, normalizedConfig, emitter, mentionEngine);
|
|
33
|
-
|
|
42
|
+
let destroyed = false;
|
|
43
|
+
const schedule = (callback) => {
|
|
44
|
+
const run = () => {
|
|
45
|
+
if (!destroyed) callback();
|
|
46
|
+
};
|
|
47
|
+
if (ownerDocument.defaultView?.requestAnimationFrame) ownerDocument.defaultView.requestAnimationFrame(run);
|
|
48
|
+
else setTimeout(run, 0);
|
|
49
|
+
};
|
|
34
50
|
renderer.init();
|
|
35
51
|
renderer.renderMessages(chatManager.getMessages());
|
|
36
|
-
|
|
52
|
+
renderer.setThemeTokens(themeManager.getTokens());
|
|
53
|
+
injectStyles(themeManager.getTokens(), prefix, renderer.getRootElement());
|
|
54
|
+
const applyTransportAck = async (ack) => {
|
|
55
|
+
const localId = chatManager.getMessageIdByClientMessageId(ack.clientMessageId);
|
|
56
|
+
if (localId) chatManager.updateMessage(localId, {
|
|
57
|
+
...ack.message ?? {},
|
|
58
|
+
id: localId,
|
|
59
|
+
clientMessageId: ack.clientMessageId,
|
|
60
|
+
status: "sent",
|
|
61
|
+
...ack.sequence !== void 0 && { sequence: ack.sequence },
|
|
62
|
+
...ack.cursor !== void 0 && { cursor: ack.cursor }
|
|
63
|
+
});
|
|
64
|
+
if (normalizedConfig.outbox) await normalizedConfig.outbox.remove(ack.clientMessageId);
|
|
65
|
+
emitter.emit("transport-ack", ack);
|
|
66
|
+
};
|
|
67
|
+
const handleTransportEvent = (event) => {
|
|
68
|
+
if (event.type === "message") chatManager.upsertMessage({
|
|
69
|
+
...event.message,
|
|
70
|
+
...event.cursor !== void 0 && { cursor: event.cursor }
|
|
71
|
+
}, {
|
|
72
|
+
sequence: event.sequence,
|
|
73
|
+
source: "remote"
|
|
74
|
+
});
|
|
75
|
+
else if (event.type === "ack") applyTransportAck(event.ack).catch((error) => {
|
|
76
|
+
emitter.emit("transport-error", error);
|
|
77
|
+
});
|
|
78
|
+
else if (event.type === "cursor") emitter.emit("transport-cursor", event.cursor);
|
|
79
|
+
else emitter.emit("transport-error", event.error, event.recoverable);
|
|
80
|
+
};
|
|
81
|
+
const transportController = normalizedConfig.transport ? new ChatTransportController(normalizedConfig.transport, {
|
|
82
|
+
conversationId: normalizedConfig.conversationId,
|
|
83
|
+
cursor: normalizedConfig.transportCursor,
|
|
84
|
+
onEvent: handleTransportEvent,
|
|
85
|
+
onStatusChange: (status) => {
|
|
86
|
+
emitter.emit("transport-status", status);
|
|
87
|
+
}
|
|
88
|
+
}) : null;
|
|
89
|
+
schedule(() => {
|
|
37
90
|
renderer.scrollToBottom(false);
|
|
38
91
|
});
|
|
39
92
|
emitter.on("theme-change", (_resolved, tokens) => {
|
|
40
|
-
|
|
93
|
+
renderer.setThemeTokens(tokens);
|
|
41
94
|
});
|
|
42
95
|
emitter.on("message-added", (message) => {
|
|
43
96
|
renderer.appendMessage(message);
|
|
44
|
-
|
|
97
|
+
schedule(() => {
|
|
45
98
|
renderer.scrollToBottom(true);
|
|
46
99
|
});
|
|
47
100
|
});
|
|
101
|
+
emitter.on("mention-select", (member) => {
|
|
102
|
+
normalizedConfig.onMentionSelect?.(member);
|
|
103
|
+
});
|
|
48
104
|
emitter.on("messages-prepended", (messages) => {
|
|
49
105
|
renderer.prependMessages(messages);
|
|
50
106
|
});
|
|
@@ -56,85 +112,160 @@ function createChat(config) {
|
|
|
56
112
|
});
|
|
57
113
|
emitter.on("message-content-appended", (id, content) => {
|
|
58
114
|
renderer.updateMessageContent(id, content);
|
|
59
|
-
|
|
115
|
+
schedule(() => {
|
|
60
116
|
renderer.scrollToBottom(false);
|
|
61
117
|
});
|
|
62
118
|
});
|
|
63
|
-
|
|
119
|
+
const instance = {
|
|
64
120
|
addMessage(message) {
|
|
65
|
-
chatManager.addMessage(message);
|
|
121
|
+
if (!destroyed) chatManager.addMessage(message);
|
|
66
122
|
},
|
|
67
123
|
prependMessages(messages) {
|
|
68
|
-
chatManager.prependMessages(messages);
|
|
124
|
+
if (!destroyed) chatManager.prependMessages(messages);
|
|
69
125
|
},
|
|
70
126
|
updateMessage(id, updates) {
|
|
71
|
-
chatManager.updateMessage(id, updates);
|
|
127
|
+
if (!destroyed) chatManager.updateMessage(id, updates);
|
|
72
128
|
},
|
|
73
129
|
removeMessage(id) {
|
|
74
|
-
chatManager.removeMessage(id);
|
|
130
|
+
if (!destroyed) chatManager.removeMessage(id);
|
|
75
131
|
},
|
|
76
132
|
setMessages(messages) {
|
|
133
|
+
if (destroyed) return;
|
|
77
134
|
chatManager.setMessages(messages);
|
|
78
135
|
renderer.renderMessages(chatManager.getMessages());
|
|
79
|
-
|
|
136
|
+
schedule(() => {
|
|
80
137
|
renderer.scrollToBottom(false);
|
|
81
138
|
});
|
|
82
139
|
},
|
|
83
140
|
clearMessages() {
|
|
84
|
-
|
|
85
|
-
|
|
141
|
+
if (!destroyed) {
|
|
142
|
+
chatManager.clearMessages();
|
|
143
|
+
renderer.renderMessages([]);
|
|
144
|
+
}
|
|
86
145
|
},
|
|
87
146
|
scrollToBottom(smooth = true) {
|
|
88
|
-
renderer.scrollToBottom(smooth);
|
|
147
|
+
if (!destroyed) renderer.scrollToBottom(smooth);
|
|
89
148
|
},
|
|
90
149
|
setTheme(theme) {
|
|
91
|
-
themeManager.setTheme(theme);
|
|
150
|
+
if (!destroyed) themeManager.setTheme(theme);
|
|
92
151
|
},
|
|
93
152
|
setMentionMembers(members) {
|
|
94
|
-
mentionEngine.setMembers(members);
|
|
153
|
+
if (!destroyed) mentionEngine.setMembers(members);
|
|
95
154
|
},
|
|
96
155
|
setLoadingMore(loading) {
|
|
97
|
-
renderer.setLoadingMore(loading);
|
|
156
|
+
if (!destroyed) renderer.setLoadingMore(loading);
|
|
98
157
|
},
|
|
99
158
|
focusInput() {
|
|
100
|
-
renderer.focusInput();
|
|
159
|
+
if (!destroyed) renderer.focusInput();
|
|
101
160
|
},
|
|
102
161
|
setInputContent(content) {
|
|
103
|
-
renderer.setInputContent(content);
|
|
162
|
+
if (!destroyed) renderer.setInputContent(content);
|
|
104
163
|
},
|
|
105
164
|
getInputContent() {
|
|
106
|
-
return renderer.getInputContent();
|
|
165
|
+
return destroyed ? "" : renderer.getInputContent();
|
|
107
166
|
},
|
|
108
167
|
clearInput() {
|
|
109
|
-
renderer.clearInput();
|
|
168
|
+
if (!destroyed) renderer.clearInput();
|
|
110
169
|
},
|
|
111
170
|
isAtBottom(threshold) {
|
|
112
|
-
return renderer.isAtBottom(threshold);
|
|
171
|
+
return destroyed || renderer.isAtBottom(threshold);
|
|
113
172
|
},
|
|
114
173
|
on(event, handler) {
|
|
115
|
-
return emitter.on(event, handler);
|
|
174
|
+
return destroyed ? () => {} : emitter.on(event, handler);
|
|
116
175
|
},
|
|
117
176
|
getMessages() {
|
|
118
|
-
return chatManager.getMessages();
|
|
177
|
+
return destroyed ? [] : chatManager.getMessages();
|
|
119
178
|
},
|
|
120
179
|
getMessage(id) {
|
|
121
|
-
return chatManager.getMessage(id);
|
|
180
|
+
return destroyed ? void 0 : chatManager.getMessage(id);
|
|
122
181
|
},
|
|
123
182
|
appendMessageContent(id, chunk) {
|
|
124
|
-
chatManager.appendMessageContent(id, chunk);
|
|
183
|
+
return destroyed ? false : chatManager.appendMessageContent(id, chunk);
|
|
125
184
|
},
|
|
126
|
-
finishStreaming(id) {
|
|
127
|
-
chatManager.finishStreaming(id);
|
|
185
|
+
finishStreaming(id, generation) {
|
|
186
|
+
return destroyed ? false : chatManager.finishStreaming(id, generation);
|
|
187
|
+
},
|
|
188
|
+
beginStreaming(id, generation) {
|
|
189
|
+
return destroyed ? null : chatManager.beginStreaming(id, generation);
|
|
190
|
+
},
|
|
191
|
+
cancelStreaming(id, generation) {
|
|
192
|
+
return destroyed ? false : chatManager.cancelStreaming(id, generation);
|
|
193
|
+
},
|
|
194
|
+
mergeMessage(message, sequence) {
|
|
195
|
+
return destroyed ? "ignored" : chatManager.upsertMessage(message, {
|
|
196
|
+
sequence,
|
|
197
|
+
source: "remote"
|
|
198
|
+
});
|
|
199
|
+
},
|
|
200
|
+
async connectTransport(signal) {
|
|
201
|
+
if (!transportController) throw new Error("No chat transport is configured.");
|
|
202
|
+
await transportController.connect(signal);
|
|
203
|
+
},
|
|
204
|
+
async disconnectTransport() {
|
|
205
|
+
await transportController?.disconnect();
|
|
206
|
+
},
|
|
207
|
+
getTransportStatus() {
|
|
208
|
+
return transportController?.getStatus() ?? "idle";
|
|
209
|
+
},
|
|
210
|
+
async sendMessage(message, options = {}) {
|
|
211
|
+
if (!transportController) throw new Error("No chat transport is configured.");
|
|
212
|
+
if (destroyed) throw new Error("Chat instance is destroyed.");
|
|
213
|
+
const prepared = normalizeChatMessage({
|
|
214
|
+
...message,
|
|
215
|
+
clientMessageId: message.clientMessageId ?? createClientMessageId(message.id),
|
|
216
|
+
status: message.status ?? "sending"
|
|
217
|
+
});
|
|
218
|
+
chatManager.addMessage(prepared);
|
|
219
|
+
try {
|
|
220
|
+
if (normalizedConfig.outbox) await normalizedConfig.outbox.enqueue(prepared);
|
|
221
|
+
const ack = await transportController.send(prepared, {
|
|
222
|
+
signal: options.signal,
|
|
223
|
+
clientMessageId: prepared.clientMessageId
|
|
224
|
+
});
|
|
225
|
+
if (ack) await applyTransportAck(ack);
|
|
226
|
+
else chatManager.markMessageStatus(prepared.id, "sent");
|
|
227
|
+
emitter.emit("message-sent", prepared, ack);
|
|
228
|
+
return ack;
|
|
229
|
+
} catch (error) {
|
|
230
|
+
chatManager.markMessageStatus(prepared.id, "failed");
|
|
231
|
+
emitter.emit("message-send-failed", prepared, error);
|
|
232
|
+
throw error;
|
|
233
|
+
}
|
|
234
|
+
},
|
|
235
|
+
async flushOutbox(options = {}) {
|
|
236
|
+
if (!normalizedConfig.outbox) return {
|
|
237
|
+
sent: [],
|
|
238
|
+
failed: [],
|
|
239
|
+
remaining: []
|
|
240
|
+
};
|
|
241
|
+
if (!transportController) throw new Error("No chat transport is configured.");
|
|
242
|
+
return normalizedConfig.outbox.flush(async (message, sendOptions) => {
|
|
243
|
+
const ack = await transportController.send(message, sendOptions);
|
|
244
|
+
if (ack) await applyTransportAck(ack);
|
|
245
|
+
else if (message.id) chatManager.markMessageStatus(message.id, "sent");
|
|
246
|
+
}, options);
|
|
128
247
|
},
|
|
129
248
|
destroy() {
|
|
249
|
+
if (destroyed) return;
|
|
250
|
+
destroyed = true;
|
|
251
|
+
transportController?.dispose();
|
|
130
252
|
themeManager.destroy();
|
|
131
253
|
renderer.destroy();
|
|
132
254
|
emitter.removeAll();
|
|
133
|
-
removeStyles(prefix);
|
|
255
|
+
removeStyles(prefix, ownerDocument);
|
|
134
256
|
}
|
|
135
257
|
};
|
|
258
|
+
if (normalizedConfig.autoConnect && transportController) instance.connectTransport().catch((error) => {
|
|
259
|
+
emitter.emit("transport-error", error);
|
|
260
|
+
});
|
|
261
|
+
return instance;
|
|
262
|
+
}
|
|
263
|
+
function createClientMessageId(messageId) {
|
|
264
|
+
const cryptoObject = globalThis.crypto;
|
|
265
|
+
if (cryptoObject?.randomUUID) return cryptoObject.randomUUID();
|
|
266
|
+
return `client-${messageId}-${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
136
267
|
}
|
|
137
268
|
//#endregion
|
|
138
|
-
export { COMPONENT_CSS_VAR_PREFIX, ChatManager, DEFAULT_CLASS_PREFIX, DOMRenderer, EventEmitter, MentionEngine, STYLE_ELEMENT_ID, ThemeManager, cls, clsx, createChat, cx, darkTokens, getStyleElementId, injectStyles, lightTokens, normalizeClassPrefix, removeStyles, updateStyles, version };
|
|
269
|
+
export { CHAT_MESSAGE_SCHEMA_VERSION, COMPONENT_CSS_VAR_PREFIX, ChatManager, ChatOutbox, ChatTransportController, DEFAULT_CLASS_PREFIX, DOMRenderer, EventEmitter, MemoryChatOutboxStorage, MentionEngine, STYLE_ELEMENT_ID, ThemeManager, cloneChatMessage, cls, clsx, compareChatMessages, createChat, cx, darkTokens, getStyleElementId, injectStyles, lightTokens, normalizeChatContentBlocks, normalizeChatMessage, normalizeChatMessages, normalizeClassPrefix, removeStyles, updateStyles, version };
|
|
139
270
|
/*! End of @composy/chat-core | Powered by @composy/builder */
|
|
140
271
|
//# sourceMappingURL=index.js.map
|
package/es/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @composy/chat-core - 即时通讯/IM 组件核心库\n *\n * 提供聊天气泡、消息列表、@提及、多消息类型(文本/图片/文件/系统消息/自定义)、\n * 消息状态管理(发送中/已发送/已送达/已读/失败)、亮暗主题切换等能力。\n * 框架无关的核心实现,配合 Vue/React 适配层使用。\n *\n * @packageDocumentation\n * @module @composy/chat-core\n */\n\nimport type { ChatConfig, ChatInstance, ChatMessage, ThemeMode, MentionItem, ToolbarConfig } from './types';\nimport type { ThemeTokens } from './theme/tokens';\nimport { EventEmitter } from './core/event-emitter';\nimport { ChatManager } from './core/chat-manager';\nimport { MentionEngine } from './core/mention-engine';\nimport { ThemeManager } from './theme/theme-manager';\nimport { DOMRenderer } from './renderer/dom-renderer';\nimport { injectStyles, updateStyles, removeStyles } from './renderer/style-manager';\nimport { DEFAULT_CLASS_PREFIX, normalizeClassPrefix } from './constants/dom';\n\nexport const version = '0.1.0';\n\n// Types\nexport * from './types';\n\n// Core\nexport { EventEmitter } from './core/event-emitter';\nexport { ChatManager } from './core/chat-manager';\nexport { MentionEngine } from './core/mention-engine';\nexport type { MentionState } from './core/mention-engine';\n\n// Theme\nexport { ThemeManager } from './theme/theme-manager';\nexport type { ThemeTokens } from './theme/tokens';\nexport { lightTokens, darkTokens } from './theme/tokens';\n\n// Renderer\nexport { DOMRenderer } from './renderer/dom-renderer';\nexport { injectStyles, updateStyles, removeStyles, cls, clsx } from './renderer/style-manager';\nexport {\n DEFAULT_CLASS_PREFIX,\n COMPONENT_CSS_VAR_PREFIX,\n STYLE_ELEMENT_ID,\n getStyleElementId,\n normalizeClassPrefix,\n cx,\n} from './constants/dom';\n\n/**\n * 创建聊天实例\n */\nexport function createChat(config: ChatConfig): ChatInstance {\n // 解析容器\n const container =\n typeof config.container === 'string'\n ? document.querySelector<HTMLElement>(config.container)\n : config.container;\n\n if (!container) {\n throw new Error(`[Chat] Container not found: ${config.container}`);\n }\n\n const prefix = normalizeClassPrefix(config.classPrefix ?? DEFAULT_CLASS_PREFIX);\n const normalizedConfig = {\n ...config,\n classPrefix: prefix,\n };\n const emitter = new EventEmitter();\n const chatManager = new ChatManager(emitter, normalizedConfig.messages);\n const mentionEngine = new MentionEngine(emitter, normalizedConfig.mentionMembers);\n const themeManager = new ThemeManager(emitter, normalizedConfig.theme ?? 'light');\n const renderer = new DOMRenderer(container, normalizedConfig, emitter, mentionEngine);\n\n // 注入样式\n injectStyles(themeManager.getTokens(), prefix);\n\n // 初始化渲染\n renderer.init();\n renderer.renderMessages(chatManager.getMessages());\n\n // 初始滚动到底部\n requestAnimationFrame(() => {\n renderer.scrollToBottom(false);\n });\n\n // 监听主题变化\n emitter.on('theme-change', (_resolved: string, tokens: ThemeTokens) => {\n updateStyles(tokens, prefix);\n });\n\n // 监听消息变化\n emitter.on('message-added', (message: ChatMessage) => {\n renderer.appendMessage(message);\n requestAnimationFrame(() => {\n renderer.scrollToBottom(true);\n });\n });\n\n emitter.on('messages-prepended', (messages: ChatMessage[]) => {\n renderer.prependMessages(messages);\n });\n\n emitter.on('message-updated', (message: ChatMessage) => {\n renderer.updateMessage(message.id, message);\n });\n\n emitter.on('message-removed', (message: ChatMessage) => {\n renderer.removeMessage(message.id);\n });\n\n // 流式消息内容追加\n emitter.on('message-content-appended', (id: string, content: string) => {\n renderer.updateMessageContent(id, content);\n requestAnimationFrame(() => {\n renderer.scrollToBottom(false);\n });\n });\n\n // 创建实例\n const instance: ChatInstance = {\n addMessage(message: ChatMessage) {\n chatManager.addMessage(message);\n },\n\n prependMessages(messages: ChatMessage[]) {\n chatManager.prependMessages(messages);\n },\n\n updateMessage(id: string, updates: Partial<ChatMessage>) {\n chatManager.updateMessage(id, updates);\n },\n\n removeMessage(id: string) {\n chatManager.removeMessage(id);\n },\n\n setMessages(messages: ChatMessage[]) {\n chatManager.setMessages(messages);\n renderer.renderMessages(chatManager.getMessages());\n requestAnimationFrame(() => {\n renderer.scrollToBottom(false);\n });\n },\n\n clearMessages() {\n chatManager.clearMessages();\n renderer.renderMessages([]);\n },\n\n scrollToBottom(smooth = true) {\n renderer.scrollToBottom(smooth);\n },\n\n setTheme(theme: ThemeMode) {\n themeManager.setTheme(theme);\n },\n\n setMentionMembers(members: MentionItem[]) {\n mentionEngine.setMembers(members);\n },\n\n setLoadingMore(loading: boolean) {\n renderer.setLoadingMore(loading);\n },\n\n focusInput() {\n renderer.focusInput();\n },\n\n setInputContent(content: string) {\n renderer.setInputContent(content);\n },\n\n getInputContent() {\n return renderer.getInputContent();\n },\n\n clearInput() {\n renderer.clearInput();\n },\n\n isAtBottom(threshold?: number) {\n return renderer.isAtBottom(threshold);\n },\n\n on(event: string, handler: (...args: unknown[]) => void) {\n return emitter.on(event, handler);\n },\n\n getMessages() {\n return chatManager.getMessages();\n },\n\n getMessage(id: string) {\n return chatManager.getMessage(id);\n },\n\n appendMessageContent(id: string, chunk: string) {\n chatManager.appendMessageContent(id, chunk);\n },\n\n finishStreaming(id: string) {\n chatManager.finishStreaming(id);\n },\n\n destroy() {\n themeManager.destroy();\n renderer.destroy();\n emitter.removeAll();\n removeStyles(prefix);\n },\n };\n\n return instance;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @composy/chat-core - 即时通讯/IM 组件核心库\r\n *\r\n * 提供聊天气泡、消息列表、@提及、多消息类型(文本/图片/文件/系统消息/自定义)、\r\n * 消息状态管理(发送中/已发送/已送达/已读/失败)、亮暗主题切换等能力。\r\n * 框架无关的核心实现,配合 Vue/React 适配层使用。\r\n *\r\n * @packageDocumentation\r\n * @module @composy/chat-core\r\n */\r\n\r\nimport type { ChatOutboxFlushOptions } from './core/outbox'\r\nimport type {\r\n ChatTransportAck,\r\n ChatTransportEvent,\r\n ChatTransportStatus,\r\n} from './core/transport'\r\nimport type { ThemeTokens } from './theme/tokens'\r\nimport type {\r\n ChatConfig,\r\n ChatInstance,\r\n ChatMessage,\r\n MentionItem,\r\n ThemeMode,\r\n} from './types'\r\nimport { DEFAULT_CLASS_PREFIX, normalizeClassPrefix } from './constants/dom'\r\nimport { ChatManager } from './core/chat-manager'\r\nimport { EventEmitter } from './core/event-emitter'\r\nimport { MentionEngine } from './core/mention-engine'\r\nimport { normalizeChatMessage } from './core/message-schema'\r\nimport { ChatTransportController } from './core/transport'\r\nimport { DOMRenderer } from './renderer/dom-renderer'\r\nimport { injectStyles, removeStyles } from './renderer/style-manager'\r\nimport { ThemeManager } from './theme/theme-manager'\r\n\r\nexport const version = '0.1.0'\r\n\r\nexport {\r\n COMPONENT_CSS_VAR_PREFIX,\r\n cx,\r\n DEFAULT_CLASS_PREFIX,\r\n getStyleElementId,\r\n normalizeClassPrefix,\r\n STYLE_ELEMENT_ID,\r\n} from './constants/dom'\r\n\r\nexport { ChatManager } from './core/chat-manager'\r\nexport type {\r\n MessageMergeOptions,\r\n MessageMergeResult,\r\n StreamAppendOptions,\r\n} from './core/chat-manager'\r\n// Core\r\nexport { EventEmitter } from './core/event-emitter'\r\nexport { MentionEngine } from './core/mention-engine'\r\nexport type { MentionState } from './core/mention-engine'\r\nexport {\r\n cloneChatMessage,\r\n compareChatMessages,\r\n normalizeChatContentBlocks,\r\n normalizeChatMessage,\r\n normalizeChatMessages,\r\n} from './core/message-schema'\r\nexport { ChatOutbox, MemoryChatOutboxStorage } from './core/outbox'\r\nexport type {\r\n ChatOutboxEntry,\r\n ChatOutboxFlushOptions,\r\n ChatOutboxFlushResult,\r\n ChatOutboxOptions,\r\n ChatOutboxStorage,\r\n} from './core/outbox'\r\nexport { ChatTransportController } from './core/transport'\r\nexport type {\r\n ChatTransport,\r\n ChatTransportAck,\r\n ChatTransportContext,\r\n ChatTransportControllerOptions,\r\n ChatTransportEvent,\r\n ChatTransportStatus,\r\n} from './core/transport'\r\n\r\n// Renderer\r\nexport { DOMRenderer } from './renderer/dom-renderer'\r\nexport {\r\n cls,\r\n clsx,\r\n injectStyles,\r\n removeStyles,\r\n updateStyles,\r\n} from './renderer/style-manager'\r\n// Theme\r\nexport { ThemeManager } from './theme/theme-manager'\r\n\r\nexport type { ThemeTokens } from './theme/tokens'\r\nexport { darkTokens, lightTokens } from './theme/tokens'\r\n// Types\r\nexport * from './types'\r\n\r\n/**\r\n * 创建聊天实例\r\n */\r\nexport function createChat(config: ChatConfig): ChatInstance {\r\n // 解析容器\r\n let container: HTMLElement | null\r\n if (typeof config.container === 'string') {\r\n if (typeof document === 'undefined') {\r\n throw new Error(\r\n '[Chat] A browser Document is required to resolve a container selector.'\r\n )\r\n }\r\n container = document.querySelector<HTMLElement>(config.container)\r\n } else {\r\n container = config.container\r\n }\r\n\r\n if (!container) {\r\n throw new Error(`[Chat] Container not found: ${config.container}`)\r\n }\r\n\r\n const ownerDocument = container.ownerDocument\r\n const prefix = normalizeClassPrefix(\r\n config.classPrefix ?? DEFAULT_CLASS_PREFIX\r\n )\r\n const normalizedConfig = {\r\n ...config,\r\n classPrefix: prefix,\r\n }\r\n const emitter = new EventEmitter()\r\n const chatManager = new ChatManager(emitter, normalizedConfig.messages)\r\n const mentionEngine = new MentionEngine(\r\n emitter,\r\n normalizedConfig.mentionMembers\r\n )\r\n const themeManager = new ThemeManager(\r\n emitter,\r\n normalizedConfig.theme ?? 'light',\r\n ownerDocument.defaultView\r\n )\r\n const renderer = new DOMRenderer(\r\n container,\r\n normalizedConfig,\r\n emitter,\r\n mentionEngine\r\n )\r\n let destroyed = false\r\n const schedule = (callback: () => void) => {\r\n const run = () => {\r\n if (!destroyed) callback()\r\n }\r\n if (ownerDocument.defaultView?.requestAnimationFrame) {\r\n ownerDocument.defaultView.requestAnimationFrame(run)\r\n } else {\r\n setTimeout(run, 0)\r\n }\r\n }\r\n\r\n // 初始化渲染\r\n renderer.init()\r\n renderer.renderMessages(chatManager.getMessages())\r\n renderer.setThemeTokens(themeManager.getTokens())\r\n injectStyles(themeManager.getTokens(), prefix, renderer.getRootElement())\r\n\r\n const applyTransportAck = async (ack: ChatTransportAck): Promise<void> => {\r\n const localId = chatManager.getMessageIdByClientMessageId(\r\n ack.clientMessageId\r\n )\r\n if (localId) {\r\n chatManager.updateMessage(localId, {\r\n ...(ack.message ?? {}),\r\n id: localId,\r\n clientMessageId: ack.clientMessageId,\r\n status: 'sent',\r\n ...(ack.sequence !== undefined && { sequence: ack.sequence }),\r\n ...(ack.cursor !== undefined && { cursor: ack.cursor }),\r\n })\r\n }\r\n if (normalizedConfig.outbox) {\r\n await normalizedConfig.outbox.remove(ack.clientMessageId)\r\n }\r\n emitter.emit('transport-ack', ack)\r\n }\r\n\r\n const handleTransportEvent = (event: ChatTransportEvent): void => {\r\n if (event.type === 'message') {\r\n chatManager.upsertMessage(\r\n {\r\n ...event.message,\r\n ...(event.cursor !== undefined && { cursor: event.cursor }),\r\n },\r\n { sequence: event.sequence, source: 'remote' }\r\n )\r\n } else if (event.type === 'ack') {\r\n void applyTransportAck(event.ack).catch(error => {\r\n emitter.emit('transport-error', error)\r\n })\r\n } else if (event.type === 'cursor') {\r\n emitter.emit('transport-cursor', event.cursor)\r\n } else {\r\n emitter.emit('transport-error', event.error, event.recoverable)\r\n }\r\n }\r\n\r\n const transportController = normalizedConfig.transport\r\n ? new ChatTransportController(normalizedConfig.transport, {\r\n conversationId: normalizedConfig.conversationId,\r\n cursor: normalizedConfig.transportCursor,\r\n onEvent: handleTransportEvent,\r\n onStatusChange: status => {\r\n emitter.emit('transport-status', status)\r\n },\r\n })\r\n : null\r\n\r\n // 初始滚动到底部\r\n schedule(() => {\r\n renderer.scrollToBottom(false)\r\n })\r\n\r\n // 监听主题变化\r\n emitter.on('theme-change', (_resolved: string, tokens: ThemeTokens) => {\r\n renderer.setThemeTokens(tokens)\r\n })\r\n\r\n // 监听消息变化\r\n emitter.on('message-added', (message: ChatMessage) => {\r\n renderer.appendMessage(message)\r\n schedule(() => {\r\n renderer.scrollToBottom(true)\r\n })\r\n })\r\n\r\n emitter.on('mention-select', (member: MentionItem) => {\r\n normalizedConfig.onMentionSelect?.(member)\r\n })\r\n\r\n emitter.on('messages-prepended', (messages: ChatMessage[]) => {\r\n renderer.prependMessages(messages)\r\n })\r\n\r\n emitter.on('message-updated', (message: ChatMessage) => {\r\n renderer.updateMessage(message.id, message)\r\n })\r\n\r\n emitter.on('message-removed', (message: ChatMessage) => {\r\n renderer.removeMessage(message.id)\r\n })\r\n\r\n // 流式消息内容追加\r\n emitter.on('message-content-appended', (id: string, content: string) => {\r\n renderer.updateMessageContent(id, content)\r\n schedule(() => {\r\n renderer.scrollToBottom(false)\r\n })\r\n })\r\n\r\n // 创建实例\r\n const instance: ChatInstance = {\r\n addMessage(message: ChatMessage) {\r\n if (!destroyed) chatManager.addMessage(message)\r\n },\r\n\r\n prependMessages(messages: ChatMessage[]) {\r\n if (!destroyed) chatManager.prependMessages(messages)\r\n },\r\n\r\n updateMessage(id: string, updates: Partial<ChatMessage>) {\r\n if (!destroyed) chatManager.updateMessage(id, updates)\r\n },\r\n\r\n removeMessage(id: string) {\r\n if (!destroyed) chatManager.removeMessage(id)\r\n },\r\n\r\n setMessages(messages: ChatMessage[]) {\r\n if (destroyed) return\r\n chatManager.setMessages(messages)\r\n renderer.renderMessages(chatManager.getMessages())\r\n schedule(() => {\r\n renderer.scrollToBottom(false)\r\n })\r\n },\r\n\r\n clearMessages() {\r\n if (!destroyed) {\r\n chatManager.clearMessages()\r\n renderer.renderMessages([])\r\n }\r\n },\r\n\r\n scrollToBottom(smooth = true) {\r\n if (!destroyed) renderer.scrollToBottom(smooth)\r\n },\r\n\r\n setTheme(theme: ThemeMode) {\r\n if (!destroyed) themeManager.setTheme(theme)\r\n },\r\n\r\n setMentionMembers(members: MentionItem[]) {\r\n if (!destroyed) mentionEngine.setMembers(members)\r\n },\r\n\r\n setLoadingMore(loading: boolean) {\r\n if (!destroyed) renderer.setLoadingMore(loading)\r\n },\r\n\r\n focusInput() {\r\n if (!destroyed) renderer.focusInput()\r\n },\r\n\r\n setInputContent(content: string) {\r\n if (!destroyed) renderer.setInputContent(content)\r\n },\r\n\r\n getInputContent() {\r\n return destroyed ? '' : renderer.getInputContent()\r\n },\r\n\r\n clearInput() {\r\n if (!destroyed) renderer.clearInput()\r\n },\r\n\r\n isAtBottom(threshold?: number) {\r\n return destroyed || renderer.isAtBottom(threshold)\r\n },\r\n\r\n on(event: string, handler: (...args: unknown[]) => void) {\r\n return destroyed ? () => {} : emitter.on(event, handler)\r\n },\r\n\r\n getMessages() {\r\n return destroyed ? [] : chatManager.getMessages()\r\n },\r\n\r\n getMessage(id: string) {\r\n return destroyed ? undefined : chatManager.getMessage(id)\r\n },\r\n\r\n appendMessageContent(id: string, chunk: string) {\r\n return destroyed ? false : chatManager.appendMessageContent(id, chunk)\r\n },\r\n\r\n finishStreaming(id: string, generation?: string) {\r\n return destroyed ? false : chatManager.finishStreaming(id, generation)\r\n },\r\n\r\n beginStreaming(id: string, generation?: string) {\r\n return destroyed ? null : chatManager.beginStreaming(id, generation)\r\n },\r\n\r\n cancelStreaming(id: string, generation?: string) {\r\n return destroyed ? false : chatManager.cancelStreaming(id, generation)\r\n },\r\n\r\n mergeMessage(message: ChatMessage, sequence?: number) {\r\n return destroyed\r\n ? 'ignored'\r\n : chatManager.upsertMessage(message, {\r\n sequence,\r\n source: 'remote',\r\n })\r\n },\r\n\r\n async connectTransport(signal?: AbortSignal) {\r\n if (!transportController) {\r\n throw new Error('No chat transport is configured.')\r\n }\r\n await transportController.connect(signal)\r\n },\r\n\r\n async disconnectTransport() {\r\n await transportController?.disconnect()\r\n },\r\n\r\n getTransportStatus(): ChatTransportStatus {\r\n return transportController?.getStatus() ?? 'idle'\r\n },\r\n\r\n async sendMessage(\r\n message: ChatMessage,\r\n options: { signal?: AbortSignal } = {}\r\n ): Promise<ChatTransportAck | void> {\r\n if (!transportController) {\r\n throw new Error('No chat transport is configured.')\r\n }\r\n if (destroyed) throw new Error('Chat instance is destroyed.')\r\n const prepared = normalizeChatMessage({\r\n ...message,\r\n clientMessageId:\r\n message.clientMessageId ?? createClientMessageId(message.id),\r\n status: message.status ?? 'sending',\r\n })\r\n chatManager.addMessage(prepared)\r\n try {\r\n if (normalizedConfig.outbox) {\r\n await normalizedConfig.outbox.enqueue(prepared)\r\n }\r\n const ack = await transportController.send(prepared, {\r\n signal: options.signal,\r\n clientMessageId: prepared.clientMessageId,\r\n })\r\n if (ack) await applyTransportAck(ack)\r\n else chatManager.markMessageStatus(prepared.id, 'sent')\r\n emitter.emit('message-sent', prepared, ack)\r\n return ack\r\n } catch (error) {\r\n chatManager.markMessageStatus(prepared.id, 'failed')\r\n emitter.emit('message-send-failed', prepared, error)\r\n throw error\r\n }\r\n },\r\n\r\n async flushOutbox(options: ChatOutboxFlushOptions = {}) {\r\n if (!normalizedConfig.outbox) {\r\n return { sent: [], failed: [], remaining: [] }\r\n }\r\n if (!transportController) {\r\n throw new Error('No chat transport is configured.')\r\n }\r\n return normalizedConfig.outbox.flush(async (message, sendOptions) => {\r\n const ack = await transportController.send(message, sendOptions)\r\n if (ack) await applyTransportAck(ack)\r\n else if (message.id) chatManager.markMessageStatus(message.id, 'sent')\r\n }, options)\r\n },\r\n\r\n destroy() {\r\n if (destroyed) return\r\n destroyed = true\r\n transportController?.dispose()\r\n themeManager.destroy()\r\n renderer.destroy()\r\n emitter.removeAll()\r\n removeStyles(prefix, ownerDocument)\r\n },\r\n }\r\n\r\n if (normalizedConfig.autoConnect && transportController) {\r\n void instance.connectTransport().catch(error => {\r\n emitter.emit('transport-error', error)\r\n })\r\n }\r\n\r\n return instance\r\n}\r\n\r\nfunction createClientMessageId(messageId: string): string {\r\n const cryptoObject = globalThis.crypto\r\n if (cryptoObject?.randomUUID) return cryptoObject.randomUUID()\r\n return `client-${messageId}-${Date.now()}-${Math.random().toString(36).slice(2)}`\r\n}\r\n"],"mappings":"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"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
import type { EventEmitter } from '../core/event-emitter';
|
|
2
|
+
import type { MentionEngine } from '../core/mention-engine';
|
|
3
|
+
import type { ThemeTokens } from '../theme/tokens';
|
|
1
4
|
import type { ChatConfig, ChatMessage, MentionItem } from '../types';
|
|
2
|
-
import { EventEmitter } from '../core/event-emitter';
|
|
3
|
-
import { MentionEngine } from '../core/mention-engine';
|
|
4
5
|
export declare class DOMRenderer {
|
|
5
6
|
private container;
|
|
7
|
+
private document;
|
|
6
8
|
private config;
|
|
7
9
|
private emitter;
|
|
8
10
|
private mentionEngine;
|
|
@@ -21,6 +23,8 @@ export declare class DOMRenderer {
|
|
|
21
23
|
private isRecording;
|
|
22
24
|
private recognition;
|
|
23
25
|
private lastVoiceTranscript;
|
|
26
|
+
private destroyed;
|
|
27
|
+
private pendingFileInputs;
|
|
24
28
|
constructor(container: HTMLElement, config: ChatConfig, emitter: EventEmitter, mentionEngine: MentionEngine);
|
|
25
29
|
init(): void;
|
|
26
30
|
updateMessageContent(id: string, content: string): void;
|
|
@@ -32,6 +36,8 @@ export declare class DOMRenderer {
|
|
|
32
36
|
scrollToBottom(smooth?: boolean): void;
|
|
33
37
|
isAtBottom(threshold?: number): boolean;
|
|
34
38
|
setLoadingMore(loading: boolean): void;
|
|
39
|
+
setThemeTokens(tokens: ThemeTokens): void;
|
|
40
|
+
getRootElement(): HTMLElement;
|
|
35
41
|
focusInput(): void;
|
|
36
42
|
setInputContent(content: string): void;
|
|
37
43
|
getInputContent(): string;
|
|
@@ -55,6 +61,7 @@ export declare class DOMRenderer {
|
|
|
55
61
|
private autoResize;
|
|
56
62
|
private updateSendButtonState;
|
|
57
63
|
private renderLoadMoreButton;
|
|
64
|
+
private loadMore;
|
|
58
65
|
private renderTimeDivider;
|
|
59
66
|
private createTimeDivider;
|
|
60
67
|
private renderMessageRow;
|
|
@@ -62,18 +69,23 @@ export declare class DOMRenderer {
|
|
|
62
69
|
private createAvatar;
|
|
63
70
|
private createMessageFooter;
|
|
64
71
|
private createBubble;
|
|
72
|
+
private renderContentBlocks;
|
|
65
73
|
private renderTextContent;
|
|
74
|
+
private setSanitizedCustomHtml;
|
|
75
|
+
private sanitizeCustomNode;
|
|
76
|
+
private safeResourceUrl;
|
|
77
|
+
private safeUrl;
|
|
66
78
|
private renderEmpty;
|
|
67
79
|
private removeEmpty;
|
|
68
80
|
private el;
|
|
69
81
|
private getMessageElements;
|
|
82
|
+
private getMessageRow;
|
|
83
|
+
private refreshTimeDividers;
|
|
70
84
|
private formatTime;
|
|
71
85
|
private formatShortTime;
|
|
72
86
|
private formatFileSize;
|
|
73
87
|
private limitInput;
|
|
74
|
-
private getCssSizeValue;
|
|
75
88
|
private escapeHtml;
|
|
76
89
|
private escapeAttr;
|
|
77
90
|
private escapeRegex;
|
|
78
91
|
}
|
|
79
|
-
//# sourceMappingURL=dom-renderer.d.ts.map
|