You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(js-sdk): run the template test suite on Deno (#1595)
## What
Extends the Deno vitest run (#1585) with the `template` project and
fixes the real runtime bug the suite surfaced. Split out of #1594 (Bun
counterpart: #1596).
```jsonc
// packages/js-sdk/package.json
"test:deno": "deno run -A npm:vitest run --project unit --project connectionConfig --project template",
```
## Bug — Deno: template uploads used chunked transfer encoding
Deno's native `fetch` ignores an explicit `Content-Length` header on
stream bodies and falls back to `Transfer-Encoding: chunked` — exactly
the failure #1243 fixed for Node, since S3-compatible presigned PUT URLs
reject chunked uploads with 501.
`uploadFile` now streams the spooled archive through **undici's
`fetch`** (via the existing `loadUndici()` helper — undici 8 where it
imports, undici 7 on Bun, global `fetch` where undici isn't resolvable,
e.g. bundled apps), which honors the `Content-Length` header on stream
bodies on every runtime. One upload path, no runtime sniffing.
Approaches rejected along the way, all verified empirically with 1GB
uploads + RSS sampling:
- **File-backed `Blob` body (`fs.openAsBlob`)** — lazy on Node/Bun, but
Deno's shim reads the whole file into memory eagerly
(denoland/deno#32316), and Bun infers an unstrippable MIME type from the
extension whose `Content-Type` breaks presigned signatures (403 against
production storage).
- **`node:http(s)` on Deno** — works (and is memory-bounded), but can't
be unified: Bun's `node:http` ignores abort signals, and it's a second
code path.
Known caveat: Deno's `Readable.toWeb` shim has no backpressure, so the
archive is buffered in memory during upload on Deno (Node and Bun stream
in lockstep with the socket). Filed upstream as denoland/deno#36275 —
accepted as Deno's to fix rather than worked around here.
As part of this, `tarFileStream` became `spoolTarArchive`, returning `{
path, size, cleanup }` with caller-owned cleanup instead of a
self-deleting read stream. `tests/template/uploadFile.test.ts` also
asserts no `Content-Type` header is sent.
## Python SDK parity
Intentionally none: `upload_file` already sends a sized file body via
httpx.
## Testing
- Real template builds (`tests/template/build.test.ts`, against prod S3
presigned URLs) green under **Node, Deno, and Bun**
- `uploadFile` + `spoolTarArchive` suites green under Node, Deno, and
Bun
- `tests/template/abortSignal.test.ts` green under Deno
- `pnpm build`, `lint`, `typecheck`, `prettier --check` clean
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Fix template file uploads under Deno. Deno's native `fetch` ignores a `Content-Length` header on stream bodies and fell back to `Transfer-Encoding: chunked`, which S3-compatible presigned upload URLs reject (see #1243). `Template.build` uploads now stream the spooled archive through undici's `fetch`, which honors the header on every runtime, falling back to the global `fetch` where undici isn't resolvable.
0 commit comments