clockworklabs / clockworklabs/SpacetimeDB
TypeScript SDK 2.2.0 still requires 'unsafe-eval' — Function() codegen breaks strict CSP (recurrence of #4669)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 25.2k
- Forks
- 1.1k
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 46
Description
Re-filing because #4669 was closed without a fix or comment, and the issue is still present in spacetimedb@2.2.0. This is a real production blocker for apps that ship a strict Content-Security-Policy.
Environment
- SpacetimeDB SDK:
2.2.0(npmspacetimedb) - Framework: Next.js 16.2.4 (App Router, Turbopack)
- Host: Firebase App Hosting
- Browsers: Chrome, Safari (mobile + desktop), Firefox
Repro
- Ship a Next.js app with this CSP header (no
'unsafe-eval'):script-src 'self' 'unsafe-inline' - Build for production and connect via
DbConnection.builder()...build(). - The first row deserialization throws a CSP violation; React's error boundary cannot recover; Next.js 16 falls back to its built-in
DefaultGlobalErrorUI ("This page couldn't load. Reload to try again, or go back."). The reload button is a<form>POST to/, so the page reloads in a tight loop until the user navigates away.
Where the eval happens (SDK 2.2.0, dist/index.browser.mjs)
Five codegen sites all rely on the Function() constructor:
// line 1189 — product type serializer
serializer = Function("writer", "value", body2);
// line 1197 — product type serializer (bound)
serializer = Function("writer", "value", body).bind(...)
// line 1236 — deserializer
deserializer = Function("reader", body);
// line 1241 — deserializer
deserializer = Function(...)
// line 1327 — product type serializer (bound)
serializer = Function("writer", "value", body).bind(...)
These fire on every subscription update and every reducer arg encode/decode, so 'unsafe-eval' is required throughout the lifetime of the connection — not just at startup.
Why the previous "workaround" isn't a workaround
Adding 'unsafe-eval' undoes the most important hardening the CSP gives you. For projects subject to OWASP ASVS, SOC 2, or enterprise procurement reviews, that's not a trade we can make.
Suggested fix (same as #4669)
spacetime generate already produces fully-typed client bindings. Emit the serializer and deserializer bodies at codegen time into the generated module_bindings/ files, the same way Protobuf, FlatBuffers, and Cap'n Proto do. The SDK then imports concrete functions instead of building them at runtime.
Happy to test a beta SDK against a Next.js + strict-CSP app if it'd help.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by tracing the five Function() sites in dist/index.browser.mjs and the spacetime generate path that emits module_bindings/. Compare the generated bindings with the runtime serializer and deserializer code, then verify that a production Next.js app using the stated strict CSP can connect and process rows without requiring unsafe-eval.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- firebase, next.js, typescript
- Domain
- build-system, security, web-dev
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100