Skip to content

Commit 1ce32ec

Browse files
sd2kclaude
andauthored
fix(js): always fall back to non-streaming WebAssembly.instantiate (#445)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 0cfe8ce commit 1ce32ec

File tree

1 file changed

+75
-0
lines changed

1 file changed

+75
-0
lines changed

js/justfile

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ build: \
1010
(build-inner "seasons") \
1111
(build-inner "transforms")
1212
just fix-package-json
13+
just fix-wasm-streaming-fallback
1314
just copy-readme
1415

1516
build-inner target args='':
@@ -32,6 +33,80 @@ fix-package-json:
3233
jq < augurs/package.json ". | .version = \"$VERSION\"" > augurs/package.json.tmp
3334
mv augurs/package.json.tmp augurs/package.json
3435

36+
# Patch wasm-bindgen's generated __wbg_load to always fall back to the
37+
# non-streaming WebAssembly.instantiate path. The generated code rethrows
38+
# when instantiateStreaming fails and Content-Type is application/wasm,
39+
# but this breaks in environments where fetch() returns a Proxy-wrapped
40+
# Response (e.g. OpenTelemetry instrumentation-fetch) that passes JS
41+
# `instanceof Response` but fails the browser's internal C++ slot check.
42+
# Related: https://github.com/open-telemetry/opentelemetry-js/issues/5477
43+
fix-wasm-streaming-fallback:
44+
#!/usr/bin/env python3
45+
import re, glob, sys
46+
# wasm-bindgen 0.2.101-0.2.106: multi-line else block
47+
CATCH_V1 = re.compile(
48+
r'(\s*)\} catch \(e\) \{\s*\n'
49+
r'\s*const validResponse.*?\n'
50+
r'\s*\n'
51+
r'\s*if \(validResponse.*?\n'
52+
r'\s*console\.warn\(.*?\n'
53+
r'\s*\n'
54+
r'\s*\} else \{\s*\n'
55+
r'\s*throw e;\s*\n'
56+
r'\s*\}'
57+
)
58+
# wasm-bindgen 0.2.107+: single-line else block
59+
CATCH_V2 = re.compile(
60+
r'(\s*)\} catch \(e\) \{\s*\n'
61+
r'\s*const validResponse.*?\n'
62+
r'\s*\n'
63+
r'\s*if \(validResponse.*?\n'
64+
r'\s*console\.warn\(.*?\n'
65+
r'\s*\n'
66+
r'\s*\} else \{ throw e; \}'
67+
)
68+
CATCH_REPL = (
69+
r'\1} catch (e) {\1 console.warn('
70+
r'"`WebAssembly.instantiateStreaming` failed. Falling back to '
71+
r'`WebAssembly.instantiate` which is slower. Original error:\\n", e);'
72+
)
73+
# Module-level Set (wasm-bindgen 0.2.101-0.2.106)
74+
EXPECTED_TYPES_SET_RE = re.compile(r"const EXPECTED_RESPONSE_TYPES[^\n]*\n\n")
75+
# Local function inside __wbg_load (wasm-bindgen 0.2.107+)
76+
EXPECTED_TYPE_FN_RE = re.compile(
77+
r"\n function expectedResponseType\(type\) \{"
78+
r".*?return false;\n \}\n",
79+
re.DOTALL,
80+
)
81+
errors = []
82+
for f in sorted(glob.glob("augurs/*.js")):
83+
text = open(f).read()
84+
if "instantiateStreaming" not in text:
85+
continue
86+
# Replace the conditional rethrow with an unconditional warn + fallback.
87+
# Try both patterns; only one will match depending on wasm-bindgen version.
88+
text, n = CATCH_V2.subn(CATCH_REPL, text)
89+
if n == 0:
90+
text, n = CATCH_V1.subn(CATCH_REPL, text)
91+
if n == 0:
92+
errors.append(f"{f}: expected to patch __wbg_load but regex didn't match")
93+
continue
94+
# Remove the now-unused response type check helper.
95+
text = EXPECTED_TYPES_SET_RE.sub("", text)
96+
text = EXPECTED_TYPE_FN_RE.sub("\n", text)
97+
# Verify the original rethrow pattern is fully gone after patching.
98+
if CATCH_V1.search(text) or CATCH_V2.search(text):
99+
errors.append(f"{f}: patched but original rethrow pattern still present")
100+
continue
101+
open(f, "w").write(text)
102+
print(f" patched {f} ({n} replacement(s))")
103+
if errors:
104+
print("ERROR: wasm-streaming-fallback patch failed:", file=sys.stderr)
105+
for e in errors:
106+
print(f" {e}", file=sys.stderr)
107+
print("The wasm-bindgen output format may have changed. Update the regex in js/justfile.", file=sys.stderr)
108+
sys.exit(1)
109+
35110
copy-readme:
36111
cp README.md augurs/README.md
37112

0 commit comments

Comments
 (0)