@zhin.js/adapter-sandbox 1.0.70 → 1.1.0
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 +951 -50
- package/README.md +60 -36
- package/adapters/sandbox.js +25 -0
- package/adapters/sandbox.ts +30 -0
- package/agent/skills/sandbox.md +33 -0
- package/lib/client.d.ts +27 -0
- package/lib/client.js +27 -0
- package/lib/endpoint.d.ts +42 -0
- package/lib/endpoint.js +357 -0
- package/lib/index.d.ts +3 -55
- package/lib/index.js +3 -176
- package/lib/protocol.d.ts +78 -0
- package/lib/protocol.js +301 -0
- package/lib/run-config.d.ts +10 -0
- package/lib/run-config.js +30 -0
- package/package.json +60 -24
- package/pages/RichTextEditor.js +366 -0
- package/{client → pages}/RichTextEditor.tsx +59 -13
- package/pages/SandboxChat.js +615 -0
- package/pages/SandboxChat.tsx +1186 -0
- package/pages/agentTrace.js +559 -0
- package/pages/agentTrace.test.js +235 -0
- package/pages/agentTrace.test.ts +265 -0
- package/pages/agentTrace.ts +646 -0
- package/pages/index.js +18 -0
- package/pages/index.tsx +18 -0
- package/pages/playgroundState.js +126 -0
- package/pages/playgroundState.test.js +92 -0
- package/pages/playgroundState.test.ts +105 -0
- package/pages/playgroundState.ts +172 -0
- package/pages/sandboxTransport.js +45 -0
- package/pages/sandboxTransport.ts +45 -0
- package/plugin.js +8 -0
- package/schema.json +76 -0
- package/src/client.ts +47 -0
- package/src/endpoint.ts +420 -0
- package/src/index.ts +26 -238
- package/src/protocol.ts +398 -0
- package/src/run-config.ts +41 -0
- package/LICENSE +0 -21
- package/client/Sandbox.tsx +0 -493
- package/client/index.tsx +0 -11
- package/client/tsconfig.json +0 -7
- package/dist/index.js +0 -1
- package/lib/index.d.ts.map +0 -1
- package/lib/index.js.map +0 -1
package/LICENSE
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2025 凉菜
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
package/client/Sandbox.tsx
DELETED
|
@@ -1,493 +0,0 @@
|
|
|
1
|
-
import React, { useState, useEffect, useRef } from 'react';
|
|
2
|
-
import { MessageSegment, cn, resolveMediaSrc, pickMediaRawUrl } from '@zhin.js/client';
|
|
3
|
-
import { User, Users, Trash2, Send, Hash, MessageSquare, Wifi, WifiOff, Smile, Image, X, Check, Info, Search, Bot, UserPlus, Bell, Video, Music } from 'lucide-react';
|
|
4
|
-
import RichTextEditor, { RichTextEditorRef } from './RichTextEditor';
|
|
5
|
-
|
|
6
|
-
interface Message {
|
|
7
|
-
id: string; type: 'sent' | 'received'; channelType: 'private' | 'group' | 'channel';
|
|
8
|
-
channelId: string; channelName: string; senderId: string; senderName: string;
|
|
9
|
-
content: MessageSegment[]; timestamp: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
interface Channel { id: string; name: string; type: 'private' | 'group' | 'channel'; unread: number; }
|
|
13
|
-
interface Face { id: number; emojiId: number; stickerId: number; emojiType: string; name: string; describe: string; png: boolean; apng: boolean; lottie: boolean; }
|
|
14
|
-
|
|
15
|
-
export default function Sandbox() {
|
|
16
|
-
const [messages, setMessages] = useState<Message[]>([])
|
|
17
|
-
const [channels, setChannels] = useState<Channel[]>([
|
|
18
|
-
{ id: 'user_1001', name: '测试用户', type: 'private', unread: 0 },
|
|
19
|
-
{ id: 'group_2001', name: '测试群组', type: 'group', unread: 0 },
|
|
20
|
-
{ id: 'channel_3001', name: '测试频道', type: 'channel', unread: 0 }
|
|
21
|
-
])
|
|
22
|
-
const [faceList, setFaceList] = useState<Face[]>([])
|
|
23
|
-
const [activeChannel, setActiveChannel] = useState<Channel>(channels[0])
|
|
24
|
-
const [inputText, setInputText] = useState('')
|
|
25
|
-
const [botName, setBotName] = useState('ProcessBot')
|
|
26
|
-
const [connected, setConnected] = useState(false)
|
|
27
|
-
const [showFacePicker, setShowFacePicker] = useState(false)
|
|
28
|
-
/** 输入区:插入图片 / 视频 / 音频 URL */
|
|
29
|
-
const [mediaPanel, setMediaPanel] = useState<null | 'image' | 'video' | 'audio'>(null)
|
|
30
|
-
const [mediaUrl, setMediaUrl] = useState('')
|
|
31
|
-
const [showAtPicker, setShowAtPicker] = useState(false)
|
|
32
|
-
const [atPopoverPosition, setAtPopoverPosition] = useState<{ top: number; left: number } | null>(null)
|
|
33
|
-
const [atSearchQuery, setAtSearchQuery] = useState('')
|
|
34
|
-
const [faceSearchQuery, setFaceSearchQuery] = useState('')
|
|
35
|
-
const [atUserName, setAtUserName] = useState('')
|
|
36
|
-
const [atSuggestions] = useState([
|
|
37
|
-
{ id: '10001', name: '张三' }, { id: '10002', name: '李四' }, { id: '10003', name: '王五' },
|
|
38
|
-
{ id: '10004', name: '赵六' }, { id: '10005', name: '测试用户' }, { id: '10086', name: 'Admin' },
|
|
39
|
-
{ id: '10010', name: 'Test User' }
|
|
40
|
-
])
|
|
41
|
-
const [previewSegments, setPreviewSegments] = useState<MessageSegment[]>([])
|
|
42
|
-
const [showChannelList, setShowChannelList] = useState(false)
|
|
43
|
-
const [viewMode, setViewMode] = useState<'chat' | 'requests' | 'notices'>('chat')
|
|
44
|
-
const messagesEndRef = useRef<HTMLDivElement>(null)
|
|
45
|
-
const wsRef = useRef<WebSocket | null>(null)
|
|
46
|
-
const editorRef = useRef<RichTextEditorRef>(null)
|
|
47
|
-
|
|
48
|
-
const fetchFaceList = async () => {
|
|
49
|
-
try { const res = await fetch('https://face.viki.moe/metadata.json'); setFaceList(await res.json()) }
|
|
50
|
-
catch (err) { console.error('[Sandbox] Failed to fetch face list:', err) }
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
useEffect(() => { fetchFaceList() }, [])
|
|
54
|
-
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:'
|
|
57
|
-
wsRef.current = new WebSocket(`${protocol}//${window.location.host}/sandbox`)
|
|
58
|
-
wsRef.current.onopen = () => setConnected(true)
|
|
59
|
-
wsRef.current.onmessage = (event) => {
|
|
60
|
-
try {
|
|
61
|
-
const data = JSON.parse(event.data)
|
|
62
|
-
let content: MessageSegment[] = typeof data.content === 'string'
|
|
63
|
-
? parseTextToSegments(data.content)
|
|
64
|
-
: Array.isArray(data.content) ? data.content : parseTextToSegments(String(data.content))
|
|
65
|
-
|
|
66
|
-
let targetChannel = channels.find((c) => c.id === data.id)
|
|
67
|
-
if (!targetChannel) {
|
|
68
|
-
const channelName = data.type === 'private' ? `私聊-${data.bot || botName}` : data.type === 'group' ? `群组-${data.id}` : `频道-${data.id}`
|
|
69
|
-
targetChannel = { id: data.id, name: channelName, type: data.type, unread: 0 }
|
|
70
|
-
setChannels((prev) => [...prev, targetChannel!])
|
|
71
|
-
setActiveChannel(targetChannel)
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const botMessage: Message = {
|
|
75
|
-
id: `bot_${data.timestamp}`, type: 'received', channelType: data.type,
|
|
76
|
-
channelId: data.id, channelName: targetChannel.name, senderId: 'bot',
|
|
77
|
-
senderName: data.bot || botName, content, timestamp: data.timestamp
|
|
78
|
-
}
|
|
79
|
-
setMessages((prev) => [...prev, botMessage])
|
|
80
|
-
} catch (err) { console.error('[Sandbox] Failed to parse message:', err) }
|
|
81
|
-
}
|
|
82
|
-
wsRef.current.onclose = () => setConnected(false)
|
|
83
|
-
return () => { wsRef.current?.close() }
|
|
84
|
-
}, [botName, channels])
|
|
85
|
-
|
|
86
|
-
useEffect(() => { messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' }) }, [messages])
|
|
87
|
-
useEffect(() => { setPreviewSegments(inputText.trim() ? parseTextToSegments(inputText) : []) }, [inputText])
|
|
88
|
-
|
|
89
|
-
const parseTextToSegments = (text: string): MessageSegment[] => {
|
|
90
|
-
const segments: MessageSegment[] = []
|
|
91
|
-
const regex = /\[@([^\]]+)\]|\[face:(\d+)\]|\[image:([^\]]+)\]|\[video:([^\]]+)\]|\[audio:([^\]]+)\]/g
|
|
92
|
-
let lastIndex = 0
|
|
93
|
-
let match: RegExpExecArray | null
|
|
94
|
-
while ((match = regex.exec(text)) !== null) {
|
|
95
|
-
if (match.index > lastIndex) {
|
|
96
|
-
const t = text.substring(lastIndex, match.index)
|
|
97
|
-
if (t) segments.push({ type: 'text', data: { text: t } })
|
|
98
|
-
}
|
|
99
|
-
if (match[1]) segments.push({ type: 'at', data: { qq: match[1], name: match[1] } })
|
|
100
|
-
else if (match[2]) segments.push({ type: 'face', data: { id: parseInt(match[2], 10) } })
|
|
101
|
-
else if (match[3]) segments.push({ type: 'image', data: { url: match[3] } })
|
|
102
|
-
else if (match[4]) segments.push({ type: 'video', data: { url: match[4] } })
|
|
103
|
-
else if (match[5]) segments.push({ type: 'audio', data: { url: match[5] } })
|
|
104
|
-
lastIndex = regex.lastIndex
|
|
105
|
-
}
|
|
106
|
-
if (lastIndex < text.length) {
|
|
107
|
-
const r = text.substring(lastIndex)
|
|
108
|
-
if (r) segments.push({ type: 'text', data: { text: r } })
|
|
109
|
-
}
|
|
110
|
-
return segments.length > 0 ? segments : [{ type: 'text', data: { text } }]
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
const hasRenderableSegments = (segments: MessageSegment[]) => {
|
|
114
|
-
if (segments.length === 0) return false
|
|
115
|
-
return segments.some((s) => {
|
|
116
|
-
if (s.type === 'text') return Boolean(String(s.data?.text ?? '').trim())
|
|
117
|
-
return true
|
|
118
|
-
})
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
const renderMessageSegments = (segments: (MessageSegment | string)[], isSent: boolean) => {
|
|
122
|
-
const ring = isSent ? 'ring-1 ring-primary-foreground/25' : 'ring-1 ring-border/60'
|
|
123
|
-
return segments.map((segment, index) => {
|
|
124
|
-
if (typeof segment === 'string') {
|
|
125
|
-
return <span key={index}>{segment.split('\n').map((part, i) => <React.Fragment key={i}>{part}{i < segment.split('\n').length - 1 && <br />}</React.Fragment>)}</span>
|
|
126
|
-
}
|
|
127
|
-
const d = segment.data as Record<string, unknown>
|
|
128
|
-
switch (segment.type) {
|
|
129
|
-
case 'text':
|
|
130
|
-
return <span key={index}>{String(d.text ?? '').split('\n').map((part: string, i: number) => <React.Fragment key={i}>{part}{i < String(d.text ?? '').split('\n').length - 1 && <br />}</React.Fragment>)}</span>
|
|
131
|
-
case 'at':
|
|
132
|
-
return <span key={index} className="inline-flex items-center px-1.5 py-0.5 rounded bg-accent text-accent-foreground text-xs mx-0.5">@{String(d.name ?? d.qq ?? '')}</span>
|
|
133
|
-
case 'face':
|
|
134
|
-
return <img key={index} src={`https://face.viki.moe/apng/${d.id}.png`} alt="" className="w-6 h-6 inline-block align-middle mx-0.5" />
|
|
135
|
-
case 'image': {
|
|
136
|
-
const raw = pickMediaRawUrl(d)
|
|
137
|
-
const src = resolveMediaSrc(raw, 'image')
|
|
138
|
-
if (!src) return <span key={index} className="text-xs opacity-70">[图片]</span>
|
|
139
|
-
return (
|
|
140
|
-
<a key={index} href={src} target="_blank" rel="noreferrer" className="block my-1">
|
|
141
|
-
<img src={src} alt="" className={cn('max-w-[min(320px,88vw)] rounded-lg block', ring, 'ring-offset-0')} onError={(e) => { (e.target as HTMLImageElement).style.display = 'none' }} />
|
|
142
|
-
</a>
|
|
143
|
-
)
|
|
144
|
-
}
|
|
145
|
-
case 'video': {
|
|
146
|
-
const raw = pickMediaRawUrl(d)
|
|
147
|
-
const src = resolveMediaSrc(raw, 'video')
|
|
148
|
-
if (!src) return <span key={index} className="text-xs opacity-70">[视频无地址]</span>
|
|
149
|
-
return (
|
|
150
|
-
<video
|
|
151
|
-
key={index}
|
|
152
|
-
src={src}
|
|
153
|
-
controls
|
|
154
|
-
playsInline
|
|
155
|
-
preload="metadata"
|
|
156
|
-
className={cn('max-w-[min(360px,92vw)] max-h-72 rounded-lg my-1 bg-black/10', ring)}
|
|
157
|
-
/>
|
|
158
|
-
)
|
|
159
|
-
}
|
|
160
|
-
case 'audio':
|
|
161
|
-
case 'record': {
|
|
162
|
-
const raw = pickMediaRawUrl(d)
|
|
163
|
-
const src = resolveMediaSrc(raw, 'audio')
|
|
164
|
-
if (!src) return <span key={index} className="text-xs opacity-70">[音频无地址]</span>
|
|
165
|
-
return (
|
|
166
|
-
<audio
|
|
167
|
-
key={index}
|
|
168
|
-
src={src}
|
|
169
|
-
controls
|
|
170
|
-
preload="metadata"
|
|
171
|
-
className={cn('w-full max-w-sm my-2 h-10', isSent && 'opacity-95')}
|
|
172
|
-
/>
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
case 'file':
|
|
176
|
-
return <span key={index} className="inline-flex items-center px-1.5 py-0.5 rounded border text-xs mx-0.5">📎 {String(d.name || '文件')}</span>
|
|
177
|
-
default:
|
|
178
|
-
return <span key={index} className="text-xs opacity-70">[{segment.type}]</span>
|
|
179
|
-
}
|
|
180
|
-
})
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
const handleSendMessage = (text: string, segments: MessageSegment[]) => {
|
|
184
|
-
if (!hasRenderableSegments(segments)) return
|
|
185
|
-
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() }
|
|
186
|
-
setMessages((prev) => [...prev, newMessage]); setInputText(''); setPreviewSegments([])
|
|
187
|
-
editorRef.current?.clear()
|
|
188
|
-
wsRef.current?.send(JSON.stringify({ type: activeChannel.type, id: activeChannel.id, content: segments, timestamp: Date.now() }))
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const clearMessages = () => { if (confirm('确定清空所有消息记录?')) setMessages([]) }
|
|
192
|
-
const switchChannel = (channel: Channel) => { setViewMode('chat'); setActiveChannel(channel); setChannels((prev) => prev.map((c) => c.id === channel.id ? { ...c, unread: 0 } : c)); if (window.innerWidth < 768) setShowChannelList(false) }
|
|
193
|
-
const addChannel = () => {
|
|
194
|
-
const types: Array<'private' | 'group' | 'channel'> = ['private', 'group', 'channel']
|
|
195
|
-
const type = types[Math.floor(Math.random() * types.length)]
|
|
196
|
-
const name = prompt(`请输入频道名称:`)
|
|
197
|
-
if (name) { const nc: Channel = { id: `${type}_${Date.now()}`, name, type, unread: 0 }; setChannels((p) => [...p, nc]); setActiveChannel(nc) }
|
|
198
|
-
}
|
|
199
|
-
const getChannelIcon = (type: string) => { switch (type) { case 'private': return <User size={16} />; case 'group': return <Users size={16} />; case 'channel': return <Hash size={16} />; default: return <MessageSquare size={16} /> } }
|
|
200
|
-
const insertFace = (faceId: number) => { editorRef.current?.insertFace(faceId); setShowFacePicker(false) }
|
|
201
|
-
const commitMediaUrl = () => {
|
|
202
|
-
const u = mediaUrl.trim()
|
|
203
|
-
if (!u || !mediaPanel) return
|
|
204
|
-
if (mediaPanel === 'image') editorRef.current?.insertImage(u)
|
|
205
|
-
else if (mediaPanel === 'video') editorRef.current?.insertVideo(u)
|
|
206
|
-
else editorRef.current?.insertAudio(u)
|
|
207
|
-
setMediaUrl('')
|
|
208
|
-
setMediaPanel(null)
|
|
209
|
-
}
|
|
210
|
-
const insertAtUser = () => { if (!atUserName.trim()) return; editorRef.current?.insertAt(atUserName.trim()); setAtUserName(''); setShowAtPicker(false) }
|
|
211
|
-
const selectAtUser = (user: { id: string; name: string }) => { editorRef.current?.replaceAtTrigger(user.name, user.id); setAtPopoverPosition(null); setAtSearchQuery('') }
|
|
212
|
-
const handleAtTrigger = (show: boolean, searchQuery: string, position?: { top: number; left: number }) => {
|
|
213
|
-
if (activeChannel.type === 'private') { setAtPopoverPosition(null); setAtSearchQuery(''); return }
|
|
214
|
-
if (show && position) { setAtPopoverPosition(position); setAtSearchQuery(searchQuery) } else { setAtPopoverPosition(null); setAtSearchQuery('') }
|
|
215
|
-
}
|
|
216
|
-
const filteredAtSuggestions = atSuggestions.filter((user) => { if (!atSearchQuery.trim()) return true; const q = atSearchQuery.toLowerCase(); return user.name.toLowerCase().includes(q) || user.id.toLowerCase().includes(q) })
|
|
217
|
-
const handleEditorChange = (text: string, segments: MessageSegment[]) => { setInputText(text); setPreviewSegments(segments) }
|
|
218
|
-
const filteredFaces = faceList.filter(face => face.name.toLowerCase().includes(faceSearchQuery.toLowerCase()) || face.describe.toLowerCase().includes(faceSearchQuery.toLowerCase()))
|
|
219
|
-
const channelMessages = messages.filter((msg) => msg.channelId === activeChannel.id)
|
|
220
|
-
|
|
221
|
-
return (
|
|
222
|
-
<div className="sandbox-container rounded-xl border border-border/70 bg-card/30 shadow-sm">
|
|
223
|
-
<button className="mobile-channel-toggle md:hidden" onClick={() => setShowChannelList(!showChannelList)}>
|
|
224
|
-
<MessageSquare size={20} /> 频道列表
|
|
225
|
-
</button>
|
|
226
|
-
|
|
227
|
-
{/* Channel sidebar */}
|
|
228
|
-
<div className={cn("channel-sidebar rounded-lg border bg-card", showChannelList && "show")}>
|
|
229
|
-
<div className="p-3 border-b">
|
|
230
|
-
<div className="flex justify-between items-center">
|
|
231
|
-
<div className="flex items-center gap-2">
|
|
232
|
-
<div className="p-1 rounded-md bg-secondary"><MessageSquare size={16} className="text-muted-foreground" /></div>
|
|
233
|
-
<h3 className="font-semibold">频道列表</h3>
|
|
234
|
-
</div>
|
|
235
|
-
<span className={cn("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border", connected ? "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")}>
|
|
236
|
-
{connected ? <Wifi size={12} /> : <WifiOff size={12} />}
|
|
237
|
-
{connected ? '已连接' : '未连接'}
|
|
238
|
-
</span>
|
|
239
|
-
</div>
|
|
240
|
-
</div>
|
|
241
|
-
|
|
242
|
-
<div className="flex-1 overflow-y-auto p-2 space-y-1">
|
|
243
|
-
{channels.map((channel) => {
|
|
244
|
-
const isActive = viewMode === 'chat' && activeChannel.id === channel.id
|
|
245
|
-
return (
|
|
246
|
-
<div key={channel.id} className={cn("menu-item", isActive && "active")} onClick={() => switchChannel(channel)}>
|
|
247
|
-
<span className="shrink-0">{getChannelIcon(channel.type)}</span>
|
|
248
|
-
<div className="flex-1 min-w-0">
|
|
249
|
-
<div className="text-sm font-medium truncate">{channel.name}</div>
|
|
250
|
-
<div className="text-xs text-muted-foreground">{channel.type === 'private' ? '私聊' : channel.type === 'group' ? '群聊' : '频道'}</div>
|
|
251
|
-
</div>
|
|
252
|
-
{channel.unread > 0 && <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">{channel.unread}</span>}
|
|
253
|
-
</div>
|
|
254
|
-
)
|
|
255
|
-
})}
|
|
256
|
-
<div className="pt-2 mt-2 border-t space-y-1">
|
|
257
|
-
<div className={cn("menu-item", viewMode === 'requests' && "active")} onClick={() => { setViewMode('requests'); if (window.innerWidth < 768) setShowChannelList(false) }}>
|
|
258
|
-
<UserPlus size={16} className="shrink-0" />
|
|
259
|
-
<div className="flex-1 min-w-0">
|
|
260
|
-
<div className="text-sm font-medium">请求</div>
|
|
261
|
-
<div className="text-xs text-muted-foreground">好友/群邀请等</div>
|
|
262
|
-
</div>
|
|
263
|
-
</div>
|
|
264
|
-
<div className={cn("menu-item", viewMode === 'notices' && "active")} onClick={() => { setViewMode('notices'); if (window.innerWidth < 768) setShowChannelList(false) }}>
|
|
265
|
-
<Bell size={16} className="shrink-0" />
|
|
266
|
-
<div className="flex-1 min-w-0">
|
|
267
|
-
<div className="text-sm font-medium">通知</div>
|
|
268
|
-
<div className="text-xs text-muted-foreground">群管/撤回等</div>
|
|
269
|
-
</div>
|
|
270
|
-
</div>
|
|
271
|
-
</div>
|
|
272
|
-
</div>
|
|
273
|
-
|
|
274
|
-
<div className="p-2 border-t">
|
|
275
|
-
<button className="w-full py-2 px-3 rounded-md border border-dashed text-sm text-muted-foreground hover:bg-accent transition-colors" onClick={addChannel}>+ 添加频道</button>
|
|
276
|
-
</div>
|
|
277
|
-
</div>
|
|
278
|
-
|
|
279
|
-
{showChannelList && <div className="channel-overlay md:hidden" onClick={() => setShowChannelList(false)} />}
|
|
280
|
-
|
|
281
|
-
{/* Main area: Chat / Requests / Notices */}
|
|
282
|
-
<div className="chat-area">
|
|
283
|
-
{viewMode === 'requests' && (
|
|
284
|
-
<div className="rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden">
|
|
285
|
-
<div className="p-3 border-b flex-shrink-0">
|
|
286
|
-
<h2 className="text-lg font-bold flex items-center gap-2">
|
|
287
|
-
<UserPlus size={20} /> 请求
|
|
288
|
-
</h2>
|
|
289
|
-
</div>
|
|
290
|
-
<div className="flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center">
|
|
291
|
-
<UserPlus size={48} className="opacity-30" />
|
|
292
|
-
<span>沙盒为模拟环境,暂无请求数据</span>
|
|
293
|
-
<span className="text-sm">实际好友/群邀请等请求请到侧边栏 <strong>机器人</strong> 页面进入对应机器人管理查看</span>
|
|
294
|
-
</div>
|
|
295
|
-
</div>
|
|
296
|
-
)}
|
|
297
|
-
|
|
298
|
-
{viewMode === 'notices' && (
|
|
299
|
-
<div className="rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden">
|
|
300
|
-
<div className="p-3 border-b flex-shrink-0">
|
|
301
|
-
<h2 className="text-lg font-bold flex items-center gap-2">
|
|
302
|
-
<Bell size={20} /> 通知
|
|
303
|
-
</h2>
|
|
304
|
-
</div>
|
|
305
|
-
<div className="flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center">
|
|
306
|
-
<Bell size={48} className="opacity-30" />
|
|
307
|
-
<span>沙盒为模拟环境,暂无通知数据</span>
|
|
308
|
-
<span className="text-sm">实际群管、撤回等通知请到侧边栏 <strong>机器人</strong> 页面进入对应机器人管理查看</span>
|
|
309
|
-
</div>
|
|
310
|
-
</div>
|
|
311
|
-
)}
|
|
312
|
-
|
|
313
|
-
{viewMode === 'chat' && (
|
|
314
|
-
<>
|
|
315
|
-
{/* Top bar */}
|
|
316
|
-
<div className="rounded-lg border bg-card p-3 flex-shrink-0">
|
|
317
|
-
<div className="flex justify-between items-center flex-wrap gap-2">
|
|
318
|
-
<div className="flex items-center gap-3">
|
|
319
|
-
<div className="p-2 rounded-lg bg-secondary">{getChannelIcon(activeChannel.type)}</div>
|
|
320
|
-
<div>
|
|
321
|
-
<h2 className="text-lg font-bold">{activeChannel.name}</h2>
|
|
322
|
-
<div className="flex items-center gap-2 text-xs text-muted-foreground">
|
|
323
|
-
<span>{activeChannel.id}</span>
|
|
324
|
-
<span className="inline-flex items-center px-1.5 py-0.5 rounded border text-[10px]">{channelMessages.length}</span>
|
|
325
|
-
<span>条消息</span>
|
|
326
|
-
</div>
|
|
327
|
-
</div>
|
|
328
|
-
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-secondary text-secondary-foreground">
|
|
329
|
-
{activeChannel.type === 'private' ? '私聊' : activeChannel.type === 'group' ? '群聊' : '频道'}
|
|
330
|
-
</span>
|
|
331
|
-
</div>
|
|
332
|
-
<div className="flex items-center gap-2">
|
|
333
|
-
<input value={botName} onChange={(e) => setBotName(e.target.value)} placeholder="机器人名称"
|
|
334
|
-
className="h-8 w-28 rounded-md border bg-transparent px-2 text-sm" />
|
|
335
|
-
<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={clearMessages}>
|
|
336
|
-
<Trash2 size={14} /> 清空
|
|
337
|
-
</button>
|
|
338
|
-
</div>
|
|
339
|
-
</div>
|
|
340
|
-
</div>
|
|
341
|
-
|
|
342
|
-
{/* Messages */}
|
|
343
|
-
<div className="rounded-lg border bg-card flex-1 flex flex-col min-h-0">
|
|
344
|
-
<div className="flex-1 overflow-y-auto p-4">
|
|
345
|
-
{channelMessages.length === 0 ? (
|
|
346
|
-
<div className="flex flex-col items-center justify-center h-full gap-3">
|
|
347
|
-
<MessageSquare size={64} className="text-muted-foreground/20" />
|
|
348
|
-
<span className="text-muted-foreground">暂无消息,开始对话吧!</span>
|
|
349
|
-
</div>
|
|
350
|
-
) : (
|
|
351
|
-
<div className="space-y-2">
|
|
352
|
-
{channelMessages.map((msg) => (
|
|
353
|
-
<div key={msg.id} className={cn("flex", msg.type === 'sent' ? "justify-end" : "justify-start")}>
|
|
354
|
-
<div className={cn("max-w-[70%] p-3 rounded-2xl", msg.type === 'sent' ? "bg-primary text-primary-foreground" : "bg-muted")}>
|
|
355
|
-
<div className="flex items-center gap-2 mb-1">
|
|
356
|
-
{msg.type === 'received' && <Bot size={14} />}
|
|
357
|
-
{msg.type === 'sent' && <User size={14} />}
|
|
358
|
-
<span className="text-xs font-medium opacity-90">{msg.senderName}</span>
|
|
359
|
-
<span className="text-xs opacity-70">{new Date(msg.timestamp).toLocaleTimeString()}</span>
|
|
360
|
-
</div>
|
|
361
|
-
<div className="text-sm space-y-1">{renderMessageSegments(msg.content, msg.type === 'sent')}</div>
|
|
362
|
-
</div>
|
|
363
|
-
</div>
|
|
364
|
-
))}
|
|
365
|
-
<div ref={messagesEndRef} />
|
|
366
|
-
</div>
|
|
367
|
-
)}
|
|
368
|
-
</div>
|
|
369
|
-
</div>
|
|
370
|
-
|
|
371
|
-
{/* Input area */}
|
|
372
|
-
<div className="rounded-lg border bg-card p-3 flex-shrink-0 space-y-3">
|
|
373
|
-
{/* Toolbar */}
|
|
374
|
-
<div className="flex gap-2 items-center flex-wrap">
|
|
375
|
-
<button type="button" className={cn("h-8 w-8 rounded-md flex items-center justify-center border transition-colors", showFacePicker ? "bg-primary text-primary-foreground" : "hover:bg-accent")}
|
|
376
|
-
onClick={() => { setShowFacePicker(!showFacePicker); setMediaPanel(null) }} title="插入表情">
|
|
377
|
-
<Smile size={16} />
|
|
378
|
-
</button>
|
|
379
|
-
<button type="button" className={cn("h-8 w-8 rounded-md flex items-center justify-center border transition-colors", mediaPanel === 'image' ? "bg-primary text-primary-foreground" : "hover:bg-accent")}
|
|
380
|
-
onClick={() => { setMediaPanel((p) => (p === 'image' ? null : 'image')); setShowFacePicker(false) }} title="插入图片 URL">
|
|
381
|
-
<Image size={16} />
|
|
382
|
-
</button>
|
|
383
|
-
<button type="button" className={cn("h-8 w-8 rounded-md flex items-center justify-center border transition-colors", mediaPanel === 'video' ? "bg-primary text-primary-foreground" : "hover:bg-accent")}
|
|
384
|
-
onClick={() => { setMediaPanel((p) => (p === 'video' ? null : 'video')); setShowFacePicker(false) }} title="插入视频 URL">
|
|
385
|
-
<Video size={16} />
|
|
386
|
-
</button>
|
|
387
|
-
<button type="button" className={cn("h-8 w-8 rounded-md flex items-center justify-center border transition-colors", mediaPanel === 'audio' ? "bg-primary text-primary-foreground" : "hover:bg-accent")}
|
|
388
|
-
onClick={() => { setMediaPanel((p) => (p === 'audio' ? null : 'audio')); setShowFacePicker(false) }} title="插入音频 URL">
|
|
389
|
-
<Music size={16} />
|
|
390
|
-
</button>
|
|
391
|
-
<div className="flex-1 min-w-[1rem]" />
|
|
392
|
-
{inputText && (
|
|
393
|
-
<button className="h-8 w-8 rounded-md flex items-center justify-center hover:bg-accent transition-colors"
|
|
394
|
-
onClick={() => { setInputText(''); setPreviewSegments([]) }}><X size={16} /></button>
|
|
395
|
-
)}
|
|
396
|
-
</div>
|
|
397
|
-
|
|
398
|
-
{/* Face picker */}
|
|
399
|
-
{showFacePicker && (
|
|
400
|
-
<div className="p-3 rounded-md border bg-muted/30 max-h-64 overflow-y-auto space-y-2">
|
|
401
|
-
<input value={faceSearchQuery} onChange={(e) => setFaceSearchQuery(e.target.value)}
|
|
402
|
-
placeholder="搜索表情..." className="w-full h-8 rounded-md border bg-transparent px-2 text-sm" />
|
|
403
|
-
<div className="grid grid-cols-8 gap-1">
|
|
404
|
-
{filteredFaces.slice(0, 80).map((face) => (
|
|
405
|
-
<button key={face.id} onClick={() => insertFace(face.id)} title={face.name}
|
|
406
|
-
className="w-10 h-10 rounded-md border flex items-center justify-center hover:bg-accent transition-colors">
|
|
407
|
-
<img src={`https://face.viki.moe/apng/${face.id}.png`} alt={face.name} className="w-8 h-8" />
|
|
408
|
-
</button>
|
|
409
|
-
))}
|
|
410
|
-
</div>
|
|
411
|
-
{filteredFaces.length === 0 && (
|
|
412
|
-
<div className="flex flex-col items-center gap-2 py-4">
|
|
413
|
-
<Search size={32} className="text-muted-foreground/30" />
|
|
414
|
-
<span className="text-sm text-muted-foreground">未找到匹配的表情</span>
|
|
415
|
-
</div>
|
|
416
|
-
)}
|
|
417
|
-
</div>
|
|
418
|
-
)}
|
|
419
|
-
|
|
420
|
-
{mediaPanel && (
|
|
421
|
-
<div className="p-3 rounded-md border bg-muted/30 space-y-2">
|
|
422
|
-
<p className="text-xs text-muted-foreground">
|
|
423
|
-
{mediaPanel === 'image' && '支持 http(s) 图片链接或 data URL'}
|
|
424
|
-
{mediaPanel === 'video' && '支持浏览器可解码的视频直链(如 .mp4、.webm)'}
|
|
425
|
-
{mediaPanel === 'audio' && '支持 .mp3、.ogg、.wav 等音频直链'}
|
|
426
|
-
</p>
|
|
427
|
-
<input
|
|
428
|
-
value={mediaUrl}
|
|
429
|
-
onChange={(e) => setMediaUrl(e.target.value)}
|
|
430
|
-
placeholder={mediaPanel === 'image' ? '图片 URL…' : mediaPanel === 'video' ? '视频 URL…' : '音频 URL…'}
|
|
431
|
-
className="w-full h-8 rounded-md border border-input bg-background px-2 text-sm"
|
|
432
|
-
onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); commitMediaUrl() } }}
|
|
433
|
-
/>
|
|
434
|
-
<button
|
|
435
|
-
type="button"
|
|
436
|
-
className="inline-flex items-center gap-1 h-8 px-3 rounded-md bg-primary text-primary-foreground text-sm disabled:opacity-50"
|
|
437
|
-
onClick={commitMediaUrl}
|
|
438
|
-
disabled={!mediaUrl.trim()}
|
|
439
|
-
>
|
|
440
|
-
<Check size={14} /> 插入到输入框
|
|
441
|
-
</button>
|
|
442
|
-
</div>
|
|
443
|
-
)}
|
|
444
|
-
|
|
445
|
-
{/* Editor + send */}
|
|
446
|
-
<div className="flex gap-2 items-start">
|
|
447
|
-
<div className="flex-1 relative">
|
|
448
|
-
<RichTextEditor
|
|
449
|
-
ref={editorRef} placeholder={`向 ${activeChannel.name} 发送消息...`}
|
|
450
|
-
onSend={handleSendMessage} onChange={handleEditorChange} onAtTrigger={handleAtTrigger}
|
|
451
|
-
minHeight="44px" maxHeight="200px"
|
|
452
|
-
/>
|
|
453
|
-
{atPopoverPosition && (
|
|
454
|
-
<div className="absolute z-50 rounded-lg border bg-popover shadow-md min-w-60 max-h-72 overflow-y-auto p-1"
|
|
455
|
-
style={{ top: `${atPopoverPosition.top}px`, left: `${atPopoverPosition.left}px` }}>
|
|
456
|
-
{filteredAtSuggestions.length > 0 ? filteredAtSuggestions.map((user) => (
|
|
457
|
-
<div key={user.id} className="flex items-center gap-2 p-2 rounded-md cursor-pointer hover:bg-accent transition-colors" onClick={() => selectAtUser(user)}>
|
|
458
|
-
<User size={16} className="text-muted-foreground" />
|
|
459
|
-
<div className="flex-1"><div className="text-sm font-medium">{user.name}</div><div className="text-xs text-muted-foreground">ID: {user.id}</div></div>
|
|
460
|
-
</div>
|
|
461
|
-
)) : (
|
|
462
|
-
<div className="flex flex-col items-center gap-2 p-4">
|
|
463
|
-
<Search size={20} className="text-muted-foreground/50" />
|
|
464
|
-
<span className="text-xs text-muted-foreground">未找到匹配的用户</span>
|
|
465
|
-
</div>
|
|
466
|
-
)}
|
|
467
|
-
</div>
|
|
468
|
-
)}
|
|
469
|
-
</div>
|
|
470
|
-
<button
|
|
471
|
-
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"
|
|
472
|
-
onClick={() => { const c = editorRef.current?.getContent(); if (c) handleSendMessage(c.text, c.segments) }}
|
|
473
|
-
disabled={!hasRenderableSegments(previewSegments)}>
|
|
474
|
-
<Send size={16} /> 发送
|
|
475
|
-
</button>
|
|
476
|
-
</div>
|
|
477
|
-
|
|
478
|
-
{/* Hints */}
|
|
479
|
-
<div className="flex items-center gap-2 flex-wrap text-xs text-muted-foreground">
|
|
480
|
-
<Info size={12} /> 快捷操作:
|
|
481
|
-
<span className="px-1 py-0.5 rounded border text-[10px]">Enter</span> 发送
|
|
482
|
-
<span className="px-1 py-0.5 rounded border text-[10px]">Shift+Enter</span> 换行
|
|
483
|
-
<span className="px-1 py-0.5 rounded border text-[10px]">[@名称]</span> @某人
|
|
484
|
-
<span className="px-1 py-0.5 rounded border text-[10px]">[video:URL]</span>
|
|
485
|
-
<span className="px-1 py-0.5 rounded border text-[10px]">[audio:URL]</span>
|
|
486
|
-
</div>
|
|
487
|
-
</div>
|
|
488
|
-
</>
|
|
489
|
-
)}
|
|
490
|
-
</div>
|
|
491
|
-
</div>
|
|
492
|
-
)
|
|
493
|
-
}
|
package/client/index.tsx
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { addPage } from '@zhin.js/client'
|
|
2
|
-
import { Terminal } from 'lucide-react'
|
|
3
|
-
import Sandbox from './Sandbox'
|
|
4
|
-
addPage({
|
|
5
|
-
key: 'process-sandbox',
|
|
6
|
-
path: '/sandbox',
|
|
7
|
-
title: '沙盒',
|
|
8
|
-
icon: <Terminal className="w-5 h-5" />,
|
|
9
|
-
element: <Sandbox/>
|
|
10
|
-
})
|
|
11
|
-
|
package/client/tsconfig.json
DELETED
package/dist/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{addPage as e,cn as t,pickMediaRawUrl as n,resolveMediaSrc as r}from"@zhin.js/client";import{Bell as i,Bot as a,Check as o,Hash as s,Image as c,Info as l,MessageSquare as u,Music as d,Search as f,Send as ee,Smile as p,Terminal as m,Trash2 as h,User as g,UserPlus as _,Users as v,Video as y,Wifi as b,WifiOff as te,X as ne}from"lucide-react";import re,{forwardRef as x,useEffect as S,useImperativeHandle as C,useRef as w,useState as T}from"react";import{Fragment as ie,jsx as E,jsxs as D}from"react/jsx-runtime";var ae=x(({placeholder:e2="输入消息...",onSend:t2,onChange:n2,onAtTrigger:r2,minHeight:i2="44px",maxHeight:a2="200px"},o2)=>{let s2=w(null),c2=w(null),l2=()=>{if(!s2.current)return{text:"",segments:[]};let e3="",t3=[],n3=Array.from(s2.current.childNodes);for(let r3 of n3)if(r3.nodeType===Node.TEXT_NODE){let n4=r3.textContent||"";n4&&(e3+=n4,t3.push({type:"text",data:{text:n4}}))}else if(r3.nodeType===Node.ELEMENT_NODE){let n4=r3;if(n4.classList.contains("editor-face")){let r4=n4.dataset.id;e3+=`[face:${r4}]`,t3.push({type:"face",data:{id:Number(r4)}})}else if(n4.classList.contains("editor-image")){let r4=n4.dataset.url;e3+=`[image:${r4}]`,t3.push({type:"image",data:{url:r4}})}else if(n4.classList.contains("editor-video")){let r4=n4.dataset.url||"";e3+=`[video:${r4}]`,t3.push({type:"video",data:{url:r4}})}else if(n4.classList.contains("editor-audio")){let r4=n4.dataset.url||"";e3+=`[audio:${r4}]`,t3.push({type:"audio",data:{url:r4}})}else if(n4.classList.contains("editor-at")){let r4=n4.dataset.name,i3=n4.dataset.id;e3+=`[@${r4}]`,t3.push({type:"at",data:{name:r4,qq:i3}})}else n4.tagName==="BR"&&(e3+="\n")}return{text:e3,segments:t3}},u2=e3=>{if(!s2.current)return;let t3=document.createElement("img");t3.src=`https://face.viki.moe/apng/${e3}.png`,t3.alt=`[face:${e3}]`,t3.dataset.type="face",t3.dataset.id=String(e3),t3.className="editor-face",m2(t3),y2()},d2=e3=>{if(!s2.current||!e3.trim())return;let t3=document.createElement("img");t3.src=e3.trim(),t3.alt=`[image:${e3.trim()}]`,t3.dataset.type="image",t3.dataset.url=e3.trim(),t3.className="editor-image",m2(t3),y2()},f2=e3=>{if(!s2.current||!e3.trim())return;let t3=e3.trim(),n3=document.createElement("span");n3.className="editor-video",n3.dataset.url=t3,n3.contentEditable="false",n3.textContent="📹 视频",m2(n3),y2()},ee2=e3=>{if(!s2.current||!e3.trim())return;let t3=e3.trim(),n3=document.createElement("span");n3.className="editor-audio",n3.dataset.url=t3,n3.contentEditable="false",n3.textContent="🎵 音频",m2(n3),y2()},p2=(e3,t3)=>{if(!s2.current||!e3.trim())return;let n3=document.createElement("span");n3.dataset.type="at",n3.dataset.name=e3,t3&&(n3.dataset.id=t3),n3.className="editor-at",n3.contentEditable="false";let r3=document.createElement("span");r3.textContent="@",r3.className="editor-at-symbol";let i3=document.createElement("span");i3.textContent=e3,i3.className="editor-at-name",n3.appendChild(r3),n3.appendChild(i3),m2(n3),y2()},m2=e3=>{if(!s2.current)return;s2.current.focus();let t3=window.getSelection();if(t3&&t3.rangeCount>0){let n3=t3.getRangeAt(0);if(s2.current.contains(n3.commonAncestorContainer))n3.deleteContents(),n3.insertNode(e3),n3.collapse(false),t3.removeAllRanges(),t3.addRange(n3);else{s2.current.appendChild(e3);let n4=document.createRange();n4.setStartAfter(e3),n4.collapse(true),t3.removeAllRanges(),t3.addRange(n4)}}else{s2.current.appendChild(e3);let t4=window.getSelection();if(t4){let n3=document.createRange();n3.setStartAfter(e3),n3.collapse(true),t4.removeAllRanges(),t4.addRange(n3)}}},h2=()=>{s2.current&&(s2.current.innerHTML="",y2())},g2=()=>{s2.current?.focus()},_2=()=>l2(),v2=()=>{if(!s2.current||!r2)return;let e3=window.getSelection();if(!e3||e3.rangeCount===0){r2(false,""),c2.current=null;return}let t3=e3.getRangeAt(0);if(!s2.current.contains(t3.commonAncestorContainer)){r2(false,""),c2.current=null;return}let n3=t3.startContainer;if(n3.nodeType!==Node.TEXT_NODE){r2(false,""),c2.current=null;return}let i3=n3,a3=i3.textContent?.substring(0,t3.startOffset)||"",o3=a3.lastIndexOf("@");if(o3!==-1){let e4=a3.substring(o3+1);if(e4.includes(" ")||e4.includes("\n")){r2(false,""),c2.current=null;return}c2.current=i3;let t4=document.createRange();t4.setStart(i3,o3),t4.setEnd(i3,o3+1);let n4=t4.getBoundingClientRect(),l3=s2.current.getBoundingClientRect();r2(true,e4,{top:n4.bottom-l3.top,left:n4.left-l3.left})}else r2(false,""),c2.current=null},y2=()=>{if(v2(),n2){let{text:e3,segments:t3}=l2();n2(e3,t3)}},b2=(e3,t3)=>{if(!c2.current)return;let n3=c2.current,r3=n3.textContent||"",i3=r3.lastIndexOf("@");if(i3!==-1){let e4=r3.substring(i3+1),t4=i3+1+e4.split(/[\s\n]/)[0].length;n3.textContent=r3.substring(0,i3)+r3.substring(t4);let a3=window.getSelection();if(a3){let e5=document.createRange();e5.setStart(n3,i3),e5.collapse(true),a3.removeAllRanges(),a3.addRange(e5)}}c2.current=null,p2(e3,t3)};return C(o2,()=>({focus:g2,clear:h2,insertFace:u2,insertImage:d2,insertVideo:f2,insertAudio:ee2,insertAt:p2,replaceAtTrigger:b2,getContent:_2})),E("div",{ref:s2,contentEditable:true,suppressContentEditableWarning:true,onInput:y2,onKeyDown:e3=>{if(e3.key==="Enter"&&!e3.shiftKey&&(e3.preventDefault(),t2)){let{text:e4,segments:n3}=l2();t2(e4,n3)}},"data-placeholder":e2,className:"rich-text-editor",style:{width:"100%",minHeight:i2,maxHeight:a2,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)"}})});ae.displayName="RichTextEditor";function oe(){let[e2,m2]=T([]),[x2,C2]=T([{id:"user_1001",name:"测试用户",type:"private",unread:0},{id:"group_2001",name:"测试群组",type:"group",unread:0},{id:"channel_3001",name:"测试频道",type:"channel",unread:0}]),[oe2,se]=T([]),[O,k]=T(x2[0]),[A,j]=T(""),[M,ce]=T("ProcessBot"),[N,P]=T(false),[F,I]=T(false),[L,R]=T(null),[z,B]=T(""),[le,ue]=T(false),[V,H]=T(null),[de,U]=T(""),[W,fe]=T(""),[pe,me]=T(""),[he]=T([{id:"10001",name:"张三"},{id:"10002",name:"李四"},{id:"10003",name:"王五"},{id:"10004",name:"赵六"},{id:"10005",name:"测试用户"},{id:"10086",name:"Admin"},{id:"10010",name:"Test User"}]),[ge,G]=T([]),[K,q]=T(false),[J,Y]=T("chat"),_e=w(null),X=w(null),Z=w(null),ve=async()=>{try{se(await(await fetch("https://face.viki.moe/metadata.json")).json())}catch(e3){console.error("[Sandbox] Failed to fetch face list:",e3)}};S(()=>{ve()},[]),S(()=>{let e3=window.location.protocol==="https:"?"wss:":"ws:";return X.current=new WebSocket(`${e3}//${window.location.host}/sandbox`),X.current.onopen=()=>P(true),X.current.onmessage=e4=>{try{let t2=JSON.parse(e4.data),n2=typeof t2.content=="string"?Q(t2.content):Array.isArray(t2.content)?t2.content:Q(String(t2.content)),r2=x2.find(e5=>e5.id===t2.id);if(!r2){let e5=t2.type==="private"?`私聊-${t2.bot||M}`:t2.type==="group"?`群组-${t2.id}`:`频道-${t2.id}`;r2={id:t2.id,name:e5,type:t2.type,unread:0},C2(e6=>[...e6,r2]),k(r2)}let i2={id:`bot_${t2.timestamp}`,type:"received",channelType:t2.type,channelId:t2.id,channelName:r2.name,senderId:"bot",senderName:t2.bot||M,content:n2,timestamp:t2.timestamp};m2(e5=>[...e5,i2])}catch(e5){console.error("[Sandbox] Failed to parse message:",e5)}},X.current.onclose=()=>P(false),()=>{X.current?.close()}},[M,x2]),S(()=>{_e.current?.scrollIntoView({behavior:"smooth"})},[e2]),S(()=>{G(A.trim()?Q(A):[])},[A]);let Q=e3=>{let t2=[],n2=/\[@([^\]]+)\]|\[face:(\d+)\]|\[image:([^\]]+)\]|\[video:([^\]]+)\]|\[audio:([^\]]+)\]/g,r2=0,i2;for(;(i2=n2.exec(e3))!==null;){if(i2.index>r2){let n3=e3.substring(r2,i2.index);n3&&t2.push({type:"text",data:{text:n3}})}i2[1]?t2.push({type:"at",data:{qq:i2[1],name:i2[1]}}):i2[2]?t2.push({type:"face",data:{id:parseInt(i2[2],10)}}):i2[3]?t2.push({type:"image",data:{url:i2[3]}}):i2[4]?t2.push({type:"video",data:{url:i2[4]}}):i2[5]&&t2.push({type:"audio",data:{url:i2[5]}}),r2=n2.lastIndex}if(r2<e3.length){let n3=e3.substring(r2);n3&&t2.push({type:"text",data:{text:n3}})}return t2.length>0?t2:[{type:"text",data:{text:e3}}]},ye=e3=>e3.length===0?false:e3.some(e4=>e4.type==="text"?!!String(e4.data?.text??"").trim():true),be=(e3,i2)=>{let a2=i2?"ring-1 ring-primary-foreground/25":"ring-1 ring-border/60";return e3.map((e4,o2)=>{if(typeof e4=="string")return E("span",{children:e4.split("\n").map((t2,n2)=>D(re.Fragment,{children:[t2,n2<e4.split("\n").length-1&&E("br",{})]},n2))},o2);let s2=e4.data;switch(e4.type){case"text":return E("span",{children:String(s2.text??"").split("\n").map((e5,t2)=>D(re.Fragment,{children:[e5,t2<String(s2.text??"").split("\n").length-1&&E("br",{})]},t2))},o2);case"at":return D("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(s2.name??s2.qq??"")]},o2);case"face":return E("img",{src:`https://face.viki.moe/apng/${s2.id}.png`,alt:"",className:"w-6 h-6 inline-block align-middle mx-0.5"},o2);case"image":{let e5=r(n(s2),"image");return e5?E("a",{href:e5,target:"_blank",rel:"noreferrer",className:"block my-1",children:E("img",{src:e5,alt:"",className:t("max-w-[min(320px,88vw)] rounded-lg block",a2,"ring-offset-0"),onError:e6=>{e6.target.style.display="none"}})},o2):E("span",{className:"text-xs opacity-70",children:"[图片]"},o2)}case"video":{let e5=r(n(s2),"video");return e5?E("video",{src:e5,controls:true,playsInline:true,preload:"metadata",className:t("max-w-[min(360px,92vw)] max-h-72 rounded-lg my-1 bg-black/10",a2)},o2):E("span",{className:"text-xs opacity-70",children:"[视频无地址]"},o2)}case"audio":case"record":{let e5=r(n(s2),"audio");return e5?E("audio",{src:e5,controls:true,preload:"metadata",className:t("w-full max-w-sm my-2 h-10",i2&&"opacity-95")},o2):E("span",{className:"text-xs opacity-70",children:"[音频无地址]"},o2)}case"file":return D("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-xs mx-0.5",children:["📎 ",String(s2.name||"文件")]},o2);default:return D("span",{className:"text-xs opacity-70",children:["[",e4.type,"]"]},o2)}})},xe=(e3,t2)=>{if(!ye(t2))return;let n2={id:`msg_${Date.now()}`,type:"sent",channelType:O.type,channelId:O.id,channelName:O.name,senderId:"test_user",senderName:"测试用户",content:t2,timestamp:Date.now()};m2(e4=>[...e4,n2]),j(""),G([]),Z.current?.clear(),X.current?.send(JSON.stringify({type:O.type,id:O.id,content:t2,timestamp:Date.now()}))},Se=()=>{confirm("确定清空所有消息记录?")&&m2([])},Ce=e3=>{Y("chat"),k(e3),C2(t2=>t2.map(t3=>t3.id===e3.id?{...t3,unread:0}:t3)),window.innerWidth<768&&q(false)},we=()=>{let e3=["private","group","channel"],t2=e3[Math.floor(Math.random()*e3.length)],n2=prompt("请输入频道名称:");if(n2){let e4={id:`${t2}_${Date.now()}`,name:n2,type:t2,unread:0};C2(t3=>[...t3,e4]),k(e4)}},Te=e3=>{switch(e3){case"private":return E(g,{size:16});case"group":return E(v,{size:16});case"channel":return E(s,{size:16});default:return E(u,{size:16})}},Ee=e3=>{Z.current?.insertFace(e3),I(false)},De=()=>{let e3=z.trim();!e3||!L||(L==="image"?Z.current?.insertImage(e3):L==="video"?Z.current?.insertVideo(e3):Z.current?.insertAudio(e3),B(""),R(null))},Oe=e3=>{Z.current?.replaceAtTrigger(e3.name,e3.id),H(null),U("")},ke=(e3,t2,n2)=>{if(O.type==="private"){H(null),U("");return}e3&&n2?(H(n2),U(t2)):(H(null),U(""))},Ae=he.filter(e3=>{if(!de.trim())return true;let t2=de.toLowerCase();return e3.name.toLowerCase().includes(t2)||e3.id.toLowerCase().includes(t2)}),je=(e3,t2)=>{j(e3),G(t2)},Me=oe2.filter(e3=>e3.name.toLowerCase().includes(W.toLowerCase())||e3.describe.toLowerCase().includes(W.toLowerCase())),$=e2.filter(e3=>e3.channelId===O.id);return D("div",{className:"sandbox-container rounded-xl border border-border/70 bg-card/30 shadow-sm",children:[D("button",{className:"mobile-channel-toggle md:hidden",onClick:()=>q(!K),children:[E(u,{size:20})," 频道列表"]}),D("div",{className:t("channel-sidebar rounded-lg border bg-card",K&&"show"),children:[E("div",{className:"p-3 border-b",children:D("div",{className:"flex justify-between items-center",children:[D("div",{className:"flex items-center gap-2",children:[E("div",{className:"p-1 rounded-md bg-secondary",children:E(u,{size:16,className:"text-muted-foreground"})}),E("h3",{className:"font-semibold",children:"频道列表"})]}),D("span",{className:t("inline-flex items-center gap-1 px-2 py-0.5 rounded-full text-xs font-medium border",N?"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(N?b:te,{size:12}),N?"已连接":"未连接"]})]})}),D("div",{className:"flex-1 overflow-y-auto p-2 space-y-1",children:[x2.map(e3=>D("div",{className:t("menu-item",J==="chat"&&O.id===e3.id&&"active"),onClick:()=>Ce(e3),children:[E("span",{className:"shrink-0",children:Te(e3.type)}),D("div",{className:"flex-1 min-w-0",children:[E("div",{className:"text-sm font-medium truncate",children:e3.name}),E("div",{className:"text-xs text-muted-foreground",children:e3.type==="private"?"私聊":e3.type==="group"?"群聊":"频道"})]}),e3.unread>0&&E("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:e3.unread})]},e3.id)),D("div",{className:"pt-2 mt-2 border-t space-y-1",children:[D("div",{className:t("menu-item",J==="requests"&&"active"),onClick:()=>{Y("requests"),window.innerWidth<768&&q(false)},children:[E(_,{size:16,className:"shrink-0"}),D("div",{className:"flex-1 min-w-0",children:[E("div",{className:"text-sm font-medium",children:"请求"}),E("div",{className:"text-xs text-muted-foreground",children:"好友/群邀请等"})]})]}),D("div",{className:t("menu-item",J==="notices"&&"active"),onClick:()=>{Y("notices"),window.innerWidth<768&&q(false)},children:[E(i,{size:16,className:"shrink-0"}),D("div",{className:"flex-1 min-w-0",children:[E("div",{className:"text-sm font-medium",children:"通知"}),E("div",{className:"text-xs text-muted-foreground",children:"群管/撤回等"})]})]})]})]}),E("div",{className:"p-2 border-t",children:E("button",{className:"w-full py-2 px-3 rounded-md border border-dashed text-sm text-muted-foreground hover:bg-accent transition-colors",onClick:we,children:"+ 添加频道"})})]}),K&&E("div",{className:"channel-overlay md:hidden",onClick:()=>q(false)}),D("div",{className:"chat-area",children:[J==="requests"&&D("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden",children:[E("div",{className:"p-3 border-b flex-shrink-0",children:D("h2",{className:"text-lg font-bold flex items-center gap-2",children:[E(_,{size:20})," 请求"]})}),D("div",{className:"flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center",children:[E(_,{size:48,className:"opacity-30"}),E("span",{children:"沙盒为模拟环境,暂无请求数据"}),D("span",{className:"text-sm",children:["实际好友/群邀请等请求请到侧边栏 ",E("strong",{children:"机器人"})," 页面进入对应机器人管理查看"]})]})]}),J==="notices"&&D("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0 overflow-hidden",children:[E("div",{className:"p-3 border-b flex-shrink-0",children:D("h2",{className:"text-lg font-bold flex items-center gap-2",children:[E(i,{size:20})," 通知"]})}),D("div",{className:"flex-1 overflow-y-auto p-4 flex flex-col items-center justify-center gap-3 text-muted-foreground text-center",children:[E(i,{size:48,className:"opacity-30"}),E("span",{children:"沙盒为模拟环境,暂无通知数据"}),D("span",{className:"text-sm",children:["实际群管、撤回等通知请到侧边栏 ",E("strong",{children:"机器人"})," 页面进入对应机器人管理查看"]})]})]}),J==="chat"&&D(ie,{children:[E("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0",children:D("div",{className:"flex justify-between items-center flex-wrap gap-2",children:[D("div",{className:"flex items-center gap-3",children:[E("div",{className:"p-2 rounded-lg bg-secondary",children:Te(O.type)}),D("div",{children:[E("h2",{className:"text-lg font-bold",children:O.name}),D("div",{className:"flex items-center gap-2 text-xs text-muted-foreground",children:[E("span",{children:O.id}),E("span",{className:"inline-flex items-center px-1.5 py-0.5 rounded border text-[10px]",children:$.length}),E("span",{children:"条消息"})]})]}),E("span",{className:"inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-secondary text-secondary-foreground",children:O.type==="private"?"私聊":O.type==="group"?"群聊":"频道"})]}),D("div",{className:"flex items-center gap-2",children:[E("input",{value:M,onChange:e3=>ce(e3.target.value),placeholder:"机器人名称",className:"h-8 w-28 rounded-md border bg-transparent px-2 text-sm"}),D("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:Se,children:[E(h,{size:14})," 清空"]})]})]})}),E("div",{className:"rounded-lg border bg-card flex-1 flex flex-col min-h-0",children:E("div",{className:"flex-1 overflow-y-auto p-4",children:$.length===0?D("div",{className:"flex flex-col items-center justify-center h-full gap-3",children:[E(u,{size:64,className:"text-muted-foreground/20"}),E("span",{className:"text-muted-foreground",children:"暂无消息,开始对话吧!"})]}):D("div",{className:"space-y-2",children:[$.map(e3=>E("div",{className:t("flex",e3.type==="sent"?"justify-end":"justify-start"),children:D("div",{className:t("max-w-[70%] p-3 rounded-2xl",e3.type==="sent"?"bg-primary text-primary-foreground":"bg-muted"),children:[D("div",{className:"flex items-center gap-2 mb-1",children:[e3.type==="received"&&E(a,{size:14}),e3.type==="sent"&&E(g,{size:14}),E("span",{className:"text-xs font-medium opacity-90",children:e3.senderName}),E("span",{className:"text-xs opacity-70",children:new Date(e3.timestamp).toLocaleTimeString()})]}),E("div",{className:"text-sm space-y-1",children:be(e3.content,e3.type==="sent")})]})},e3.id)),E("div",{ref:_e})]})})}),D("div",{className:"rounded-lg border bg-card p-3 flex-shrink-0 space-y-3",children:[D("div",{className:"flex gap-2 items-center flex-wrap",children:[E("button",{type:"button",className:t("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",F?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{I(!F),R(null)},title:"插入表情",children:E(p,{size:16})}),E("button",{type:"button",className:t("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",L==="image"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{R(e3=>e3==="image"?null:"image"),I(false)},title:"插入图片 URL",children:E(c,{size:16})}),E("button",{type:"button",className:t("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",L==="video"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{R(e3=>e3==="video"?null:"video"),I(false)},title:"插入视频 URL",children:E(y,{size:16})}),E("button",{type:"button",className:t("h-8 w-8 rounded-md flex items-center justify-center border transition-colors",L==="audio"?"bg-primary text-primary-foreground":"hover:bg-accent"),onClick:()=>{R(e3=>e3==="audio"?null:"audio"),I(false)},title:"插入音频 URL",children:E(d,{size:16})}),E("div",{className:"flex-1 min-w-[1rem]"}),A&&E("button",{className:"h-8 w-8 rounded-md flex items-center justify-center hover:bg-accent transition-colors",onClick:()=>{j(""),G([])},children:E(ne,{size:16})})]}),F&&D("div",{className:"p-3 rounded-md border bg-muted/30 max-h-64 overflow-y-auto space-y-2",children:[E("input",{value:W,onChange:e3=>fe(e3.target.value),placeholder:"搜索表情...",className:"w-full h-8 rounded-md border bg-transparent px-2 text-sm"}),E("div",{className:"grid grid-cols-8 gap-1",children:Me.slice(0,80).map(e3=>E("button",{onClick:()=>Ee(e3.id),title:e3.name,className:"w-10 h-10 rounded-md border flex items-center justify-center hover:bg-accent transition-colors",children:E("img",{src:`https://face.viki.moe/apng/${e3.id}.png`,alt:e3.name,className:"w-8 h-8"})},e3.id))}),Me.length===0&&D("div",{className:"flex flex-col items-center gap-2 py-4",children:[E(f,{size:32,className:"text-muted-foreground/30"}),E("span",{className:"text-sm text-muted-foreground",children:"未找到匹配的表情"})]})]}),L&&D("div",{className:"p-3 rounded-md border bg-muted/30 space-y-2",children:[D("p",{className:"text-xs text-muted-foreground",children:[L==="image"&&"支持 http(s) 图片链接或 data URL",L==="video"&&"支持浏览器可解码的视频直链(如 .mp4、.webm)",L==="audio"&&"支持 .mp3、.ogg、.wav 等音频直链"]}),E("input",{value:z,onChange:e3=>B(e3.target.value),placeholder:L==="image"?"图片 URL…":L==="video"?"视频 URL…":"音频 URL…",className:"w-full h-8 rounded-md border border-input bg-background px-2 text-sm",onKeyDown:e3=>{e3.key==="Enter"&&(e3.preventDefault(),De())}}),D("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:De,disabled:!z.trim(),children:[E(o,{size:14})," 插入到输入框"]})]}),D("div",{className:"flex gap-2 items-start",children:[D("div",{className:"flex-1 relative",children:[E(ae,{ref:Z,placeholder:`向 ${O.name} 发送消息...`,onSend:xe,onChange:je,onAtTrigger:ke,minHeight:"44px",maxHeight:"200px"}),V&&E("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:`${V.top}px`,left:`${V.left}px`},children:Ae.length>0?Ae.map(e3=>D("div",{className:"flex items-center gap-2 p-2 rounded-md cursor-pointer hover:bg-accent transition-colors",onClick:()=>Oe(e3),children:[E(g,{size:16,className:"text-muted-foreground"}),D("div",{className:"flex-1",children:[E("div",{className:"text-sm font-medium",children:e3.name}),D("div",{className:"text-xs text-muted-foreground",children:["ID: ",e3.id]})]})]},e3.id)):D("div",{className:"flex flex-col items-center gap-2 p-4",children:[E(f,{size:20,className:"text-muted-foreground/50"}),E("span",{className:"text-xs text-muted-foreground",children:"未找到匹配的用户"})]})})]}),D("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 e3=Z.current?.getContent();e3&&xe(e3.text,e3.segments)},disabled:!ye(ge),children:[E(ee,{size:16})," 发送"]})]}),D("div",{className:"flex items-center gap-2 flex-wrap text-xs text-muted-foreground",children:[E(l,{size:12})," 快捷操作:",E("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Enter"})," 发送",E("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"Shift+Enter"})," 换行",E("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[@名称]"})," @某人",E("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[video:URL]"}),E("span",{className:"px-1 py-0.5 rounded border text-[10px]",children:"[audio:URL]"})]})]})]})]})]})}e({key:"process-sandbox",path:"/sandbox",title:"沙盒",icon:E(m,{className:"w-5 h-5"}),element:E(oe,{})});
|
package/lib/index.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AACtC,OAAO,EACL,GAAG,EACH,OAAO,EAEP,OAAO,EACP,WAAW,EAGX,WAAW,EACX,cAAc,EACd,MAAM,EACP,MAAM,SAAS,CAAC;AACjB,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,IAAI,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAGvC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,SAAS,CAAC;IACnB,EAAE,EAAE,SAAS,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,wBAAwB;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,OAAO,QAAQ,SAAS,CAAC;IACvB,UAAU,MAAM,CAAC;QACf,UAAU,QAAQ;YAChB,MAAM,EAAE,MAAM,CAAC;YACf,GAAG,EAAE,GAAG,CAAC;SACV;KACF;IAED,UAAU,QAAQ;QAChB,OAAO,EAAE,cAAc,CAAC;KACzB;CACF;AAYD,qBAAa,UAAW,SAAQ,YAAa,YAAW,GAAG,CAAC,aAAa,EAAE;IAAE,OAAO,EAAE,cAAc,EAAE,CAAC;IAAC,EAAE,EAAE,MAAM,CAAA;CAAE,CAAC;IAShG,OAAO,EAAE,cAAc;IAAS,OAAO,EAAE,aAAa;IARzE,UAAU,EAAE,OAAO,CAAS;IAE5B,IAAI,GAAG,WAEN;IAED,OAAO,CAAC,MAAM,CAAU;gBAEL,OAAO,EAAE,cAAc,EAAS,OAAO,EAAE,aAAa;IAqBnE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAIzB,WAAW,IAAI,OAAO,CAAC,IAAI,CAAC;IAKlC,cAAc,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;QAAE,OAAO,EAAE,cAAc,EAAE,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,WAAW,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE;;;;IAsC5G,YAAY,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IAenD,cAAc,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAGhD;AAED,cAAM,cAAe,SAAQ,OAAO,CAAC,UAAU,CAAC;IAC9C,GAAG,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;gBAEnB,MAAM,EAAE,MAAM;IAI1B,SAAS,CAAC,MAAM,EAAE,aAAa,GAAG,UAAU;IAOtC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAKtB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAkCpD"}
|
package/lib/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|