@zhin.js/adapter-sandbox 3.0.2 → 3.0.3
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/CHANGELOG.md +16 -0
- package/README.md +16 -2
- package/client/Sandbox.tsx +111 -31
- package/client/sandboxTransport.ts +61 -0
- package/dist/index.js +7 -7
- package/lib/fetch-sse.d.ts +11 -0
- package/lib/fetch-sse.d.ts.map +1 -0
- package/lib/fetch-sse.js +76 -0
- package/lib/fetch-sse.js.map +1 -0
- package/lib/fetch-ws.d.ts +11 -0
- package/lib/fetch-ws.d.ts.map +1 -0
- package/lib/fetch-ws.js +13 -0
- package/lib/fetch-ws.js.map +1 -0
- package/lib/index.d.ts +16 -48
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +25 -132
- package/lib/index.js.map +1 -1
- package/lib/sandbox-sse-hub.d.ts +10 -0
- package/lib/sandbox-sse-hub.d.ts.map +1 -0
- package/lib/sandbox-sse-hub.js +101 -0
- package/lib/sandbox-sse-hub.js.map +1 -0
- package/lib/sandbox-ws.d.ts +91 -0
- package/lib/sandbox-ws.d.ts.map +1 -0
- package/lib/sandbox-ws.js +337 -0
- package/lib/sandbox-ws.js.map +1 -0
- package/package.json +14 -9
- package/src/fetch-sse.ts +87 -0
- package/src/fetch-ws.ts +23 -0
- package/src/index.ts +57 -181
- package/src/sandbox-sse-hub.ts +118 -0
- package/src/sandbox-ws.ts +462 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @zhin.js/adapter-process
|
|
2
2
|
|
|
3
|
+
## 3.0.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 0db9fed: fix: deno deploy
|
|
8
|
+
- f19d2e0: fix: remove multiple runtime support
|
|
9
|
+
- Updated dependencies [0db9fed]
|
|
10
|
+
- Updated dependencies [f19d2e0]
|
|
11
|
+
- Updated dependencies [2d24338]
|
|
12
|
+
- @zhin.js/console@3.0.3
|
|
13
|
+
- @zhin.js/http-host@0.1.3
|
|
14
|
+
- @zhin.js/core@1.1.26
|
|
15
|
+
- zhin.js@1.0.84
|
|
16
|
+
- @zhin.js/client@1.1.3
|
|
17
|
+
- @zhin.js/http@1.0.77
|
|
18
|
+
|
|
3
19
|
## 3.0.2
|
|
4
20
|
|
|
5
21
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -4,7 +4,8 @@ Zhin.js Sandbox 适配器,基于 WebSocket 的本地测试适配器,配合 W
|
|
|
4
4
|
|
|
5
5
|
## 功能特性
|
|
6
6
|
|
|
7
|
-
-
|
|
7
|
+
- **Node Host**:WebSocket `/sandbox`
|
|
8
|
+
- **Edge**(Vercel 等):`transport: http-sse` — `POST /sandbox/message` + `GET /sandbox/events`
|
|
8
9
|
- 浏览器端 React 聊天 UI
|
|
9
10
|
- 支持多客户端同时连接
|
|
10
11
|
- 无需第三方平台账号,即开即用
|
|
@@ -31,6 +32,7 @@ Sandbox 适配器需要以下服务插件:
|
|
|
31
32
|
bots:
|
|
32
33
|
- context: sandbox
|
|
33
34
|
name: sandbox-bot
|
|
35
|
+
# transport: http-sse # Edge / Vercel;Node 省略或 websocket
|
|
34
36
|
|
|
35
37
|
plugins:
|
|
36
38
|
- adapter-sandbox
|
|
@@ -64,7 +66,19 @@ export default defineConfig({
|
|
|
64
66
|
2. 打开浏览器访问 Web 控制台(默认 `http://localhost:8086`)
|
|
65
67
|
3. 在控制台的 Sandbox 聊天窗口中发送消息进行测试
|
|
66
68
|
|
|
67
|
-
|
|
69
|
+
每个浏览器客户端连接后创建 Sandbox Bot(无 yaml 固定名时为 `sandbox-xxxx`)。传输层在 `src/sandbox-ws.ts`(WS)与 `src/fetch-sse.ts`(SSE)。
|
|
70
|
+
|
|
71
|
+
**Node**(默认 `transport: websocket`):`Router.ws("/sandbox")`(插件 `useContext("router")` 自动挂载)。
|
|
72
|
+
|
|
73
|
+
**Edge**(`zhin.config.yml` 中 `transport: http-sse`):
|
|
74
|
+
|
|
75
|
+
```typescript
|
|
76
|
+
import { registerSandboxSseRoutes } from "@zhin.js/adapter-sandbox/edge";
|
|
77
|
+
|
|
78
|
+
registerSandboxSseRoutes(routeTable, () => plugin.inject("sandbox"));
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
仍支持 Deno 等可 WS 的环境:`registerSandboxWebSocketRoutes`。
|
|
68
82
|
|
|
69
83
|
## 消息格式
|
|
70
84
|
|
package/client/Sandbox.tsx
CHANGED
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import React, { useState, useEffect, useRef } from 'react';
|
|
2
2
|
import { MessageSegment, cn, resolveMediaSrc, pickMediaRawUrl } from '@zhin.js/client';
|
|
3
|
+
import {
|
|
4
|
+
getSandboxApiBase,
|
|
5
|
+
getSandboxAuthHeaders,
|
|
6
|
+
getSandboxSessionId,
|
|
7
|
+
resolveSandboxTransport,
|
|
8
|
+
transportFromModuleUrl,
|
|
9
|
+
} from './sandboxTransport';
|
|
3
10
|
import { User, Users, Trash2, Send, Hash, MessageSquare, Wifi, WifiOff, Smile, Image, X, Check, Info, Search, Bot, UserPlus, Bell, Video, Music } from 'lucide-react';
|
|
4
11
|
import RichTextEditor, { RichTextEditorRef } from './RichTextEditor';
|
|
5
12
|
|
|
@@ -43,6 +50,10 @@ export default function Sandbox() {
|
|
|
43
50
|
const [viewMode, setViewMode] = useState<'chat' | 'requests' | 'notices'>('chat')
|
|
44
51
|
const messagesEndRef = useRef<HTMLDivElement>(null)
|
|
45
52
|
const wsRef = useRef<WebSocket | null>(null)
|
|
53
|
+
const esRef = useRef<EventSource | null>(null)
|
|
54
|
+
const transportRef = useRef<'websocket' | 'http-sse'>('websocket')
|
|
55
|
+
const apiBaseRef = useRef('')
|
|
56
|
+
const sessionIdRef = useRef('')
|
|
46
57
|
const editorRef = useRef<RichTextEditorRef>(null)
|
|
47
58
|
|
|
48
59
|
const fetchFaceList = async () => {
|
|
@@ -52,39 +63,94 @@ export default function Sandbox() {
|
|
|
52
63
|
|
|
53
64
|
useEffect(() => { fetchFaceList() }, [])
|
|
54
65
|
|
|
66
|
+
const handleInboundPayload = (data: {
|
|
67
|
+
type: string; id: string; content?: unknown; bot?: string; timestamp: number
|
|
68
|
+
}) => {
|
|
69
|
+
const content: MessageSegment[] = typeof data.content === 'string'
|
|
70
|
+
? parseTextToSegments(data.content)
|
|
71
|
+
: Array.isArray(data.content) ? data.content as MessageSegment[] : parseTextToSegments(String(data.content ?? ''))
|
|
72
|
+
|
|
73
|
+
const channelName = data.type === 'private'
|
|
74
|
+
? `私聊-${data.bot || botName}`
|
|
75
|
+
: data.type === 'group'
|
|
76
|
+
? `群组-${data.id}`
|
|
77
|
+
: `频道-${data.id}`
|
|
78
|
+
const channelType = data.type as Channel['type']
|
|
79
|
+
|
|
80
|
+
setChannels((prev) => {
|
|
81
|
+
if (prev.some((c) => c.id === data.id)) return prev
|
|
82
|
+
const created: Channel = { id: data.id, name: channelName, type: channelType, unread: 0 }
|
|
83
|
+
setActiveChannel(created)
|
|
84
|
+
return [...prev, created]
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
setMessages((prev) => [...prev, {
|
|
88
|
+
id: `bot_${data.timestamp}`, type: 'received', channelType,
|
|
89
|
+
channelId: data.id, channelName, senderId: 'bot',
|
|
90
|
+
senderName: data.bot || botName, content, timestamp: data.timestamp,
|
|
91
|
+
}])
|
|
92
|
+
}
|
|
93
|
+
|
|
55
94
|
useEffect(() => {
|
|
56
|
-
|
|
57
|
-
const base = (
|
|
58
|
-
const
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
wsRef.current.onopen = () => setConnected(true)
|
|
62
|
-
wsRef.current.onmessage = (event) => {
|
|
63
|
-
try {
|
|
64
|
-
const data = JSON.parse(event.data)
|
|
65
|
-
let content: MessageSegment[] = typeof data.content === 'string'
|
|
66
|
-
? parseTextToSegments(data.content)
|
|
67
|
-
: Array.isArray(data.content) ? data.content : parseTextToSegments(String(data.content))
|
|
68
|
-
|
|
69
|
-
let targetChannel = channels.find((c) => c.id === data.id)
|
|
70
|
-
if (!targetChannel) {
|
|
71
|
-
const channelName = data.type === 'private' ? `私聊-${data.bot || botName}` : data.type === 'group' ? `群组-${data.id}` : `频道-${data.id}`
|
|
72
|
-
targetChannel = { id: data.id, name: channelName, type: data.type, unread: 0 }
|
|
73
|
-
setChannels((prev) => [...prev, targetChannel!])
|
|
74
|
-
setActiveChannel(targetChannel)
|
|
75
|
-
}
|
|
95
|
+
let cancelled = false
|
|
96
|
+
const base = getSandboxApiBase()
|
|
97
|
+
const sessionId = getSandboxSessionId()
|
|
98
|
+
apiBaseRef.current = base
|
|
99
|
+
sessionIdRef.current = sessionId
|
|
76
100
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
101
|
+
const connectWebSocket = () => {
|
|
102
|
+
if (wsRef.current) return
|
|
103
|
+
transportRef.current = 'websocket'
|
|
104
|
+
const wsUrl = new URL('/sandbox', `${base}/`)
|
|
105
|
+
wsUrl.protocol = wsUrl.protocol === 'https:' ? 'wss:' : 'ws:'
|
|
106
|
+
wsRef.current = new WebSocket(wsUrl.href)
|
|
107
|
+
wsRef.current.onopen = () => setConnected(true)
|
|
108
|
+
wsRef.current.onmessage = (event) => {
|
|
109
|
+
try { handleInboundPayload(JSON.parse(event.data)) }
|
|
110
|
+
catch (err) { console.error('[Sandbox] Failed to parse message:', err) }
|
|
111
|
+
}
|
|
112
|
+
wsRef.current.onclose = () => setConnected(false)
|
|
84
113
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
114
|
+
|
|
115
|
+
const connectSse = () => {
|
|
116
|
+
if (esRef.current) return
|
|
117
|
+
transportRef.current = 'http-sse'
|
|
118
|
+
const eventsUrl = new URL('/sandbox/events', `${base}/`)
|
|
119
|
+
eventsUrl.searchParams.set('session', sessionId)
|
|
120
|
+
const auth = getSandboxAuthHeaders().Authorization
|
|
121
|
+
if (auth?.startsWith('Bearer ')) {
|
|
122
|
+
eventsUrl.searchParams.set('access_token', auth.slice(7))
|
|
123
|
+
}
|
|
124
|
+
esRef.current = new EventSource(eventsUrl.href)
|
|
125
|
+
esRef.current.onopen = () => setConnected(true)
|
|
126
|
+
esRef.current.onmessage = (event) => {
|
|
127
|
+
try { handleInboundPayload(JSON.parse(event.data)) }
|
|
128
|
+
catch (err) { console.error('[Sandbox] Failed to parse SSE message:', err) }
|
|
129
|
+
}
|
|
130
|
+
esRef.current.onerror = () => setConnected(false)
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const moduleMode = transportFromModuleUrl()
|
|
134
|
+
if (moduleMode === 'http-sse') {
|
|
135
|
+
connectSse()
|
|
136
|
+
} else {
|
|
137
|
+
void (async () => {
|
|
138
|
+
const mode = await resolveSandboxTransport(base)
|
|
139
|
+
if (cancelled) return
|
|
140
|
+
if (mode === 'http-sse') connectSse()
|
|
141
|
+
else connectWebSocket()
|
|
142
|
+
})()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
return () => {
|
|
146
|
+
cancelled = true
|
|
147
|
+
wsRef.current?.close()
|
|
148
|
+
wsRef.current = null
|
|
149
|
+
esRef.current?.close()
|
|
150
|
+
esRef.current = null
|
|
151
|
+
setConnected(false)
|
|
152
|
+
}
|
|
153
|
+
}, [])
|
|
88
154
|
|
|
89
155
|
useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [messages])
|
|
90
156
|
useEffect(() => { setPreviewSegments(inputText.trim() ? parseTextToSegments(inputText) : []) }, [inputText])
|
|
@@ -188,7 +254,21 @@ export default function Sandbox() {
|
|
|
188
254
|
const newMessage: Message = { id: `msg_${Date.now()}`, type: 'sent', channelType: activeChannel.type, channelId: activeChannel.id, channelName: activeChannel.name, senderId: 'test_user', senderName: '测试用户', content: segments, timestamp: Date.now() }
|
|
189
255
|
setMessages((prev) => [...prev, newMessage]); setInputText(''); setPreviewSegments([])
|
|
190
256
|
editorRef.current?.clear()
|
|
191
|
-
|
|
257
|
+
const payload = JSON.stringify({ type: activeChannel.type, id: activeChannel.id, content: segments, timestamp: Date.now() })
|
|
258
|
+
if (transportRef.current === 'http-sse') {
|
|
259
|
+
const url = new URL('/sandbox/message', `${apiBaseRef.current}/`)
|
|
260
|
+
void fetch(url.href, {
|
|
261
|
+
method: 'POST',
|
|
262
|
+
headers: {
|
|
263
|
+
'Content-Type': 'application/json',
|
|
264
|
+
'X-Sandbox-Session': sessionIdRef.current,
|
|
265
|
+
...getSandboxAuthHeaders(),
|
|
266
|
+
},
|
|
267
|
+
body: payload,
|
|
268
|
+
}).catch((err) => console.error('[Sandbox] POST message failed:', err))
|
|
269
|
+
} else {
|
|
270
|
+
wsRef.current?.send(payload)
|
|
271
|
+
}
|
|
192
272
|
}
|
|
193
273
|
|
|
194
274
|
const clearMessages = () => { if (confirm('确定清空所有消息记录?')) setMessages([]) }
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
export type SandboxTransportMode = "websocket" | "http-sse";
|
|
2
|
+
|
|
3
|
+
export function getSandboxApiBase(): string {
|
|
4
|
+
const stored = localStorage.getItem("zhin_api_base")?.trim();
|
|
5
|
+
return (stored ? stored.replace(/\/$/, "") : null) ?? window.location.origin;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function getSandboxSessionId(): string {
|
|
9
|
+
const key = "zhin_sandbox_session";
|
|
10
|
+
let id = sessionStorage.getItem(key)?.trim();
|
|
11
|
+
if (!id) {
|
|
12
|
+
id = crypto.randomUUID();
|
|
13
|
+
sessionStorage.setItem(key, id);
|
|
14
|
+
}
|
|
15
|
+
return id;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function getSandboxAuthHeaders(): Record<string, string> {
|
|
19
|
+
const token =
|
|
20
|
+
localStorage.getItem("HTTP_TOKEN")?.trim() ||
|
|
21
|
+
localStorage.getItem("zhin_http_token")?.trim() ||
|
|
22
|
+
"";
|
|
23
|
+
return token ? { Authorization: `Bearer ${token}` } : {};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/** Edge 构建的 sandbox.mjs 带 ?v=edge 或 ?transport=http-sse */
|
|
27
|
+
export function transportFromModuleUrl(): SandboxTransportMode | null {
|
|
28
|
+
try {
|
|
29
|
+
const u = new URL(import.meta.url);
|
|
30
|
+
if (u.searchParams.get("transport") === "http-sse") return "http-sse";
|
|
31
|
+
if (u.searchParams.get("v") === "edge") return "http-sse";
|
|
32
|
+
} catch {
|
|
33
|
+
/* 非 ESM 环境 */
|
|
34
|
+
}
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
async function fetchTransportHint(apiBase: string, path: string): Promise<SandboxTransportMode | null> {
|
|
39
|
+
const res = await fetch(new URL(path, `${apiBase.replace(/\/$/, "")}/`).href);
|
|
40
|
+
if (!res.ok) return null;
|
|
41
|
+
const data = (await res.json()) as { sandboxTransport?: string };
|
|
42
|
+
return data.sandboxTransport === "http-sse" ? "http-sse" : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export async function resolveSandboxTransport(apiBase: string): Promise<SandboxTransportMode> {
|
|
46
|
+
const fromModule = transportFromModuleUrl();
|
|
47
|
+
if (fromModule) return fromModule;
|
|
48
|
+
|
|
49
|
+
const override = localStorage.getItem("zhin_sandbox_transport")?.trim();
|
|
50
|
+
if (override === "http-sse" || override === "websocket") return override;
|
|
51
|
+
|
|
52
|
+
for (const path of ["/entries", "/api/info"]) {
|
|
53
|
+
try {
|
|
54
|
+
const mode = await fetchTransportHint(apiBase, path);
|
|
55
|
+
if (mode) return mode;
|
|
56
|
+
} catch {
|
|
57
|
+
/* CORS / 离线 */
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return "websocket";
|
|
61
|
+
}
|
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
`)}return{text:d,segments:t}},
|
|
3
|
-
`)){
|
|
4
|
-
`).map((
|
|
5
|
-
`).length-1&&a("br",{})]},
|
|
6
|
-
`).map((
|
|
7
|
-
`).length-1&&a("br",{})]},k))},u);case"at":return o("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded bg-accent text-accent-foreground text-xs mx-0.5",children:["@",String(S.name??S.qq??"")]},u);case"face":return a("img",{src:`https://face.viki.moe/apng/${S.id}.png`,alt:"",className:"w-6 h-6 inline-block align-middle mx-0.5"},u);case"image":{let y=Ae(S),k=ye(y,"image");return k?a("a",{href:k,target:"_blank",rel:"noreferrer",className:"block my-1",children:a("img",{src:k,alt:"",className:M("max-w-[min(320px,88vw)] rounded-lg block",L,"ring-offset-0"),onError:V=>{V.target.style.display="none"}})},u):a("span",{className:"text-xs opacity-70",children:"[\u56FE\u7247]"},u)}case"video":{let y=Ae(S),k=ye(y,"video");return k?a("video",{src:k,controls:!0,playsInline:!0,preload:"metadata",className:M("max-w-[min(360px,92vw)] max-h-72 rounded-lg my-1 bg-black/10",L)},u):a("span",{className:"text-xs opacity-70",children:"[\u89C6\u9891\u65E0\u5730\u5740]"},u)}case"audio":case"record":{let y=Ae(S),k=ye(y,"audio");return k?a("audio",{src:k,controls:!0,preload:"metadata",className:M("w-full max-w-sm my-2 h-10",f&&"opacity-95")},u):a("span",{className:"text-xs opacity-70",children:"[\u97F3\u9891\u65E0\u5730\u5740]"},u)}case"file":return o("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-xs mx-0.5",children:["\u{1F4CE} ",String(S.name||"\u6587\u4EF6")]},u);default:return o("span",{className:"text-xs opacity-70",children:["[",I.type,"]"]},u)}})},De=(e,f)=>{if(!Fe(f))return;let L={id:`msg_${Date.now()}`,type:"sent",channelType:g.type,channelId:g.id,channelName:g.name,senderId:"test_user",senderName:"\u6D4B\u8BD5\u7528\u6237",content:f,timestamp:Date.now()};m(I=>[...I,L]),F(""),T([]),U.current?.clear(),j.current?.send(JSON.stringify({type:g.type,id:g.id,content:f,timestamp:Date.now()}))},Ze=()=>{confirm("\u786E\u5B9A\u6E05\u7A7A\u6240\u6709\u6D88\u606F\u8BB0\u5F55\uFF1F")&&m([])},Qe=e=>{he("chat"),n(e),x(f=>f.map(L=>L.id===e.id?{...L,unread:0}:L)),window.innerWidth<768&&q(!1)},_e=()=>{let e=["private","group","channel"],f=e[Math.floor(Math.random()*e.length)],L=prompt("\u8BF7\u8F93\u5165\u9891\u9053\u540D\u79F0\uFF1A");if(L){let I={id:`${f}_${Date.now()}`,name:L,type:f,unread:0};x(u=>[...u,I]),n(I)}},Re=e=>{switch(e){case"private":return a(K,{size:16});case"group":return a(ie,{size:16});case"channel":return a(oe,{size:16});default:return a(O,{size:16})}},Je=e=>{U.current?.insertFace(e),B(!1)},be=()=>{let e=Y.trim();!e||!P||(P==="image"?U.current?.insertImage(e):P==="video"?U.current?.insertVideo(e):U.current?.insertAudio(e),Le(""),G(null))},Da=()=>{s.trim()&&(U.current?.insertAt(s.trim()),c(""),ge(!1))},je=e=>{U.current?.replaceAtTrigger(e.name,e.id),_(null),t("")},$e=(e,f,L)=>{if(g.type==="private"){_(null),t("");return}e&&L?(_(L),t(f)):(_(null),t(""))},ve=A.filter(e=>{if(!d.trim())return!0;let f=d.toLowerCase();return e.name.toLowerCase().includes(f)||e.id.toLowerCase().includes(f)}),Ye=(e,f)=>{F(e),T(f)},Te=N.filter(e=>e.name.toLowerCase().includes(l.toLowerCase())||e.describe.toLowerCase().includes(l.toLowerCase())),ke=p.filter(e=>e.channelId===g.id);return o("div",{className:"sandbox-container rounded-xl border border-border/70 bg-card/30 shadow-sm",children:[o("button",{className:"mobile-channel-toggle md:hidden",onClick:()=>q(!R),children:[a(O,{size:20})," \u9891\u9053\u5217\u8868"]}),o("div",{className:M("channel-sidebar rounded-lg border bg-card",R&&"show"),children:[a("div",{className:"p-3 border-b",children:o("div",{className:"flex justify-between items-center",children:[o("div",{className:"flex items-center gap-2",children:[a("div",{className:"p-1 rounded-md bg-secondary",children:a(O,{size:16,className:"text-muted-foreground"})}),a("h3",{className:"font-semibold",children:"\u9891\u9053\u5217\u8868"})]}),o("span",{className:M("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border",E?"bg-emerald-100 text-emerald-800 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800":"bg-muted text-muted-foreground"),children:[E?a(pe,{size:12}):a(ne,{size:12}),E?"\u5DF2\u8FDE\u63A5":"\u672A\u8FDE\u63A5"]})]})}),o("div",{className:"flex-1 overflow-y-auto p-2 space-y-1",children:[h.map(e=>{let f=J==="chat"&&g.id===e.id;return o("div",{className:M("menu-item",f&&"active"),onClick:()=>Qe(e),children:[a("span",{className:"shrink-0",children:Re(e.type)}),o("div",{className:"flex-1 min-w-0",children:[a("div",{className:"text-sm font-medium truncate",children:e.name}),a("div",{className:"text-xs text-muted-foreground",children:e.type==="private"?"\u79C1\u804A":e.type==="group"?"\u7FA4\u804A":"\u9891\u9053"})]}),e.unread>0&&a("span",{className:"inline-flex items-center justify-center h-5 min-w-5 rounded-full bg-destructive text-destructive-foreground text-[10px] font-medium px-1",children:e.unread})]},e.id)}),o("div",{className:"pt-2 mt-2 border-t space-y-1",children:[o("div",{className:M("menu-item",J==="requests"&&"active"),onClick:()=>{he("requests"),window.innerWidth<768&&q(!1)},children:[a(X,{size:16,className:"shrink-0"}),o("div",{className:"flex-1 min-w-0",children:[a("div",{className:"text-sm font-medium",children:"\u8BF7\u6C42"}),a("div",{className:"text-xs text-muted-foreground",children:"\u597D\u53CB/\u7FA4\u9080\u8BF7\u7B49"})]})]}),o("div",{className:M("menu-item",J==="notices"&&"active"),onClick:()=>{he("notices"),window.innerWidth<768&&q(!1)},children:[a(z,{size:16,className:"shrink-0"}),o("div",{className:"flex-1 min-w-0",children:[a("div",{className:"text-sm font-medium",children:"\u901A\u77E5"}),a("div",{className:"text-xs text-muted-foreground",children:"\u7FA4\u7BA1/\u64A4\u56DE\u7B49"})]})]})]})]}),a("div",{className:"p-2 border-t",children:a("button",{className:"w-full py-2 px-3 rounded-md border border-dashed text-sm text-muted-foreground hover:bg-accent transition-colors",onClick:_e,children:"+ \u6DFB\u52A0\u9891\u9053"})})]}),R&&a("div",{className:"channel-overlay md:hidden",onClick:()=>q(!1)}),o("div",{className:"chat-area",children:[J==="requests"&&o("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden",children:[a("div",{className:"p-3 border-b flex-shrink-0",children:o("h2",{className:"text-lg font-bold flex items-center gap-2",children:[a(X,{size:20})," \u8BF7\u6C42"]})}),o("div",{className:"flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center",children:[a(X,{size:48,className:"opacity-30"}),a("span",{children:"\u6C99\u76D2\u4E3A\u6A21\u62DF\u73AF\u5883\uFF0C\u6682\u65E0\u8BF7\u6C42\u6570\u636E"}),o("span",{className:"text-sm",children:["\u5B9E\u9645\u597D\u53CB/\u7FA4\u9080\u8BF7\u7B49\u8BF7\u6C42\u8BF7\u5230\u4FA7\u8FB9\u680F ",a("strong",{children:"\u673A\u5668\u4EBA"})," \u9875\u9762\u8FDB\u5165\u5BF9\u5E94\u673A\u5668\u4EBA\u7BA1\u7406\u67E5\u770B"]})]})]}),J==="notices"&&o("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden",children:[a("div",{className:"p-3 border-b flex-shrink-0",children:o("h2",{className:"text-lg font-bold flex items-center gap-2",children:[a(z,{size:20})," \u901A\u77E5"]})}),o("div",{className:"flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center",children:[a(z,{size:48,className:"opacity-30"}),a("span",{children:"\u6C99\u76D2\u4E3A\u6A21\u62DF\u73AF\u5883\uFF0C\u6682\u65E0\u901A\u77E5\u6570\u636E"}),o("span",{className:"text-sm",children:["\u5B9E\u9645\u7FA4\u7BA1\u3001\u64A4\u56DE\u7B49\u901A\u77E5\u8BF7\u5230\u4FA7\u8FB9\u680F ",a("strong",{children:"\u673A\u5668\u4EBA"})," \u9875\u9762\u8FDB\u5165\u5BF9\u5E94\u673A\u5668\u4EBA\u7BA1\u7406\u67E5\u770B"]})]})]}),J==="chat"&&o(Fa,{children:[a("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0",children:o("div",{className:"flex justify-between items-center flex-wrap gap-2",children:[o("div",{className:"flex items-center gap-3",children:[a("div",{className:"p-2 rounded-lg bg-secondary",children:Re(g.type)}),o("div",{children:[a("h2",{className:"text-lg font-bold",children:g.name}),o("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[a("span",{children:g.id}),a("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-[10px]",children:ke.length}),a("span",{children:"\u6761\u6D88\u606F"})]})]}),a("span",{className:"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-secondary text-secondary-foreground",children:g.type==="private"?"\u79C1\u804A":g.type==="group"?"\u7FA4\u804A":"\u9891\u9053"})]}),o("div",{className:"flex items-center gap-2",children:[a("input",{value:b,onChange:e=>Z(e.target.value),placeholder:"\u673A\u5668\u4EBA\u540D\u79F0",className:"h-8 w-28 rounded-md border bg-transparent px-2 text-sm"}),o("button",{className:"inline-flex items-center gap-1 h-8 px-3 rounded-md bg-secondary text-secondary-foreground text-sm hover:bg-secondary/80",onClick:Ze,children:[a(fe,{size:14})," \u6E05\u7A7A"]})]})]})}),a("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0",children:a("div",{className:"flex-1 overflow-y-auto p-4",children:ke.length===0?o("div",{className:"flex flex-col items-center justify-center h-full gap-3",children:[a(O,{size:64,className:"text-muted-foreground/20"}),a("span",{className:"text-muted-foreground",children:"\u6682\u65E0\u6D88\u606F\uFF0C\u5F00\u59CB\u5BF9\u8BDD\u5427\uFF01"})]}):o("div",{className:"space-y-2",children:[ke.map(e=>a("div",{className:M("flex",e.type==="sent"?"justify-end":"justify-start"),children:o("div",{className:M("max-w-[70%] p-3 rounded-2xl",e.type==="sent"?"bg-primary text-primary-foreground":"bg-muted"),children:[o("div",{className:"flex items-center gap-2 mb-1",children:[e.type==="received"&&a(ae,{size:14}),e.type==="sent"&&a(K,{size:14}),a("span",{className:"text-xs font-medium opacity-90",children:e.senderName}),a("span",{className:"text-xs opacity-70",children:new Date(e.timestamp).toLocaleTimeString()})]}),a("div",{className:"text-sm space-y-1",children:Ke(e.content,e.type==="sent")})]})},e.id)),a("div",{ref:Be})]})})}),o("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0 space-y-3",children:[o("div",{className:"flex gap-2 items-center flex-wrap",children:[a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",H?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{B(!H),G(null)},title:"\u63D2\u5165\u8868\u60C5",children:a(re,{size:16})}),a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",P==="image"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{G(e=>e==="image"?null:"image"),B(!1)},title:"\u63D2\u5165\u56FE\u7247 URL",children:a(de,{size:16})}),a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",P==="video"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{G(e=>e==="video"?null:"video"),B(!1)},title:"\u63D2\u5165\u89C6\u9891 URL",children:a(ce,{size:16})}),a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",P==="audio"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{G(e=>e==="audio"?null:"audio"),B(!1)},title:"\u63D2\u5165\u97F3\u9891 URL",children:a(le,{size:16})}),a("div",{className:"flex-1 min-w-[1rem]"}),w&&a("button",{className:"h-8 w-8 rounded-md flex items-center justify-center hover:bg-accent transition-colors",onClick:()=>{F(""),T([])},children:a(me,{size:16})})]}),H&&o("div",{className:"p-3 rounded-md border bg-muted/30 max-h-64 overflow-y-auto space-y-2",children:[a("input",{value:l,onChange:e=>i(e.target.value),placeholder:"\u641C\u7D22\u8868\u60C5...",className:"w-full h-8 rounded-md border bg-transparent px-2 text-sm"}),a("div",{className:"grid grid-cols-8 gap-1",children:Te.slice(0,80).map(e=>a("button",{onClick:()=>Je(e.id),title:e.name,className:"w-10 h-10 rounded-md border flex items-center justify-center hover:bg-accent transition-colors",children:a("img",{src:`https://face.viki.moe/apng/${e.id}.png`,alt:e.name,className:"w-8 h-8"})},e.id))}),Te.length===0&&o("div",{className:"flex flex-col items-center gap-2 py-4",children:[a($,{size:32,className:"text-muted-foreground/30"}),a("span",{className:"text-sm text-muted-foreground",children:"\u672A\u627E\u5230\u5339\u914D\u7684\u8868\u60C5"})]})]}),P&&o("div",{className:"p-3 rounded-md border bg-muted/30 space-y-2",children:[o("p",{className:"text-xs text-muted-foreground",children:[P==="image"&&"\u652F\u6301 http(s) \u56FE\u7247\u94FE\u63A5\u6216 data URL",P==="video"&&"\u652F\u6301\u6D4F\u89C8\u5668\u53EF\u89E3\u7801\u7684\u89C6\u9891\u76F4\u94FE\uFF08\u5982 .mp4\u3001.webm\uFF09",P==="audio"&&"\u652F\u6301 .mp3\u3001.ogg\u3001.wav \u7B49\u97F3\u9891\u76F4\u94FE"]}),a("input",{value:Y,onChange:e=>Le(e.target.value),placeholder:P==="image"?"\u56FE\u7247 URL\u2026":P==="video"?"\u89C6\u9891 URL\u2026":"\u97F3\u9891 URL\u2026",className:"w-full h-8 rounded-md border border-input bg-background px-2 text-sm",onKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),be())}}),o("button",{type:"button",className:"inline-flex items-center gap-1 h-8 px-3 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50",onClick:be,disabled:!Y.trim(),children:[a(te,{size:14})," \u63D2\u5165\u5230\u8F93\u5165\u6846"]})]}),o("div",{className:"flex gap-2 items-start",children:[o("div",{className:"flex-1 relative",children:[a(Ve,{ref:U,placeholder:`\u5411 ${g.name} \u53D1\u9001\u6D88\u606F...`,onSend:De,onChange:Ye,onAtTrigger:$e,minHeight:"44px",maxHeight:"200px"}),ee&&a("div",{className:"absolute z-50 rounded-lg border bg-popover shadow-md min-w-60 max-h-72 overflow-y-auto p-1",style:{top:`${ee.top}px`,left:`${ee.left}px`},children:ve.length>0?ve.map(e=>o("div",{className:"flex items-center gap-2 p-2 rounded-md cursor-pointer hover:bg-accent transition-colors",onClick:()=>je(e),children:[a(K,{size:16,className:"text-muted-foreground"}),o("div",{className:"flex-1",children:[a("div",{className:"text-sm font-medium",children:e.name}),o("div",{className:"text-xs text-muted-foreground",children:["ID: ",e.id]})]})]},e.id)):o("div",{className:"flex flex-col items-center gap-2 p-4",children:[a($,{size:20,className:"text-muted-foreground/50"}),a("span",{className:"text-xs text-muted-foreground",children:"\u672A\u627E\u5230\u5339\u914D\u7684\u7528\u6237"})]})})]}),o("button",{className:"inline-flex items-center gap-1.5 h-10 px-4 rounded-md bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50 transition-colors hover:bg-primary/90",onClick:()=>{let e=U.current?.getContent();e&&De(e.text,e.segments)},disabled:!Fe(W),children:[a(se,{size:16})," \u53D1\u9001"]})]}),o("div",{className:"flex items-center gap-2 flex-wrap text-xs text-muted-foreground",children:[a(ue,{size:12})," \u5FEB\u6377\u64CD\u4F5C:",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Enter"})," \u53D1\u9001",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Shift+Enter"})," \u6362\u884C",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[@\u540D\u79F0]"})," @\u67D0\u4EBA",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[video:URL]"}),a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[audio:URL]"})]})]})]})]})]})}function Co(p){p.addRoute({path:"/console/sandbox",name:"\u6C99\u76D2",element:p.React.createElement(Me,{hostReact:p.React})}),p.addTool({id:"sandbox",name:"\u6C99\u76D2",path:"/console/sandbox"})}export{Co as register};
|
|
1
|
+
import ea,{useState as k,useEffect as he,useRef as Q}from"react";import{cn as M,resolveMediaSrc as Fe,pickMediaRawUrl as De}from"@zhin.js/client";function We(){let r=localStorage.getItem("zhin_api_base")?.trim();return(r?r.replace(/\/$/,""):null)??window.location.origin}function Ve(){let r="zhin_sandbox_session",c=sessionStorage.getItem(r)?.trim();return c||(c=crypto.randomUUID(),sessionStorage.setItem(r,c)),c}function Ae(){let r=localStorage.getItem("HTTP_TOKEN")?.trim()||localStorage.getItem("zhin_http_token")?.trim()||"";return r?{Authorization:`Bearer ${r}`}:{}}function Me(){try{let r=new URL(import.meta.url);if(r.searchParams.get("transport")==="http-sse"||r.searchParams.get("v")==="edge")return"http-sse"}catch{}return null}async function ca(r,c){let C=await fetch(new URL(c,`${r.replace(/\/$/,"")}/`).href);return C.ok&&(await C.json()).sandboxTransport==="http-sse"?"http-sse":null}async function ze(r){let c=Me();if(c)return c;let C=localStorage.getItem("zhin_sandbox_transport")?.trim();if(C==="http-sse"||C==="websocket")return C;for(let L of["/entries","/api/info"])try{let D=await ca(r,L);if(D)return D}catch{}return"websocket"}import{forwardRef as xa,createElement as Ia}from"react";var Ce=(...r)=>r.filter((c,C,L)=>!!c&&c.trim()!==""&&L.indexOf(c)===C).join(" ").trim();var Xe=r=>r.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();var Ke=r=>r.replace(/^([A-Z])|[\s-_]+(\w)/g,(c,C,L)=>L?L.toUpperCase():C.toLowerCase());var Be=r=>{let c=Ke(r);return c.charAt(0).toUpperCase()+c.slice(1)};import{forwardRef as La,createElement as Qe}from"react";var ge={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};var Ze=r=>{for(let c in r)if(c.startsWith("aria-")||c==="role"||c==="title")return!0;return!1};import{createContext as na,useContext as pa,useMemo as ja,createElement as $a}from"react";var ma=na({});var _e=()=>pa(ma);var Je=La(({color:r,size:c,strokeWidth:C,absoluteStrokeWidth:L,className:D="",children:b,iconNode:w,...m},P)=>{let{size:F=24,strokeWidth:O=2,absoluteStrokeWidth:J=!1,color:W="currentColor",className:v=""}=_e()??{},N=L??J?Number(C??O)*24/Number(c??F):C??O;return Qe("svg",{ref:P,...ge,width:c??F??ge.width,height:c??F??ge.height,stroke:r??W,strokeWidth:N,className:Ce("lucide",v,D),...!b&&!Ze(m)&&{"aria-hidden":"true"},...m},[...w.map(([B,y])=>Qe(B,y)),...Array.isArray(b)?b:[b]])});var i=(r,c)=>{let C=xa(({className:L,...D},b)=>Ia(Je,{ref:b,iconNode:c,className:Ce(`lucide-${Xe(Be(r))}`,`lucide-${r}`,L),...D}));return C.displayName=Be(r),C};var Ca=[["path",{d:"M10.268 21a2 2 0 0 0 3.464 0",key:"vwvbt9"}],["path",{d:"M3.262 15.326A1 1 0 0 0 4 17h16a1 1 0 0 0 .74-1.673C19.41 13.956 18 12.499 18 8A6 6 0 0 0 6 8c0 4.499-1.411 5.956-2.738 7.326",key:"11g9vi"}]],K=i("bell",Ca);var ga=[["path",{d:"M12 8V4H8",key:"hb8ula"}],["rect",{width:"16",height:"12",x:"4",y:"8",rx:"2",key:"enze0r"}],["path",{d:"M2 14h2",key:"vft8re"}],["path",{d:"M20 14h2",key:"4cs60a"}],["path",{d:"M15 13v2",key:"1xurst"}],["path",{d:"M9 13v2",key:"rq6x2g"}]],oe=i("bot",ga);var ha=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],de=i("check",ha);var Sa=[["line",{x1:"4",x2:"20",y1:"9",y2:"9",key:"4lhtct"}],["line",{x1:"4",x2:"20",y1:"15",y2:"15",key:"vyu0kd"}],["line",{x1:"10",x2:"8",y1:"3",y2:"21",key:"1ggp8o"}],["line",{x1:"16",x2:"14",y1:"3",y2:"21",key:"weycgp"}]],ue=i("hash",Sa);var ka=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",ry:"2",key:"1m3agn"}],["circle",{cx:"9",cy:"9",r:"2",key:"af1f0g"}],["path",{d:"m21 15-3.086-3.086a2 2 0 0 0-2.828 0L6 21",key:"1xmnt7"}]],le=i("image",ka);var wa=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M12 16v-4",key:"1dtifu"}],["path",{d:"M12 8h.01",key:"e9boi3"}]],re=i("info",wa);var Pa=[["path",{d:"M22 17a2 2 0 0 1-2 2H6.828a2 2 0 0 0-1.414.586l-2.202 2.202A.71.71 0 0 1 2 21.286V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2z",key:"18887p"}]],G=i("message-square",Pa);var ya=[["path",{d:"M9 18V5l12-2v13",key:"1jmyc2"}],["circle",{cx:"6",cy:"18",r:"3",key:"fqmcym"}],["circle",{cx:"18",cy:"16",r:"3",key:"1hluhg"}]],se=i("music",ya);var Aa=[["path",{d:"m21 21-4.34-4.34",key:"14j7rj"}],["circle",{cx:"11",cy:"11",r:"8",key:"4ej97u"}]],Y=i("search",Aa);var Ma=[["path",{d:"M14.536 21.686a.5.5 0 0 0 .937-.024l6.5-19a.496.496 0 0 0-.635-.635l-19 6.5a.5.5 0 0 0-.024.937l7.93 3.18a2 2 0 0 1 1.112 1.11z",key:"1ffxy3"}],["path",{d:"m21.854 2.147-10.94 10.939",key:"12cjpa"}]],fe=i("send",Ma);var Ba=[["circle",{cx:"12",cy:"12",r:"10",key:"1mglay"}],["path",{d:"M8 14s1.5 2 4 2 4-2 4-2",key:"1y1vjs"}],["line",{x1:"9",x2:"9.01",y1:"9",y2:"9",key:"yxxnd0"}],["line",{x1:"15",x2:"15.01",y1:"9",y2:"9",key:"1p4y9e"}]],ie=i("smile",Ba);var Fa=[["path",{d:"M10 11v6",key:"nco0om"}],["path",{d:"M14 11v6",key:"outv1u"}],["path",{d:"M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6",key:"miytrc"}],["path",{d:"M3 6h18",key:"d0wm0j"}],["path",{d:"M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2",key:"e791ji"}]],ce=i("trash-2",Fa);var Da=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}],["line",{x1:"19",x2:"19",y1:"8",y2:"14",key:"1bvyxn"}],["line",{x1:"22",x2:"16",y1:"11",y2:"11",key:"1shjgl"}]],Z=i("user-plus",Da);var ba=[["path",{d:"M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2",key:"975kel"}],["circle",{cx:"12",cy:"7",r:"4",key:"17ys0d"}]],_=i("user",ba);var Ra=[["path",{d:"M16 21v-2a4 4 0 0 0-4-4H6a4 4 0 0 0-4 4v2",key:"1yyitq"}],["path",{d:"M16 3.128a4 4 0 0 1 0 7.744",key:"16gr8j"}],["path",{d:"M22 21v-2a4 4 0 0 0-3-3.87",key:"kshegd"}],["circle",{cx:"9",cy:"7",r:"4",key:"nufk8"}]],ne=i("users",Ra);var va=[["path",{d:"m16 13 5.223 3.482a.5.5 0 0 0 .777-.416V7.87a.5.5 0 0 0-.752-.432L16 10.5",key:"ftymec"}],["rect",{x:"2",y:"6",width:"14",height:"12",rx:"2",key:"158x01"}]],pe=i("video",va);var Ta=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}],["path",{d:"M5 12.859a10 10 0 0 1 5.17-2.69",key:"1dl1wf"}],["path",{d:"M19 12.859a10 10 0 0 0-2.007-1.523",key:"4k23kn"}],["path",{d:"M2 8.82a15 15 0 0 1 4.177-2.643",key:"1grhjp"}],["path",{d:"M22 8.82a15 15 0 0 0-11.288-3.764",key:"z3jwby"}],["path",{d:"m2 2 20 20",key:"1ooewy"}]],me=i("wifi-off",Ta);var qa=[["path",{d:"M12 20h.01",key:"zekei9"}],["path",{d:"M2 8.82a15 15 0 0 1 20 0",key:"dnpr2z"}],["path",{d:"M5 12.859a10 10 0 0 1 14 0",key:"1x1e6c"}],["path",{d:"M8.5 16.429a5 5 0 0 1 7 0",key:"1bycff"}]],Le=i("wifi",qa);var Ua=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],xe=i("x",Ua);import{useRef as je,forwardRef as Ha,useImperativeHandle as Oa}from"react";import{jsx as Na}from"react/jsx-runtime";var $e=Ha(({placeholder:r="\u8F93\u5165\u6D88\u606F...",onSend:c,onChange:C,onAtTrigger:L,minHeight:D="44px",maxHeight:b="200px"},w)=>{let m=je(null),P=je(null),F=()=>{if(!m.current)return{text:"",segments:[]};let d="",t=[],u=Array.from(m.current.childNodes);for(let n of u)if(n.nodeType===Node.TEXT_NODE){let f=n.textContent||"";f&&(d+=f,t.push({type:"text",data:{text:f}}))}else if(n.nodeType===Node.ELEMENT_NODE){let f=n;if(f.classList.contains("editor-face")){let p=f.dataset.id;d+=`[face:${p}]`,t.push({type:"face",data:{id:Number(p)}})}else if(f.classList.contains("editor-image")){let p=f.dataset.url;d+=`[image:${p}]`,t.push({type:"image",data:{url:p}})}else if(f.classList.contains("editor-video")){let p=f.dataset.url||"";d+=`[video:${p}]`,t.push({type:"video",data:{url:p}})}else if(f.classList.contains("editor-audio")){let p=f.dataset.url||"";d+=`[audio:${p}]`,t.push({type:"audio",data:{url:p}})}else if(f.classList.contains("editor-at")){let p=f.dataset.name,A=f.dataset.id;d+=`[@${p}]`,t.push({type:"at",data:{name:p,qq:A}})}else f.tagName==="BR"&&(d+=`
|
|
2
|
+
`)}return{text:d,segments:t}},O=d=>{if(!m.current)return;let t=document.createElement("img");t.src=`https://face.viki.moe/apng/${d}.png`,t.alt=`[face:${d}]`,t.dataset.type="face",t.dataset.id=String(d),t.className="editor-face",B(t),T()},J=d=>{if(!m.current||!d.trim())return;let t=document.createElement("img");t.src=d.trim(),t.alt=`[image:${d.trim()}]`,t.dataset.type="image",t.dataset.url=d.trim(),t.className="editor-image",B(t),T()},W=d=>{if(!m.current||!d.trim())return;let t=d.trim(),u=document.createElement("span");u.className="editor-video",u.dataset.url=t,u.contentEditable="false",u.textContent="\u{1F4F9} \u89C6\u9891",B(u),T()},v=d=>{if(!m.current||!d.trim())return;let t=d.trim(),u=document.createElement("span");u.className="editor-audio",u.dataset.url=t,u.contentEditable="false",u.textContent="\u{1F3B5} \u97F3\u9891",B(u),T()},N=(d,t)=>{if(!m.current||!d.trim())return;let u=document.createElement("span");u.dataset.type="at",u.dataset.name=d,t&&(u.dataset.id=t),u.className="editor-at",u.contentEditable="false";let n=document.createElement("span");n.textContent="@",n.className="editor-at-symbol";let f=document.createElement("span");f.textContent=d,f.className="editor-at-name",u.appendChild(n),u.appendChild(f),B(u),T()},B=d=>{if(!m.current)return;m.current.focus();let t=window.getSelection();if(t&&t.rangeCount>0){let u=t.getRangeAt(0);if(m.current.contains(u.commonAncestorContainer))u.deleteContents(),u.insertNode(d),u.collapse(!1),t.removeAllRanges(),t.addRange(u);else{m.current.appendChild(d);let f=document.createRange();f.setStartAfter(d),f.collapse(!0),t.removeAllRanges(),t.addRange(f)}}else{m.current.appendChild(d);let u=window.getSelection();if(u){let n=document.createRange();n.setStartAfter(d),n.collapse(!0),u.removeAllRanges(),u.addRange(n)}}},y=()=>{m.current&&(m.current.innerHTML="",T())},V=()=>{m.current?.focus()},ee=()=>F(),Ie=()=>{if(!m.current||!L)return;let d=window.getSelection();if(!d||d.rangeCount===0){L(!1,""),P.current=null;return}let t=d.getRangeAt(0);if(!m.current.contains(t.commonAncestorContainer)){L(!1,""),P.current=null;return}let u=t.startContainer;if(u.nodeType!==Node.TEXT_NODE){L(!1,""),P.current=null;return}let n=u,f=n.textContent?.substring(0,t.startOffset)||"",p=f.lastIndexOf("@");if(p!==-1){let A=f.substring(p+1);if(A.includes(" ")||A.includes(`
|
|
3
|
+
`)){L(!1,""),P.current=null;return}P.current=n;let z=document.createRange();z.setStart(n,p),z.setEnd(n,p+1);let q=z.getBoundingClientRect(),R=m.current.getBoundingClientRect();L(!0,A,{top:q.bottom-R.top,left:q.left-R.left})}else L(!1,""),P.current=null},T=()=>{if(Ie(),C){let{text:d,segments:t}=F();C(d,t)}},Se=(d,t)=>{if(!P.current)return;let u=P.current,n=u.textContent||"",f=n.lastIndexOf("@");if(f!==-1){let p=n.substring(f+1),A=f+1+p.split(/[\s\n]/)[0].length,z=n.substring(0,f),q=n.substring(A);u.textContent=z+q;let R=window.getSelection();if(R){let U=document.createRange();U.setStart(u,f),U.collapse(!0),R.removeAllRanges(),R.addRange(U)}}P.current=null,N(d,t)},ae=d=>{d.preventDefault();let t=d.clipboardData,n=Array.from(t.items).find(p=>p.type.startsWith("image/"));if(n){let p=n.getAsFile();if(p){let A=new FileReader;A.onload=()=>{typeof A.result=="string"&&J(A.result)},A.readAsDataURL(p)}return}let f=t.getData("text/plain");f&&(document.execCommand("insertText",!1,f),T())},j=d=>{if(d.key==="Enter"&&!d.shiftKey&&(d.preventDefault(),c)){let{text:t,segments:u}=F();c(t,u)}};return Oa(w,()=>({focus:V,clear:y,insertFace:O,insertImage:J,insertVideo:W,insertAudio:v,insertAt:N,replaceAtTrigger:Se,getContent:ee})),Na("div",{ref:m,contentEditable:!0,suppressContentEditableWarning:!0,onInput:T,onKeyDown:j,onPaste:ae,"data-placeholder":r,className:"rich-text-editor",style:{width:"100%",minHeight:D,maxHeight:b,padding:"0.5rem 0.75rem",border:"1px solid var(--gray-6)",borderRadius:"6px",backgroundColor:"var(--gray-1)",fontSize:"var(--font-size-2)",outline:"none",overflowY:"auto",lineHeight:"1.5",wordWrap:"break-word",color:"var(--gray-12)"}})});$e.displayName="RichTextEditor";var Ye=$e;import{Fragment as Ea,jsx as a,jsxs as o}from"react/jsx-runtime";function be(){let[r,c]=k([]),[C,L]=k([{id:"user_1001",name:"\u6D4B\u8BD5\u7528\u6237",type:"private",unread:0},{id:"group_2001",name:"\u6D4B\u8BD5\u7FA4\u7EC4",type:"group",unread:0},{id:"channel_3001",name:"\u6D4B\u8BD5\u9891\u9053",type:"channel",unread:0}]),[D,b]=k([]),[w,m]=k(C[0]),[P,F]=k(""),[O,J]=k("ProcessBot"),[W,v]=k(!1),[N,B]=k(!1),[y,V]=k(null),[ee,Ie]=k(""),[T,Se]=k(!1),[ae,j]=k(null),[d,t]=k(""),[u,n]=k(""),[f,p]=k(""),[A]=k([{id:"10001",name:"\u5F20\u4E09"},{id:"10002",name:"\u674E\u56DB"},{id:"10003",name:"\u738B\u4E94"},{id:"10004",name:"\u8D75\u516D"},{id:"10005",name:"\u6D4B\u8BD5\u7528\u6237"},{id:"10086",name:"Admin"},{id:"10010",name:"Test User"}]),[z,q]=k([]),[R,U]=k(!1),[$,ke]=k("chat"),Re=Q(null),E=Q(null),X=Q(null),we=Q("websocket"),ve=Q(""),Te=Q(""),H=Q(null),aa=async()=>{try{let e=await fetch("https://face.viki.moe/metadata.json");b(await e.json())}catch(e){console.error("[Sandbox] Failed to fetch face list:",e)}};he(()=>{aa()},[]);let qe=e=>{let s=typeof e.content=="string"?Pe(e.content):Array.isArray(e.content)?e.content:Pe(String(e.content??"")),x=e.type==="private"?`\u79C1\u804A-${e.bot||O}`:e.type==="group"?`\u7FA4\u7EC4-${e.id}`:`\u9891\u9053-${e.id}`,I=e.type;L(l=>{if(l.some(h=>h.id===e.id))return l;let g={id:e.id,name:x,type:I,unread:0};return m(g),[...l,g]}),c(l=>[...l,{id:`bot_${e.timestamp}`,type:"received",channelType:I,channelId:e.id,channelName:x,senderId:"bot",senderName:e.bot||O,content:s,timestamp:e.timestamp}])};he(()=>{let e=!1,s=We(),x=Ve();ve.current=s,Te.current=x;let I=()=>{if(E.current)return;we.current="websocket";let h=new URL("/sandbox",`${s}/`);h.protocol=h.protocol==="https:"?"wss:":"ws:",E.current=new WebSocket(h.href),E.current.onopen=()=>v(!0),E.current.onmessage=S=>{try{qe(JSON.parse(S.data))}catch(te){console.error("[Sandbox] Failed to parse message:",te)}},E.current.onclose=()=>v(!1)},l=()=>{if(X.current)return;we.current="http-sse";let h=new URL("/sandbox/events",`${s}/`);h.searchParams.set("session",x);let S=Ae().Authorization;S?.startsWith("Bearer ")&&h.searchParams.set("access_token",S.slice(7)),X.current=new EventSource(h.href),X.current.onopen=()=>v(!0),X.current.onmessage=te=>{try{qe(JSON.parse(te.data))}catch(ia){console.error("[Sandbox] Failed to parse SSE message:",ia)}},X.current.onerror=()=>v(!1)};return Me()==="http-sse"?l():(async()=>{let h=await ze(s);e||(h==="http-sse"?l():I())})(),()=>{e=!0,E.current?.close(),E.current=null,X.current?.close(),X.current=null,v(!1)}},[]),he(()=>{Re.current?.scrollIntoView({behavior:"smooth"})},[r]),he(()=>{q(P.trim()?Pe(P):[])},[P]);let Pe=e=>{let s=[],x=/\[@([^\]]+)\]|\[face:(\d+)\]|\[image:([^\]]+)\]|\[video:([^\]]+)\]|\[audio:([^\]]+)\]/g,I=0,l;for(;(l=x.exec(e))!==null;){if(l.index>I){let g=e.substring(I,l.index);g&&s.push({type:"text",data:{text:g}})}l[1]?s.push({type:"at",data:{qq:l[1],name:l[1]}}):l[2]?s.push({type:"face",data:{id:parseInt(l[2],10)}}):l[3]?s.push({type:"image",data:{url:l[3]}}):l[4]?s.push({type:"video",data:{url:l[4]}}):l[5]&&s.push({type:"audio",data:{url:l[5]}}),I=x.lastIndex}if(I<e.length){let g=e.substring(I);g&&s.push({type:"text",data:{text:g}})}return s.length>0?s:[{type:"text",data:{text:e}}]},Ue=e=>e.length===0?!1:e.some(s=>s.type==="text"?!!String(s.data?.text??"").trim():!0),ta=(e,s)=>{let x=s?"ring-1 ring-primary-foreground/25":"ring-1 ring-border/60";return e.map((I,l)=>{if(typeof I=="string")return a("span",{children:I.split(`
|
|
4
|
+
`).map((h,S)=>o(ea.Fragment,{children:[h,S<I.split(`
|
|
5
|
+
`).length-1&&a("br",{})]},S))},l);let g=I.data;switch(I.type){case"text":return a("span",{children:String(g.text??"").split(`
|
|
6
|
+
`).map((h,S)=>o(ea.Fragment,{children:[h,S<String(g.text??"").split(`
|
|
7
|
+
`).length-1&&a("br",{})]},S))},l);case"at":return o("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded bg-accent text-accent-foreground text-xs mx-0.5",children:["@",String(g.name??g.qq??"")]},l);case"face":return a("img",{src:`https://face.viki.moe/apng/${g.id}.png`,alt:"",className:"w-6 h-6 inline-block align-middle mx-0.5"},l);case"image":{let h=De(g),S=Fe(h,"image");return S?a("a",{href:S,target:"_blank",rel:"noreferrer",className:"block my-1",children:a("img",{src:S,alt:"",className:M("max-w-[min(320px,88vw)] rounded-lg block",x,"ring-offset-0"),onError:te=>{te.target.style.display="none"}})},l):a("span",{className:"text-xs opacity-70",children:"[\u56FE\u7247]"},l)}case"video":{let h=De(g),S=Fe(h,"video");return S?a("video",{src:S,controls:!0,playsInline:!0,preload:"metadata",className:M("max-w-[min(360px,92vw)] max-h-72 rounded-lg my-1 bg-black/10",x)},l):a("span",{className:"text-xs opacity-70",children:"[\u89C6\u9891\u65E0\u5730\u5740]"},l)}case"audio":case"record":{let h=De(g),S=Fe(h,"audio");return S?a("audio",{src:S,controls:!0,preload:"metadata",className:M("w-full max-w-sm my-2 h-10",s&&"opacity-95")},l):a("span",{className:"text-xs opacity-70",children:"[\u97F3\u9891\u65E0\u5730\u5740]"},l)}case"file":return o("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-xs mx-0.5",children:["\u{1F4CE} ",String(g.name||"\u6587\u4EF6")]},l);default:return o("span",{className:"text-xs opacity-70",children:["[",I.type,"]"]},l)}})},He=(e,s)=>{if(!Ue(s))return;let x={id:`msg_${Date.now()}`,type:"sent",channelType:w.type,channelId:w.id,channelName:w.name,senderId:"test_user",senderName:"\u6D4B\u8BD5\u7528\u6237",content:s,timestamp:Date.now()};c(l=>[...l,x]),F(""),q([]),H.current?.clear();let I=JSON.stringify({type:w.type,id:w.id,content:s,timestamp:Date.now()});if(we.current==="http-sse"){let l=new URL("/sandbox/message",`${ve.current}/`);fetch(l.href,{method:"POST",headers:{"Content-Type":"application/json","X-Sandbox-Session":Te.current,...Ae()},body:I}).catch(g=>console.error("[Sandbox] POST message failed:",g))}else E.current?.send(I)},oa=()=>{confirm("\u786E\u5B9A\u6E05\u7A7A\u6240\u6709\u6D88\u606F\u8BB0\u5F55\uFF1F")&&c([])},da=e=>{ke("chat"),m(e),L(s=>s.map(x=>x.id===e.id?{...x,unread:0}:x)),window.innerWidth<768&&U(!1)},ua=()=>{let e=["private","group","channel"],s=e[Math.floor(Math.random()*e.length)],x=prompt("\u8BF7\u8F93\u5165\u9891\u9053\u540D\u79F0\uFF1A");if(x){let I={id:`${s}_${Date.now()}`,name:x,type:s,unread:0};L(l=>[...l,I]),m(I)}},Oe=e=>{switch(e){case"private":return a(_,{size:16});case"group":return a(ne,{size:16});case"channel":return a(ue,{size:16});default:return a(G,{size:16})}},la=e=>{H.current?.insertFace(e),B(!1)},Ne=()=>{let e=ee.trim();!e||!y||(y==="image"?H.current?.insertImage(e):y==="video"?H.current?.insertVideo(e):H.current?.insertAudio(e),Ie(""),V(null))},Ga=()=>{f.trim()&&(H.current?.insertAt(f.trim()),p(""),Se(!1))},ra=e=>{H.current?.replaceAtTrigger(e.name,e.id),j(null),t("")},sa=(e,s,x)=>{if(w.type==="private"){j(null),t("");return}e&&x?(j(x),t(s)):(j(null),t(""))},Ee=A.filter(e=>{if(!d.trim())return!0;let s=d.toLowerCase();return e.name.toLowerCase().includes(s)||e.id.toLowerCase().includes(s)}),fa=(e,s)=>{F(e),q(s)},Ge=D.filter(e=>e.name.toLowerCase().includes(u.toLowerCase())||e.describe.toLowerCase().includes(u.toLowerCase())),ye=r.filter(e=>e.channelId===w.id);return o("div",{className:"sandbox-container rounded-xl border border-border/70 bg-card/30 shadow-sm",children:[o("button",{className:"mobile-channel-toggle md:hidden",onClick:()=>U(!R),children:[a(G,{size:20})," \u9891\u9053\u5217\u8868"]}),o("div",{className:M("channel-sidebar rounded-lg border bg-card",R&&"show"),children:[a("div",{className:"p-3 border-b",children:o("div",{className:"flex justify-between items-center",children:[o("div",{className:"flex items-center gap-2",children:[a("div",{className:"p-1 rounded-md bg-secondary",children:a(G,{size:16,className:"text-muted-foreground"})}),a("h3",{className:"font-semibold",children:"\u9891\u9053\u5217\u8868"})]}),o("span",{className:M("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border",W?"bg-emerald-100 text-emerald-800 border-emerald-200 dark:bg-emerald-900/30 dark:text-emerald-400 dark:border-emerald-800":"bg-muted text-muted-foreground"),children:[W?a(Le,{size:12}):a(me,{size:12}),W?"\u5DF2\u8FDE\u63A5":"\u672A\u8FDE\u63A5"]})]})}),o("div",{className:"flex-1 overflow-y-auto p-2 space-y-1",children:[C.map(e=>{let s=$==="chat"&&w.id===e.id;return o("div",{className:M("menu-item",s&&"active"),onClick:()=>da(e),children:[a("span",{className:"shrink-0",children:Oe(e.type)}),o("div",{className:"flex-1 min-w-0",children:[a("div",{className:"text-sm font-medium truncate",children:e.name}),a("div",{className:"text-xs text-muted-foreground",children:e.type==="private"?"\u79C1\u804A":e.type==="group"?"\u7FA4\u804A":"\u9891\u9053"})]}),e.unread>0&&a("span",{className:"inline-flex items-center justify-center h-5 min-w-5 rounded-full bg-destructive text-destructive-foreground text-[10px] font-medium px-1",children:e.unread})]},e.id)}),o("div",{className:"pt-2 mt-2 border-t space-y-1",children:[o("div",{className:M("menu-item",$==="requests"&&"active"),onClick:()=>{ke("requests"),window.innerWidth<768&&U(!1)},children:[a(Z,{size:16,className:"shrink-0"}),o("div",{className:"flex-1 min-w-0",children:[a("div",{className:"text-sm font-medium",children:"\u8BF7\u6C42"}),a("div",{className:"text-xs text-muted-foreground",children:"\u597D\u53CB/\u7FA4\u9080\u8BF7\u7B49"})]})]}),o("div",{className:M("menu-item",$==="notices"&&"active"),onClick:()=>{ke("notices"),window.innerWidth<768&&U(!1)},children:[a(K,{size:16,className:"shrink-0"}),o("div",{className:"flex-1 min-w-0",children:[a("div",{className:"text-sm font-medium",children:"\u901A\u77E5"}),a("div",{className:"text-xs text-muted-foreground",children:"\u7FA4\u7BA1/\u64A4\u56DE\u7B49"})]})]})]})]}),a("div",{className:"p-2 border-t",children:a("button",{className:"w-full py-2 px-3 rounded-md border border-dashed text-sm text-muted-foreground hover:bg-accent transition-colors",onClick:ua,children:"+ \u6DFB\u52A0\u9891\u9053"})})]}),R&&a("div",{className:"channel-overlay md:hidden",onClick:()=>U(!1)}),o("div",{className:"chat-area",children:[$==="requests"&&o("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden",children:[a("div",{className:"p-3 border-b flex-shrink-0",children:o("h2",{className:"text-lg font-bold flex items-center gap-2",children:[a(Z,{size:20})," \u8BF7\u6C42"]})}),o("div",{className:"flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center",children:[a(Z,{size:48,className:"opacity-30"}),a("span",{children:"\u6C99\u76D2\u4E3A\u6A21\u62DF\u73AF\u5883\uFF0C\u6682\u65E0\u8BF7\u6C42\u6570\u636E"}),o("span",{className:"text-sm",children:["\u5B9E\u9645\u597D\u53CB/\u7FA4\u9080\u8BF7\u7B49\u8BF7\u6C42\u8BF7\u5230\u4FA7\u8FB9\u680F ",a("strong",{children:"\u673A\u5668\u4EBA"})," \u9875\u9762\u8FDB\u5165\u5BF9\u5E94\u673A\u5668\u4EBA\u7BA1\u7406\u67E5\u770B"]})]})]}),$==="notices"&&o("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden",children:[a("div",{className:"p-3 border-b flex-shrink-0",children:o("h2",{className:"text-lg font-bold flex items-center gap-2",children:[a(K,{size:20})," \u901A\u77E5"]})}),o("div",{className:"flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center",children:[a(K,{size:48,className:"opacity-30"}),a("span",{children:"\u6C99\u76D2\u4E3A\u6A21\u62DF\u73AF\u5883\uFF0C\u6682\u65E0\u901A\u77E5\u6570\u636E"}),o("span",{className:"text-sm",children:["\u5B9E\u9645\u7FA4\u7BA1\u3001\u64A4\u56DE\u7B49\u901A\u77E5\u8BF7\u5230\u4FA7\u8FB9\u680F ",a("strong",{children:"\u673A\u5668\u4EBA"})," \u9875\u9762\u8FDB\u5165\u5BF9\u5E94\u673A\u5668\u4EBA\u7BA1\u7406\u67E5\u770B"]})]})]}),$==="chat"&&o(Ea,{children:[a("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0",children:o("div",{className:"flex justify-between items-center flex-wrap gap-2",children:[o("div",{className:"flex items-center gap-3",children:[a("div",{className:"p-2 rounded-lg bg-secondary",children:Oe(w.type)}),o("div",{children:[a("h2",{className:"text-lg font-bold",children:w.name}),o("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[a("span",{children:w.id}),a("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-[10px]",children:ye.length}),a("span",{children:"\u6761\u6D88\u606F"})]})]}),a("span",{className:"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-secondary text-secondary-foreground",children:w.type==="private"?"\u79C1\u804A":w.type==="group"?"\u7FA4\u804A":"\u9891\u9053"})]}),o("div",{className:"flex items-center gap-2",children:[a("input",{value:O,onChange:e=>J(e.target.value),placeholder:"\u673A\u5668\u4EBA\u540D\u79F0",className:"h-8 w-28 rounded-md border bg-transparent px-2 text-sm"}),o("button",{className:"inline-flex items-center gap-1 h-8 px-3 rounded-md bg-secondary text-secondary-foreground text-sm hover:bg-secondary/80",onClick:oa,children:[a(ce,{size:14})," \u6E05\u7A7A"]})]})]})}),a("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0",children:a("div",{className:"flex-1 overflow-y-auto p-4",children:ye.length===0?o("div",{className:"flex flex-col items-center justify-center h-full gap-3",children:[a(G,{size:64,className:"text-muted-foreground/20"}),a("span",{className:"text-muted-foreground",children:"\u6682\u65E0\u6D88\u606F\uFF0C\u5F00\u59CB\u5BF9\u8BDD\u5427\uFF01"})]}):o("div",{className:"space-y-2",children:[ye.map(e=>a("div",{className:M("flex",e.type==="sent"?"justify-end":"justify-start"),children:o("div",{className:M("max-w-[70%] p-3 rounded-2xl",e.type==="sent"?"bg-primary text-primary-foreground":"bg-muted"),children:[o("div",{className:"flex items-center gap-2 mb-1",children:[e.type==="received"&&a(oe,{size:14}),e.type==="sent"&&a(_,{size:14}),a("span",{className:"text-xs font-medium opacity-90",children:e.senderName}),a("span",{className:"text-xs opacity-70",children:new Date(e.timestamp).toLocaleTimeString()})]}),a("div",{className:"text-sm space-y-1",children:ta(e.content,e.type==="sent")})]})},e.id)),a("div",{ref:Re})]})})}),o("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0 space-y-3",children:[o("div",{className:"flex gap-2 items-center flex-wrap",children:[a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",N?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{B(!N),V(null)},title:"\u63D2\u5165\u8868\u60C5",children:a(ie,{size:16})}),a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",y==="image"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{V(e=>e==="image"?null:"image"),B(!1)},title:"\u63D2\u5165\u56FE\u7247 URL",children:a(le,{size:16})}),a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",y==="video"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{V(e=>e==="video"?null:"video"),B(!1)},title:"\u63D2\u5165\u89C6\u9891 URL",children:a(pe,{size:16})}),a("button",{type:"button",className:M("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",y==="audio"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{V(e=>e==="audio"?null:"audio"),B(!1)},title:"\u63D2\u5165\u97F3\u9891 URL",children:a(se,{size:16})}),a("div",{className:"flex-1 min-w-[1rem]"}),P&&a("button",{className:"h-8 w-8 rounded-md flex items-center justify-center hover:bg-accent transition-colors",onClick:()=>{F(""),q([])},children:a(xe,{size:16})})]}),N&&o("div",{className:"p-3 rounded-md border bg-muted/30 max-h-64 overflow-y-auto space-y-2",children:[a("input",{value:u,onChange:e=>n(e.target.value),placeholder:"\u641C\u7D22\u8868\u60C5...",className:"w-full h-8 rounded-md border bg-transparent px-2 text-sm"}),a("div",{className:"grid grid-cols-8 gap-1",children:Ge.slice(0,80).map(e=>a("button",{onClick:()=>la(e.id),title:e.name,className:"w-10 h-10 rounded-md border flex items-center justify-center hover:bg-accent transition-colors",children:a("img",{src:`https://face.viki.moe/apng/${e.id}.png`,alt:e.name,className:"w-8 h-8"})},e.id))}),Ge.length===0&&o("div",{className:"flex flex-col items-center gap-2 py-4",children:[a(Y,{size:32,className:"text-muted-foreground/30"}),a("span",{className:"text-sm text-muted-foreground",children:"\u672A\u627E\u5230\u5339\u914D\u7684\u8868\u60C5"})]})]}),y&&o("div",{className:"p-3 rounded-md border bg-muted/30 space-y-2",children:[o("p",{className:"text-xs text-muted-foreground",children:[y==="image"&&"\u652F\u6301 http(s) \u56FE\u7247\u94FE\u63A5\u6216 data URL",y==="video"&&"\u652F\u6301\u6D4F\u89C8\u5668\u53EF\u89E3\u7801\u7684\u89C6\u9891\u76F4\u94FE\uFF08\u5982 .mp4\u3001.webm\uFF09",y==="audio"&&"\u652F\u6301 .mp3\u3001.ogg\u3001.wav \u7B49\u97F3\u9891\u76F4\u94FE"]}),a("input",{value:ee,onChange:e=>Ie(e.target.value),placeholder:y==="image"?"\u56FE\u7247 URL\u2026":y==="video"?"\u89C6\u9891 URL\u2026":"\u97F3\u9891 URL\u2026",className:"w-full h-8 rounded-md border border-input bg-background px-2 text-sm",onKeyDown:e=>{e.key==="Enter"&&(e.preventDefault(),Ne())}}),o("button",{type:"button",className:"inline-flex items-center gap-1 h-8 px-3 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50",onClick:Ne,disabled:!ee.trim(),children:[a(de,{size:14})," \u63D2\u5165\u5230\u8F93\u5165\u6846"]})]}),o("div",{className:"flex gap-2 items-start",children:[o("div",{className:"flex-1 relative",children:[a(Ye,{ref:H,placeholder:`\u5411 ${w.name} \u53D1\u9001\u6D88\u606F...`,onSend:He,onChange:fa,onAtTrigger:sa,minHeight:"44px",maxHeight:"200px"}),ae&&a("div",{className:"absolute z-50 rounded-lg border bg-popover shadow-md min-w-60 max-h-72 overflow-y-auto p-1",style:{top:`${ae.top}px`,left:`${ae.left}px`},children:Ee.length>0?Ee.map(e=>o("div",{className:"flex items-center gap-2 p-2 rounded-md cursor-pointer hover:bg-accent transition-colors",onClick:()=>ra(e),children:[a(_,{size:16,className:"text-muted-foreground"}),o("div",{className:"flex-1",children:[a("div",{className:"text-sm font-medium",children:e.name}),o("div",{className:"text-xs text-muted-foreground",children:["ID: ",e.id]})]})]},e.id)):o("div",{className:"flex flex-col items-center gap-2 p-4",children:[a(Y,{size:20,className:"text-muted-foreground/50"}),a("span",{className:"text-xs text-muted-foreground",children:"\u672A\u627E\u5230\u5339\u914D\u7684\u7528\u6237"})]})})]}),o("button",{className:"inline-flex items-center gap-1.5 h-10 px-4 rounded-md bg-primary text-primary-foreground text-sm font-medium disabled:opacity-50 transition-colors hover:bg-primary/90",onClick:()=>{let e=H.current?.getContent();e&&He(e.text,e.segments)},disabled:!Ue(z),children:[a(fe,{size:16})," \u53D1\u9001"]})]}),o("div",{className:"flex items-center gap-2 flex-wrap text-xs text-muted-foreground",children:[a(re,{size:12})," \u5FEB\u6377\u64CD\u4F5C:",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Enter"})," \u53D1\u9001",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Shift+Enter"})," \u6362\u884C",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[@\u540D\u79F0]"})," @\u67D0\u4EBA",a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[video:URL]"}),a("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[audio:URL]"})]})]})]})]})]})}function bo(r){r.addRoute({path:"/console/sandbox",name:"\u6C99\u76D2",element:r.React.createElement(be,{hostReact:r.React})}),r.addTool({id:"sandbox",name:"\u6C99\u76D2",path:"/console/sandbox"})}export{bo as register};
|
|
8
8
|
/*! Bundled license information:
|
|
9
9
|
|
|
10
10
|
lucide-react/dist/esm/shared/src/utils/mergeClasses.mjs:
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type RouteTable } from "@zhin.js/http-host/edge";
|
|
2
|
+
import type { SandboxWsHostAdapter } from "./sandbox-ws.js";
|
|
3
|
+
export type RegisterSandboxSseOptions = {
|
|
4
|
+
eventsPath?: string;
|
|
5
|
+
messagePath?: string;
|
|
6
|
+
};
|
|
7
|
+
/**
|
|
8
|
+
* Edge / Vercel 等:Sandbox 使用 HTTP POST 上行 + SSE 下行(无 WebSocket upgrade)。
|
|
9
|
+
*/
|
|
10
|
+
export declare function registerSandboxSseRoutes(table: RouteTable, getAdapter: () => SandboxWsHostAdapter, options?: RegisterSandboxSseOptions): void;
|
|
11
|
+
//# sourceMappingURL=fetch-sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-sse.d.ts","sourceRoot":"","sources":["../src/fetch-sse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAE9E,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAG5D,MAAM,MAAM,yBAAyB,GAAG;IACtC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAcF;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,UAAU,EACjB,UAAU,EAAE,MAAM,oBAAoB,EACtC,OAAO,GAAE,yBAA8B,GACtC,IAAI,CAyDN"}
|
package/lib/fetch-sse.js
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { registerFetchRoute } from "@zhin.js/http-host/edge";
|
|
2
|
+
import { subscribeSandboxSse } from "./sandbox-sse-hub.js";
|
|
3
|
+
function resolveSessionId(ctx) {
|
|
4
|
+
const q = ctx.query.session?.trim();
|
|
5
|
+
if (q)
|
|
6
|
+
return q;
|
|
7
|
+
const h = ctx.get("x-sandbox-session")?.trim();
|
|
8
|
+
if (h)
|
|
9
|
+
return h;
|
|
10
|
+
const body = ctx.request.body;
|
|
11
|
+
if (body && typeof body.session === "string" && body.session.trim()) {
|
|
12
|
+
return body.session.trim();
|
|
13
|
+
}
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Edge / Vercel 等:Sandbox 使用 HTTP POST 上行 + SSE 下行(无 WebSocket upgrade)。
|
|
18
|
+
*/
|
|
19
|
+
export function registerSandboxSseRoutes(table, getAdapter, options = {}) {
|
|
20
|
+
const eventsPath = options.eventsPath ?? "/sandbox/events";
|
|
21
|
+
const messagePath = options.messagePath ?? "/sandbox/message";
|
|
22
|
+
registerFetchRoute(table, "GET", eventsPath, (ctx) => {
|
|
23
|
+
const sessionId = resolveSessionId(ctx);
|
|
24
|
+
if (!sessionId) {
|
|
25
|
+
ctx.status = 400;
|
|
26
|
+
ctx.body = { success: false, error: "Missing session (query ?session= or X-Sandbox-Session)" };
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const adapter = getAdapter();
|
|
30
|
+
if (!adapter.hasSseSession(sessionId)) {
|
|
31
|
+
adapter.acceptSseSession(sessionId);
|
|
32
|
+
}
|
|
33
|
+
const lastEventId = ctx.query["last-event-id"] ?? ctx.query.lastEventId;
|
|
34
|
+
const stream = subscribeSandboxSse(sessionId, lastEventId);
|
|
35
|
+
ctx.status = 200;
|
|
36
|
+
ctx.set("Content-Type", "text/event-stream; charset=utf-8");
|
|
37
|
+
ctx.set("Cache-Control", "no-cache, no-transform");
|
|
38
|
+
ctx.set("Connection", "keep-alive");
|
|
39
|
+
ctx.set("X-Accel-Buffering", "no");
|
|
40
|
+
ctx.body = stream;
|
|
41
|
+
});
|
|
42
|
+
registerFetchRoute(table, "POST", messagePath, async (ctx) => {
|
|
43
|
+
const sessionId = resolveSessionId(ctx);
|
|
44
|
+
if (!sessionId) {
|
|
45
|
+
ctx.status = 400;
|
|
46
|
+
ctx.body = { success: false, error: "Missing session (X-Sandbox-Session or body.session)" };
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const adapter = getAdapter();
|
|
50
|
+
if (!adapter.hasSseSession(sessionId)) {
|
|
51
|
+
ctx.status = 404;
|
|
52
|
+
ctx.body = { success: false, error: "No sandbox session; open GET /sandbox/events first" };
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const body = ctx.request.body;
|
|
56
|
+
const raw = typeof body === "string"
|
|
57
|
+
? body
|
|
58
|
+
: body === undefined || body === null
|
|
59
|
+
? ""
|
|
60
|
+
: JSON.stringify(body);
|
|
61
|
+
if (!raw) {
|
|
62
|
+
ctx.status = 400;
|
|
63
|
+
ctx.body = { success: false, error: "Empty message body" };
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
adapter.ingestSseClientMessage(sessionId, raw);
|
|
68
|
+
ctx.body = { success: true };
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
ctx.status = 500;
|
|
72
|
+
ctx.body = { success: false, error: err.message };
|
|
73
|
+
}
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=fetch-sse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetch-sse.js","sourceRoot":"","sources":["../src/fetch-sse.ts"],"names":[],"mappings":"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"}
|