Skip to content

Mirror astrid:http@1.1.0 (per-request HTTP controls) + catch up the contracts pin #19

Description

@joshuajbouw

Goal

Mirror the astrid:http@1.1.0 host contract (per-request HTTP controls) into the JS SDK, matching the Rust SDK. Deferred from the http@1.1.0 rollout because sdk-js's contracts submodule is several feature-PRs behind and doesn't carry http@1.1.0 yet. Nothing is broken today — this is catch-up work, not a fix.

Reference implementation (mirror its API shape): unicity-astrid/sdk-rust#60 — the Rust SDK equivalent. Contract source: host/http@1.1.0.wit in unicity-astrid/wit (on main). Kernel impl: unicity-astrid/astrid#1050. Design: unicity-astrid/rfcs#22 (host_abi, the "HTTP: per-request control" section).

Current state (file refs)

  • contracts submodule pin: 9742f80 — behind wit main (812c833) by feat(process): persistent-process tier SDK surface (JS/TS) #14 (process un-stub), chore: release @unicity-astrid/sdk 0.1.1 #15 (file-injection), feat(sdk): add capabilities.enumerate for sys enumerate-capabilities #16 (session 1.1.0), 🤖 Code Audit: 3 potential issue(s) found #17 (http@1.1.0). Only contracts/host/http@1.0.0.wit exists locally; http@1.1.0.wit is not yet pulled in.
  • packages/astrid-sdk/src/http.ts (~346 lines): hand-written Request (class @ line 74) / Response (138) builder. Imports httpRequest as hostRequest / httpStreamStart as hostStreamStart from "astrid:http/host@1.0.0" (lines 18-25). toWit() (128) builds the @1.0.0 http-request-data. send (172) / stream (250) / fetch (319) call the host fns. No per-request options field on Request yet.
  • Codegen: prebuild runs scripts/generate-contracts.mjs (jco-based) which generates the host bindings (httpRequest, etc.) from contracts/. scripts/sync-contracts-wit.sh syncs the bus bundle. build = tsc -b. Node >= 20. (sdk-js binds the host ABI only via the two hostRequest/hostStreamStart call sites — no astrid-sys-style world.)

Steps

  1. Bump the contracts submodule pin 9742f80812c833 (latest wit/main with http@1.1.0). NOTE: this also pulls in feat(process): persistent-process tier SDK surface (JS/TS) #14/chore: release @unicity-astrid/sdk 0.1.1 #15/feat(sdk): add capabilities.enumerate for sys enumerate-capabilities #16 — re-run scripts/sync-contracts-wit.sh to regen the bus bundle; the bundle diff will include the session 1.1.0 / process / file-injection interface records (additive). http is a host/ package, not in the bundle. Commit the submodule pointer + the regenerated bundle together (the Rust SDK's CLAUDE.md documents this pin≠mirror discipline; sdk-js mirrors it).
  2. Multi-version staging check (CRITICAL — the trap that bit the Rust SDK). astrid:http now ships TWO version files (http@1.0.0.wit + http@1.1.0.wit) in contracts/host/. wit-bindgen/jco rejects two files declaring different (package, version) identifiers in one deps/<dir>/ ("package identifier astrid:http@1.1.0 does not match previous package name of astrid:http@1.0.0"). The Rust SDK fixed this in astrid-sys/build.rs by staging each version in its own deps/astrid-<pkg>@<version>/ dir. Check whether generate-contracts.mjs / jco hits the same collision once both http files are present; if so, apply the analogous per-version-dir staging.
  3. http.ts: switch the host import to astrid:http/host@1.1.0 (the http-request-opts / http-stream-start-opts fns); add the per-request options to the Request builder and toWit() (construct request-options); call the *-opts host fns from send/stream/fetch; add response-meta accessors to Response; surface the new error arms. Keep backward compatibility: an untouched Request → all-unset options == @1.0.0 behaviour.

The surface to mirror (from the @1.1.0 contract / sdk-rust#60)

Request options (all optional; unset == @1.0.0):

  • timeouts: connect-ms / first-byte-ms / between-bytes-ms / total-ms — builder e.g. .timeout() (total) / .connectTimeout() / .firstByteTimeout() / .readTimeout() (between-bytes), in ms. The four timeout fields are DEFAULTS a caller may override (even larger), not ceilings.
  • redirect: follow | error | manual (.redirect()); max-redirects (.maxRedirects()) — a ceiling the host clamps to.
  • max-response-bytes, max-decompressed-bytes, auto-decompress — body/decompression caps.
  • https-only (.httpsOnly()), integrity (sha256-<base64> / sha384 / sha512).

Response meta (response-meta on the buffered response): final-url, redirect-count, elapsed-ms, wire-bytesResponse accessors.

New error-code arms to surface: redirect-blocked, too-many-redirects, integrity-mismatch, scheme-denied, decompression-bomb (plus dns-error / tls-error already in @1.0.0).

Defer (same as the Rust SDK)

  • http-upload (streaming request body) — the host returns not-implemented.
  • http-stream.trailers — the host returns none.
    Don't surface a non-functional API; leave // TODO notes. (These will be enabled when the kernel implements them — tracked against http@1.1.0 follow-ups.)

Verify

  • npm run build (tsc -b) green; http.ts compiles against the new @1.1.0 bindings; the codegen regenerates cleanly.
  • No version bump — releases are a separate PR per the SDK's release process.

Broader note

This bump catches sdk-js's contracts up by several feature-PRs (process un-stub, file-injection, session 1.1.0, http 1.1.0). The bundle/codegen changes are additive, but confirm the regen + tsc -b stay green against the newer contracts — that catch-up is part of the work, not just the http surface.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions