Skip to content

Commit 9f5403c

Browse files
antfuclaude
andauthored
feat(logs): add in-memory message buffer for offline queueing (#241)
Co-authored-by: Claude Haiku 4.5 <noreply@anthropic.com>
1 parent bdaf5c5 commit 9f5403c

File tree

1 file changed

+60
-24
lines changed

1 file changed

+60
-24
lines changed
Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,70 @@
1-
import type { DevToolsLogEntry, DevToolsLogEntryInput, DevToolsLogHandle, DevToolsLogsClient } from '@vitejs/devtools-kit'
1+
import type { DevToolsLogEntryInput, DevToolsLogHandle, DevToolsLogsClient } from '@vitejs/devtools-kit'
22
import type { DevToolsRpcClient } from '@vitejs/devtools-kit/client'
33

4-
function createRpcHandle(rpc: DevToolsRpcClient, initialEntry: DevToolsLogEntry): DevToolsLogHandle {
5-
let entry = initialEntry
6-
return {
7-
get entry() { return entry },
8-
get id() { return entry.id },
9-
async update(patch: Partial<DevToolsLogEntryInput>) {
10-
const updated = await rpc.call('devtoolskit:internal:logs:update', entry.id, patch)
11-
if (updated)
12-
entry = updated
13-
return updated ?? undefined
14-
},
15-
async dismiss() {
16-
await rpc.call('devtoolskit:internal:logs:remove', entry.id)
17-
},
4+
export function createClientLogsClient(rpc: DevToolsRpcClient): DevToolsLogsClient {
5+
const buffer: (() => Promise<void>)[] = []
6+
let flushing: Promise<void> | undefined
7+
8+
async function flush() {
9+
if (rpc.isTrusted !== true)
10+
return
11+
if (flushing === undefined) {
12+
// eslint-disable-next-line no-async-promise-executor
13+
flushing = new Promise(async (resolve) => {
14+
while (buffer.length > 0) {
15+
const op = buffer.shift()!
16+
await op()
17+
}
18+
resolve()
19+
})
20+
}
21+
return flushing
1822
}
19-
}
2023

21-
export function createClientLogsClient(rpc: DevToolsRpcClient): DevToolsLogsClient {
24+
async function enqueue<T>(op: () => Promise<T>): Promise<T> {
25+
if (rpc.isTrusted === true && buffer.length !== 0)
26+
await flush()
27+
28+
if (rpc.isTrusted === true && buffer.length === 0)
29+
return await op()
30+
31+
return new Promise<T>((resolve) => {
32+
buffer.push(async () => {
33+
const result = await op()
34+
resolve(result)
35+
})
36+
})
37+
}
38+
39+
rpc.events.on('rpc:is-trusted:updated', (isTrusted) => {
40+
if (isTrusted && buffer.length > 0)
41+
flush()
42+
})
43+
2244
return {
23-
async add(input: DevToolsLogEntryInput): Promise<DevToolsLogHandle> {
24-
const entry = await rpc.call('devtoolskit:internal:logs:add', input)
25-
return createRpcHandle(rpc, entry)
45+
add(input: DevToolsLogEntryInput): Promise<DevToolsLogHandle> {
46+
return enqueue(async () => {
47+
let entry = await rpc.call('devtoolskit:internal:logs:add', input)
48+
return {
49+
get entry() { return entry },
50+
get id() { return entry.id },
51+
async update(patch: Partial<DevToolsLogEntryInput>) {
52+
const updated = await rpc.call('devtoolskit:internal:logs:update', entry.id, patch)
53+
if (updated)
54+
entry = updated
55+
return updated ?? undefined
56+
},
57+
async dismiss() {
58+
await rpc.call('devtoolskit:internal:logs:remove', entry.id)
59+
},
60+
}
61+
})
2662
},
27-
async remove(id: string): Promise<void> {
28-
await rpc.call('devtoolskit:internal:logs:remove', id)
63+
remove(id: string): Promise<void> {
64+
return enqueue(() => rpc.call('devtoolskit:internal:logs:remove', id))
2965
},
30-
async clear(): Promise<void> {
31-
await rpc.call('devtoolskit:internal:logs:clear')
66+
clear(): Promise<void> {
67+
return enqueue(() => rpc.call('devtoolskit:internal:logs:clear'))
3268
},
3369
}
3470
}

0 commit comments

Comments
 (0)