playwriter 0.0.33 → 0.0.37
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/aria-snapshot.d.ts +68 -0
- package/dist/aria-snapshot.d.ts.map +1 -0
- package/dist/aria-snapshot.js +359 -0
- package/dist/aria-snapshot.js.map +1 -0
- package/dist/cdp-relay.d.ts.map +1 -1
- package/dist/cdp-relay.js +95 -5
- package/dist/cdp-relay.js.map +1 -1
- package/dist/cdp-session.d.ts +24 -3
- package/dist/cdp-session.d.ts.map +1 -1
- package/dist/cdp-session.js +23 -0
- package/dist/cdp-session.js.map +1 -1
- package/dist/debugger-api.md +4 -3
- package/dist/debugger.d.ts +4 -3
- package/dist/debugger.d.ts.map +1 -1
- package/dist/debugger.js +3 -1
- package/dist/debugger.js.map +1 -1
- package/dist/editor-api.md +2 -2
- package/dist/editor.d.ts +2 -2
- package/dist/editor.d.ts.map +1 -1
- package/dist/editor.js +1 -0
- package/dist/editor.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp.d.ts.map +1 -1
- package/dist/mcp.js +151 -14
- package/dist/mcp.js.map +1 -1
- package/dist/mcp.test.js +340 -5
- package/dist/mcp.test.js.map +1 -1
- package/dist/protocol.d.ts +12 -1
- package/dist/protocol.d.ts.map +1 -1
- package/dist/react-source.d.ts +3 -3
- package/dist/react-source.d.ts.map +1 -1
- package/dist/react-source.js +3 -1
- package/dist/react-source.js.map +1 -1
- package/dist/scoped-fs.d.ts +94 -0
- package/dist/scoped-fs.d.ts.map +1 -0
- package/dist/scoped-fs.js +356 -0
- package/dist/scoped-fs.js.map +1 -0
- package/dist/styles-api.md +3 -3
- package/dist/styles.d.ts +3 -3
- package/dist/styles.d.ts.map +1 -1
- package/dist/styles.js +3 -1
- package/dist/styles.js.map +1 -1
- package/package.json +13 -13
- package/src/aria-snapshot.ts +446 -0
- package/src/assets/aria-labels-github-snapshot.txt +605 -0
- package/src/assets/aria-labels-github.png +0 -0
- package/src/assets/aria-labels-google-snapshot.txt +110 -0
- package/src/assets/aria-labels-google.png +0 -0
- package/src/assets/aria-labels-hacker-news-snapshot.txt +1023 -0
- package/src/assets/aria-labels-hacker-news.png +0 -0
- package/src/cdp-relay.ts +103 -5
- package/src/cdp-session.ts +50 -3
- package/src/debugger.ts +6 -4
- package/src/editor.ts +4 -3
- package/src/index.ts +8 -0
- package/src/mcp.test.ts +424 -5
- package/src/mcp.ts +242 -66
- package/src/prompt.md +209 -167
- package/src/protocol.ts +14 -1
- package/src/react-source.ts +5 -3
- package/src/scoped-fs.ts +411 -0
- package/src/styles.ts +5 -3
|
Binary file
|
package/src/cdp-relay.ts
CHANGED
|
@@ -41,6 +41,23 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
41
41
|
reject: (error: Error) => void
|
|
42
42
|
}>()
|
|
43
43
|
let extensionMessageId = 0
|
|
44
|
+
let extensionPingInterval: ReturnType<typeof setInterval> | null = null
|
|
45
|
+
|
|
46
|
+
function startExtensionPing() {
|
|
47
|
+
if (extensionPingInterval) {
|
|
48
|
+
clearInterval(extensionPingInterval)
|
|
49
|
+
}
|
|
50
|
+
extensionPingInterval = setInterval(() => {
|
|
51
|
+
extensionWs?.send(JSON.stringify({ method: 'ping' }))
|
|
52
|
+
}, 5000)
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function stopExtensionPing() {
|
|
56
|
+
if (extensionPingInterval) {
|
|
57
|
+
clearInterval(extensionPingInterval)
|
|
58
|
+
extensionPingInterval = null
|
|
59
|
+
}
|
|
60
|
+
}
|
|
44
61
|
|
|
45
62
|
function logCdpMessage({
|
|
46
63
|
direction,
|
|
@@ -176,6 +193,40 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
176
193
|
})
|
|
177
194
|
}
|
|
178
195
|
|
|
196
|
+
// Auto-create initial tab when PLAYWRITER_AUTO_ENABLE is set and no targets exist.
|
|
197
|
+
// This allows Playwright to connect and immediately have a page to work with.
|
|
198
|
+
async function maybeAutoCreateInitialTab(): Promise<void> {
|
|
199
|
+
if (!process.env.PLAYWRITER_AUTO_ENABLE) {
|
|
200
|
+
return
|
|
201
|
+
}
|
|
202
|
+
if (!extensionWs) {
|
|
203
|
+
return
|
|
204
|
+
}
|
|
205
|
+
if (connectedTargets.size > 0) {
|
|
206
|
+
return
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
logger?.log(chalk.blue('Auto-creating initial tab for Playwright client'))
|
|
211
|
+
const result = await sendToExtension({ method: 'createInitialTab', timeout: 10000 }) as {
|
|
212
|
+
success: boolean
|
|
213
|
+
tabId: number
|
|
214
|
+
sessionId: string
|
|
215
|
+
targetInfo: Protocol.Target.TargetInfo
|
|
216
|
+
}
|
|
217
|
+
if (result.success && result.sessionId && result.targetInfo) {
|
|
218
|
+
connectedTargets.set(result.sessionId, {
|
|
219
|
+
sessionId: result.sessionId,
|
|
220
|
+
targetId: result.targetInfo.targetId,
|
|
221
|
+
targetInfo: result.targetInfo
|
|
222
|
+
})
|
|
223
|
+
logger?.log(chalk.blue(`Auto-created tab, now have ${connectedTargets.size} targets, url: ${result.targetInfo.url}`))
|
|
224
|
+
}
|
|
225
|
+
} catch (e) {
|
|
226
|
+
logger?.error('Failed to auto-create initial tab:', e)
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
179
230
|
async function routeCdpCommand({ method, params, sessionId }: { method: string; params: any; sessionId?: string }) {
|
|
180
231
|
switch (method) {
|
|
181
232
|
case 'Browser.getVersion': {
|
|
@@ -192,10 +243,14 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
192
243
|
return {}
|
|
193
244
|
}
|
|
194
245
|
|
|
246
|
+
// Target.setAutoAttach is a CDP command Playwright sends on first connection.
|
|
247
|
+
// We use it as the hook to auto-create an initial tab. If Playwright changes
|
|
248
|
+
// its initialization sequence in the future, this could be moved to a different command.
|
|
195
249
|
case 'Target.setAutoAttach': {
|
|
196
250
|
if (sessionId) {
|
|
197
251
|
break
|
|
198
252
|
}
|
|
253
|
+
await maybeAutoCreateInitialTab()
|
|
199
254
|
return {}
|
|
200
255
|
}
|
|
201
256
|
|
|
@@ -331,7 +386,26 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
331
386
|
}
|
|
332
387
|
})
|
|
333
388
|
|
|
389
|
+
// Validate Origin header for WebSocket connections to prevent cross-origin attacks.
|
|
390
|
+
// Browsers always send Origin header for WebSocket connections, but Node.js clients don't.
|
|
391
|
+
// We reject browser origins (except chrome-extension://) to prevent malicious websites
|
|
392
|
+
// from connecting to the local WebSocket server.
|
|
393
|
+
function isAllowedOrigin(origin: string | undefined): boolean {
|
|
394
|
+
if (!origin) {
|
|
395
|
+
return true // Node.js clients don't send Origin
|
|
396
|
+
}
|
|
397
|
+
if (origin.startsWith('chrome-extension://')) {
|
|
398
|
+
return true // Chrome extension is allowed
|
|
399
|
+
}
|
|
400
|
+
return false // Reject browser origins (http://, https://, etc.)
|
|
401
|
+
}
|
|
402
|
+
|
|
334
403
|
app.get('/cdp/:clientId?', (c, next) => {
|
|
404
|
+
const origin = c.req.header('origin')
|
|
405
|
+
if (!isAllowedOrigin(origin)) {
|
|
406
|
+
logger?.log(chalk.red(`Rejecting /cdp WebSocket from origin: ${origin}`))
|
|
407
|
+
return c.text('Forbidden', 403)
|
|
408
|
+
}
|
|
335
409
|
if (token) {
|
|
336
410
|
const url = new URL(c.req.url, 'http://localhost')
|
|
337
411
|
const providedToken = url.searchParams.get('token')
|
|
@@ -344,15 +418,16 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
344
418
|
const clientId = c.req.param('clientId') || 'default'
|
|
345
419
|
|
|
346
420
|
return {
|
|
347
|
-
onOpen(_event, ws) {
|
|
421
|
+
async onOpen(_event, ws) {
|
|
348
422
|
if (playwrightClients.has(clientId)) {
|
|
349
423
|
logger?.log(chalk.red(`Rejecting duplicate client ID: ${clientId}`))
|
|
350
424
|
ws.close(1000, 'Client ID already connected')
|
|
351
425
|
return
|
|
352
426
|
}
|
|
353
427
|
|
|
428
|
+
// Add client first so it can receive Target.attachedToTarget events
|
|
354
429
|
playwrightClients.set(clientId, { id: clientId, ws })
|
|
355
|
-
logger?.log(chalk.green(`Playwright client connected: ${clientId} (${playwrightClients.size} total)`))
|
|
430
|
+
logger?.log(chalk.green(`Playwright client connected: ${clientId} (${playwrightClients.size} total) (extension? ${!!extensionWs}) (${connectedTargets.size} pages)`))
|
|
356
431
|
},
|
|
357
432
|
|
|
358
433
|
async onMessage(event, ws) {
|
|
@@ -404,6 +479,9 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
404
479
|
waitingForDebugger: false
|
|
405
480
|
}
|
|
406
481
|
} satisfies CDPEventFor<'Target.attachedToTarget'>
|
|
482
|
+
if (!target.targetInfo.url) {
|
|
483
|
+
logger?.error(chalk.red('[Server] WARNING: Target.attachedToTarget sent with empty URL!'), JSON.stringify(attachedPayload))
|
|
484
|
+
}
|
|
407
485
|
logger?.log(chalk.magenta('[Server] Target.attachedToTarget full payload:'), JSON.stringify(attachedPayload))
|
|
408
486
|
sendToPlaywright({
|
|
409
487
|
message: attachedPayload,
|
|
@@ -424,6 +502,9 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
424
502
|
}
|
|
425
503
|
}
|
|
426
504
|
} satisfies CDPEventFor<'Target.targetCreated'>
|
|
505
|
+
if (!target.targetInfo.url) {
|
|
506
|
+
logger?.error(chalk.red('[Server] WARNING: Target.targetCreated sent with empty URL!'), JSON.stringify(targetCreatedPayload))
|
|
507
|
+
}
|
|
427
508
|
logger?.log(chalk.magenta('[Server] Target.targetCreated full payload:'), JSON.stringify(targetCreatedPayload))
|
|
428
509
|
sendToPlaywright({
|
|
429
510
|
message: targetCreatedPayload,
|
|
@@ -448,6 +529,9 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
448
529
|
waitingForDebugger: false
|
|
449
530
|
}
|
|
450
531
|
} satisfies CDPEventFor<'Target.attachedToTarget'>
|
|
532
|
+
if (!target.targetInfo.url) {
|
|
533
|
+
logger?.error(chalk.red('[Server] WARNING: Target.attachedToTarget (from attachToTarget) sent with empty URL!'), JSON.stringify(attachedPayload))
|
|
534
|
+
}
|
|
451
535
|
logger?.log(chalk.magenta('[Server] Target.attachedToTarget (from attachToTarget) payload:'), JSON.stringify(attachedPayload))
|
|
452
536
|
sendToPlaywright({
|
|
453
537
|
message: attachedPayload,
|
|
@@ -483,7 +567,14 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
483
567
|
}
|
|
484
568
|
}))
|
|
485
569
|
|
|
486
|
-
app.get('/extension',
|
|
570
|
+
app.get('/extension', (c, next) => {
|
|
571
|
+
const origin = c.req.header('origin')
|
|
572
|
+
if (!isAllowedOrigin(origin)) {
|
|
573
|
+
logger?.log(chalk.red(`Rejecting /extension WebSocket from origin: ${origin}`))
|
|
574
|
+
return c.text('Forbidden', 403)
|
|
575
|
+
}
|
|
576
|
+
return next()
|
|
577
|
+
}, upgradeWebSocket(() => {
|
|
487
578
|
return {
|
|
488
579
|
onOpen(_event, ws) {
|
|
489
580
|
if (extensionWs) {
|
|
@@ -504,6 +595,7 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
504
595
|
}
|
|
505
596
|
|
|
506
597
|
extensionWs = ws
|
|
598
|
+
startExtensionPing()
|
|
507
599
|
logger?.log('Extension connected with clean state')
|
|
508
600
|
},
|
|
509
601
|
|
|
@@ -517,7 +609,7 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
517
609
|
return
|
|
518
610
|
}
|
|
519
611
|
|
|
520
|
-
if (
|
|
612
|
+
if (message.id !== undefined) {
|
|
521
613
|
const pending = extensionPendingRequests.get(message.id)
|
|
522
614
|
if (!pending) {
|
|
523
615
|
logger?.log('Unexpected response with id:', message.id)
|
|
@@ -531,6 +623,8 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
531
623
|
} else {
|
|
532
624
|
pending.resolve(message.result)
|
|
533
625
|
}
|
|
626
|
+
} else if (message.method === 'pong') {
|
|
627
|
+
// Keep-alive response, nothing to do
|
|
534
628
|
} else if (message.method === 'log') {
|
|
535
629
|
const { level, args } = message.params
|
|
536
630
|
const logFn = (logger as any)?.[level] || logger?.log
|
|
@@ -558,6 +652,9 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
558
652
|
if (method === 'Target.attachedToTarget') {
|
|
559
653
|
const targetParams = params as Protocol.Target.AttachedToTargetEvent
|
|
560
654
|
|
|
655
|
+
if (!targetParams.targetInfo.url) {
|
|
656
|
+
logger?.error(chalk.red('[Extension] WARNING: Target.attachedToTarget received with empty URL!'), JSON.stringify({ method, params: targetParams, sessionId }))
|
|
657
|
+
}
|
|
561
658
|
logger?.log(chalk.yellow('[Extension] Target.attachedToTarget full payload:'), JSON.stringify({ method, params: targetParams, sessionId }))
|
|
562
659
|
|
|
563
660
|
// Check if we already sent this target to clients (e.g., from Target.setAutoAttach response)
|
|
@@ -681,7 +778,8 @@ export async function startPlayWriterCDPRelayServer({ port = 19988, host = '127.
|
|
|
681
778
|
},
|
|
682
779
|
|
|
683
780
|
onClose(event, ws) {
|
|
684
|
-
logger?.log(
|
|
781
|
+
logger?.log(`Extension disconnected: code=${event.code} reason=${event.reason || 'none'}`)
|
|
782
|
+
stopExtensionPing()
|
|
685
783
|
|
|
686
784
|
// If this is an old connection closing after we've already established a new one,
|
|
687
785
|
// don't clear the global state
|
package/src/cdp-session.ts
CHANGED
|
@@ -3,12 +3,26 @@ import type { Page } from 'playwright-core'
|
|
|
3
3
|
import type { ProtocolMapping } from 'devtools-protocol/types/protocol-mapping.js'
|
|
4
4
|
import type { CDPResponseBase, CDPEventBase } from './cdp-types.js'
|
|
5
5
|
|
|
6
|
+
/**
|
|
7
|
+
* Common interface for CDP sessions that works with both our CDPSession
|
|
8
|
+
* and Playwright's CDPSession. Use this type when you want to accept either.
|
|
9
|
+
*
|
|
10
|
+
* Uses loose types so Playwright's CDPSession (which uses Protocol.Events)
|
|
11
|
+
* is assignable to this interface.
|
|
12
|
+
*/
|
|
13
|
+
export interface ICDPSession {
|
|
14
|
+
send(method: string, params?: object): Promise<unknown>
|
|
15
|
+
on(event: string, callback: (params: any) => void): unknown
|
|
16
|
+
off(event: string, callback: (params: any) => void): unknown
|
|
17
|
+
detach(): Promise<void>
|
|
18
|
+
}
|
|
19
|
+
|
|
6
20
|
interface PendingRequest {
|
|
7
21
|
resolve: (result: unknown) => void
|
|
8
22
|
reject: (error: Error) => void
|
|
9
23
|
}
|
|
10
24
|
|
|
11
|
-
export class CDPSession {
|
|
25
|
+
export class CDPSession implements ICDPSession {
|
|
12
26
|
private ws: WebSocket
|
|
13
27
|
private pendingRequests = new Map<number, PendingRequest>()
|
|
14
28
|
private eventListeners = new Map<string, Set<(params: unknown) => void>>()
|
|
@@ -90,15 +104,48 @@ export class CDPSession {
|
|
|
90
104
|
})
|
|
91
105
|
}
|
|
92
106
|
|
|
93
|
-
on<K extends keyof ProtocolMapping.Events>(event: K, callback: (params: ProtocolMapping.Events[K][0]) => void) {
|
|
107
|
+
on<K extends keyof ProtocolMapping.Events>(event: K, callback: (params: ProtocolMapping.Events[K][0]) => void): this {
|
|
94
108
|
if (!this.eventListeners.has(event)) {
|
|
95
109
|
this.eventListeners.set(event, new Set())
|
|
96
110
|
}
|
|
97
111
|
this.eventListeners.get(event)!.add(callback as (params: unknown) => void)
|
|
112
|
+
return this
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Alias for `on` - matches Playwright's CDPSession interface */
|
|
116
|
+
addListener<K extends keyof ProtocolMapping.Events>(
|
|
117
|
+
event: K,
|
|
118
|
+
callback: (params: ProtocolMapping.Events[K][0]) => void,
|
|
119
|
+
): this {
|
|
120
|
+
return this.on(event, callback)
|
|
98
121
|
}
|
|
99
122
|
|
|
100
|
-
off<K extends keyof ProtocolMapping.Events>(event: K, callback: (params: ProtocolMapping.Events[K][0]) => void) {
|
|
123
|
+
off<K extends keyof ProtocolMapping.Events>(event: K, callback: (params: ProtocolMapping.Events[K][0]) => void): this {
|
|
101
124
|
this.eventListeners.get(event)?.delete(callback as (params: unknown) => void)
|
|
125
|
+
return this
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/** Alias for `off` - matches Playwright's CDPSession interface */
|
|
129
|
+
removeListener<K extends keyof ProtocolMapping.Events>(
|
|
130
|
+
event: K,
|
|
131
|
+
callback: (params: ProtocolMapping.Events[K][0]) => void,
|
|
132
|
+
): this {
|
|
133
|
+
return this.off(event, callback)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/** Listen for an event once, then automatically remove the listener */
|
|
137
|
+
once<K extends keyof ProtocolMapping.Events>(event: K, callback: (params: ProtocolMapping.Events[K][0]) => void): this {
|
|
138
|
+
const onceCallback = (params: ProtocolMapping.Events[K][0]) => {
|
|
139
|
+
this.off(event, onceCallback)
|
|
140
|
+
callback(params)
|
|
141
|
+
}
|
|
142
|
+
return this.on(event, onceCallback)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/** Alias for `close` - matches Playwright's CDPSession interface */
|
|
146
|
+
detach(): Promise<void> {
|
|
147
|
+
this.close()
|
|
148
|
+
return Promise.resolve()
|
|
102
149
|
}
|
|
103
150
|
|
|
104
151
|
close() {
|
package/src/debugger.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CDPSession } from './cdp-session.js'
|
|
1
|
+
import type { ICDPSession, CDPSession } from './cdp-session.js'
|
|
2
2
|
import type { Protocol } from 'devtools-protocol'
|
|
3
3
|
|
|
4
4
|
export interface BreakpointInfo {
|
|
@@ -61,7 +61,8 @@ export class Debugger {
|
|
|
61
61
|
* Creates a new Debugger instance.
|
|
62
62
|
*
|
|
63
63
|
* @param options - Configuration options
|
|
64
|
-
* @param options.cdp - A CDPSession instance for sending CDP commands
|
|
64
|
+
* @param options.cdp - A CDPSession instance for sending CDP commands (works with both
|
|
65
|
+
* our CDPSession and Playwright's CDPSession)
|
|
65
66
|
*
|
|
66
67
|
* @example
|
|
67
68
|
* ```ts
|
|
@@ -69,8 +70,9 @@ export class Debugger {
|
|
|
69
70
|
* const dbg = new Debugger({ cdp })
|
|
70
71
|
* ```
|
|
71
72
|
*/
|
|
72
|
-
constructor({ cdp }: { cdp:
|
|
73
|
-
|
|
73
|
+
constructor({ cdp }: { cdp: ICDPSession }) {
|
|
74
|
+
// Cast to CDPSession for internal type safety - at runtime both are compatible
|
|
75
|
+
this.cdp = cdp as CDPSession
|
|
74
76
|
this.setupEventListeners()
|
|
75
77
|
}
|
|
76
78
|
|
package/src/editor.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { CDPSession } from './cdp-session.js'
|
|
1
|
+
import type { ICDPSession, CDPSession } from './cdp-session.js'
|
|
2
2
|
|
|
3
3
|
export interface ReadResult {
|
|
4
4
|
content: string
|
|
@@ -52,8 +52,9 @@ export class Editor {
|
|
|
52
52
|
private stylesheets = new Map<string, string>()
|
|
53
53
|
private sourceCache = new Map<string, string>()
|
|
54
54
|
|
|
55
|
-
constructor({ cdp }: { cdp:
|
|
56
|
-
|
|
55
|
+
constructor({ cdp }: { cdp: ICDPSession }) {
|
|
56
|
+
// Cast to CDPSession for internal type safety - at runtime both are compatible
|
|
57
|
+
this.cdp = cdp as CDPSession
|
|
57
58
|
this.setupEventListeners()
|
|
58
59
|
}
|
|
59
60
|
|
package/src/index.ts
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
1
|
export * from './cdp-relay.js'
|
|
2
2
|
export * from './utils.js'
|
|
3
|
+
export { CDPSession, getCDPSessionForPage } from './cdp-session.js'
|
|
4
|
+
export type { ICDPSession } from './cdp-session.js'
|
|
5
|
+
export { Editor } from './editor.js'
|
|
6
|
+
export type { ReadResult, SearchMatch, EditResult } from './editor.js'
|
|
7
|
+
export { Debugger } from './debugger.js'
|
|
8
|
+
export type { BreakpointInfo, LocationInfo, EvaluateResult, ScriptInfo } from './debugger.js'
|
|
9
|
+
export { getAriaSnapshot, showAriaRefLabels, hideAriaRefLabels } from './aria-snapshot.js'
|
|
10
|
+
export type { AriaRef, AriaSnapshotResult } from './aria-snapshot.js'
|