fix: sanitize accessibility snapshot to remove unpaired surrogates

Fixes 'no low surrogate in string' API error when page content contains
malformed Unicode characters. Uses toWellFormed() on Node.js 20+ with
graceful fallback on older versions.
This commit is contained in:
Tommy D. Rossi
2026-01-06 12:43:50 +01:00
parent ab8a3db83a
commit 9d9e469bff
5 changed files with 15 additions and 4 deletions
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## 0.0.42
### Bug Fixes
- **Fix "no low surrogate in string" API error**: Sanitize accessibility snapshot text using `toWellFormed()` to remove unpaired Unicode surrogates that break JSON encoding for Claude API (requires Node.js 20+ for sanitization, gracefully degrades on older versions)
## 0.0.41
### Features
+1 -1
View File
@@ -1,7 +1,7 @@
{
"name": "playwriter",
"description": "",
"version": "0.0.41",
"version": "0.0.42",
"type": "module",
"main": "dist/index.js",
"types": "dist/index.d.ts",
+3 -1
View File
@@ -128,7 +128,9 @@ export async function getAriaSnapshot({ page }: { page: Page }): Promise<AriaSna
}
const snapshot = await snapshotMethod.call(page)
const snapshotStr = typeof snapshot === 'string' ? snapshot : (snapshot.full || JSON.stringify(snapshot, null, 2))
// Sanitize to remove unpaired surrogates that break JSON encoding for Claude API
const rawStr = typeof snapshot === 'string' ? snapshot : (snapshot.full || JSON.stringify(snapshot, null, 2))
const snapshotStr = rawStr.toWellFormed?.() ?? rawStr
// Discover refs by probing aria-ref=e1, e2, e3... until 10 consecutive misses
const refToElement = new Map<string, { role: string; name: string }>()
+4 -2
View File
@@ -719,7 +719,9 @@ server.tool(
const { page: targetPage, search, contextLines = 10, showDiffSinceLastCall = false } = options
if ((targetPage as any)._snapshotForAI) {
const snapshot = await (targetPage as any)._snapshotForAI()
const snapshotStr = typeof snapshot === 'string' ? snapshot : JSON.stringify(snapshot, null, 2)
// Sanitize to remove unpaired surrogates that break JSON encoding for Claude API
const rawStr = typeof snapshot === 'string' ? snapshot : JSON.stringify(snapshot, null, 2)
const snapshotStr = rawStr.toWellFormed?.() ?? rawStr
if (showDiffSinceLastCall) {
const previousSnapshot = lastSnapshots.get(targetPage)
@@ -1059,7 +1061,7 @@ async function checkRemoteServer({ host, port }: { host: string; port: number })
if (isConnectionError) {
throw new Error(
`Cannot connect to remote relay server at ${host}:${port}. ` +
`Make sure 'npx playwriter serve' is running on the host machine.`,
`Make sure 'npx -y playwriter serve' is running on the host machine.`,
)
}
throw new Error(`Failed to connect to remote relay server: ${error.message}`)
+1
View File
@@ -8,6 +8,7 @@
"rootDir": "${configDir}/src",
"moduleResolution": "NodeNext",
"lib": [
"es2024",
"es2022",
"es2017",
"es7",