Skip to content

Releases: vercel-labs/scriptc

v0.0.17

Choose a tag to compare

@github-actions github-actions released this 27 Jul 02:22
820b8f2

0.0.17

Fixes

  • The CLI builds and runs programs on Windows. TypeScript's virtual filesystem now sees consistently slash-normalized Windows paths, default executable names carry the required .exe suffix for both native and cross-target Windows builds, and the workspace build command survives Windows shell quoting. A Windows CI lane pins the path regressions and drives scriptc run end to end.

v0.0.16

Choose a tag to compare

@github-actions github-actions released this 26 Jul 15:35
4b2c775

0.0.16

Fixes

  • Console output is visible promptly. console.log, process.stdout.write, readline prompts, and writes from dynamic islands now submit their bytes before returning instead of retaining piped stdout until a later flush or normal exit. Live consumers see output as it happens, and output written immediately before SIGKILL matches Node instead of disappearing.
  • Native Linux builds link with host clang. Linux host builds now expose the glibc declarations the runtime uses and place libm after every link input, fixing compile failures from missing declarations and link failures from GNU ld's left-to-right archive resolution. A native Ubuntu clang lane pins the complete static build.

v0.0.15

Choose a tag to compare

@github-actions github-actions released this 25 Jul 18:01
84e0b05

0.0.15

Features

  • Outbound native FFI. scriptc build --ffi <manifest> binds exact signature-only TypeScript declarations to C ABI symbols and links the manifest's archives, objects, and system libraries into the executable — no runtime symbol lookup and no dynamic engine at the boundary. The strict versioned manifest covers numeric, boolean, UTF-8 string, and byte-span parameters plus scalar and void returns; both backends lower the calls, and scriptc coverage recognizes the same bindings.

Fixes

  • FFI profiles validate every configured binding before emit, including unused and shadowed declarations, and reject uninhabited never slots instead of letting TypeScript's control-flow assumptions disagree with a returning native function. A same-named local function remains ordinary TypeScript, while missing symbols and other native link failures surface as bounded SC5004 diagnostics rather than internal compiler errors.

v0.0.14

Choose a tag to compare

@github-actions github-actions released this 25 Jul 04:37
ee1f869

Fixes

  • Clients resolve hostnames. The http, https, TLS and HTTP/2 clients resolved nothing before dialing, so a request to any name came back ENOTFOUND and only literal addresses worked. Only the dial takes the resolved address — the original name stays on the request, which is what the Host header carries and what SNI and certificate verification see. net.connect(port, hostname) still refuses to resolve: Node's async lookup semantics on that surface are their own piece of work.
  • The URL-string form of the http and https clients compiles, along with the URL-object form, which reads as its href through the same parse. The declarations only described the options record, so http.get("http://host/path") — the first thing a client written from scratch reaches for — was a type error rather than a request. An unparsable input is the WHATWG Invalid URL TypeError and a scheme that is not the calling module's is ERR_INVALID_PROTOCOL, both catchable, both matching Node instead of silently upgrading the dial. Both rows run on the LLVM backend, as do the TLS CA-store entries, which moves the CA-store corpus off the C lane with identical output.
  • scriptc -v prints the version instead of crashing on an attempt to read -v as an entry file, and an unknown flag or a missing flag value prints one line naming what was wrong followed by usage, in place of a Node stack trace.

v0.0.13

Choose a tag to compare

@github-actions github-actions released this 25 Jul 02:34
91245d6

Features

  • Dyn values run the engine's own operations: a value held in unknown that came from the embedded engine now answers keyed reads and writes, calls and method dispatch, the Object statics, and ?? by running them in the engine — so it answers exactly what Node answers instead of meeting a fence. Scalars normalize at the wrap, composites stay engine values by reference, and a value that crosses into the checked-dynamic tree and back is the same value it was.
  • http.Agent and https.Agent compile, with real connection accounting: literal option parsing, getName, destroy, the sockets/requests/freeSockets snapshots, a settable defaultPort, and maxSockets that actually holds — over-limit requests defer their dial and queue. The request path threads the agent on both emissions. keepAlive: true refuses with the pooling fence named.
  • The HTTP and socket compatibility surface widens: flushHeaders, getHeaders, setTimeout, cork/uncork with a real writableCorked counter and coalescing flush, writeHead's raw-array form, write/end encodings and deferred callbacks, pause/resume with buffered drain, destroySoon, end(cb), setNoDelay, and the destroyed/readable/bytesWritten/res.req reads — on both the typed lane and dyn receivers. Strict equality over runtime handles is pointer identity, as it is in JS.
  • Crypto introspection, the TLS CA store, and the http2 tail: getFips and the cipher/hash/curve name lists bake at the call site; getCACertificates/rootCertificates/setDefaultCACertificates land in their own unit behind their own link gate, so a binary that only reads the trust anchors never pulls mbedTLS; http2.createSecureServer grows the eager request handler and the runtime options record; process.on/off cover unhandledRejection and rejectionHandled.
  • Library archives are verified across targets (SCRIPTC_CROSS=1): every library profile cross-builds for aarch64-linux, x86_64-linux, x86_64-windows, and x86_64-macos on both emissions, and each archive is checked for symbol exactness, the ambient audit in both spellings, and probe linkability against the target's libc.

Fixes

  • process.env.PORT || 3000 compiled and then threw at runtime. tsc builds a logical operator's result by dropping the left's falsy arms, so coercing the left into that result before the truthiness test retagged an arm the test was about to rule out; || now tests the left in its own type and retags only on the truthy branch, where those arms are gone. The left still evaluates exactly once and the right stays lazy.
  • Windows library archives carried undefined references no embedder link could resolve — the win32 libc shim unit now joins the archive for windows triples. Host archives are unchanged byte-for-byte.
  • Bytes written to a socket whose dial had not started — the agent's maxSockets queue, or a caller lookup still in flight — were silently dropped, hanging the exchange. They buffer and flush at establishment.
  • The CA-store surfaces demote the determinism attestation and can now be denied by a profile: three rows, one per Node spelling, since denying a read of the trust anchors is a different decision from denying their replacement.

v0.0.12

Choose a tag to compare

@github-actions github-actions released this 24 Jul 23:31
3a7286b

Features

  • Engine-held values iterate: for-of, destructuring, and spread over values born in the embedded engine ride the engine's own iterator protocol with V8's exact error spellings, and for-of over any dynamic value lowers generally. Compiled promises cross into the engine as thenables; Promise.all over mixed compiled-and-engine entries runs the engine's own combinator, and engine-array fulfillments settle by reference.
  • Bare module resolves the builtin exactly like node:module — the builtin wins over any same-named installed package, matching Node.

Fixes

  • stream.pipeline argument validation throws Node's synchronous ERR_INVALID_ARG_TYPE for provably-invalid stages in every position instead of crashing the compiler on an internal marker; accepted-but-uncompiled sources refuse naming what Node accepts.
  • Integer-slot attestations record u64 as u64 (the wire-format flattening now applies only where the frozen schema requires it), and declared model-field classes obligate every write — init, update arms, helpers — to the same prove-or-refuse check as export slots.
  • The 0.0.11 restore's written-binding decline was wider than its rationale, and two carve-outs bring the lost shapes back: a written binding whose declared type has no static mapping keeps the compiling no-storage trap claim, and a statement-position assignment whose right side provably throws before the write no longer counts against the claim.
  • A class extending a base the compiler itself rejected now fails the build eagerly with the base's real blocker — the deferred fence compiled a binary that refused at startup where Node runs on. Leaf rejected classes keep the runtime-deferral story.
  • A stale remnant of the island-literal fence answered typeof and .length wrongly for poisoned members; reads now fail with the captured diagnostic.

v0.0.11

Choose a tag to compare

@github-actions github-actions released this 24 Jul 18:10
e96d126

Features

  • Profiles declare integer boundary slots: library exports may class parameters and returns i64/u64, and the compiler proves integrality and range for every value that can reach them — or refuses with the slot path, the failed obligation with evidence, and the concrete fix. Proven returns cross as exact machine integers; a bounded counter loop proves its exact range; x | 0 is a proof by the ToInt32 contract. Semantics stay f64 everywhere inside the program.
  • Library fences cover the whole ambient surface: the Date, performance, and process families join the surface manifest as fenceable ids, so a profile can deny every surface the determinism attestation knows — full fences now imply a deterministic attestation by construction. The attestation itself tightened: six live ambient reads it previously missed now demote it. Profile roots refuse unknown keys.
  • Subclasses override emit: the wrap-and-forward pattern (emit(event, ...args) delegating to super.emit) compiles with Node's dispatch, error-event, and super-chain semantics, monomorphized per event.
  • Stream timing matches Node's tick order: stream emissions interleave with process.nextTick in enqueue order — Node's order — instead of draining after user ticks; stream emitters model the event-key shape that governs eventNames() order; push(string) honors defaultEncoding with Node's unknown-encoding errors.
  • node:stream/consumers compiles statically (text/json/buffer with Node's settle timing and rejection set), and createRequire erases at compile time — builtin specs become static imports, relative JSON bakes as the validated document, npm packages resolve their CJS arms under --dynamic, and unresolvable names throw Node's catchable MODULE_NOT_FOUND.

Fixes

  • The two 0.0.10 crash classes are fixed and its seven behavior regressions restored: collect-phase probes recover from rejected constructs instead of crashing, and the no-storage binding families claim statement declarators only.
  • Buffer.slice/subarray and TypedArray.subarray are true aliasing views — mutating through a view silently computed wrong bytes before.
  • Math.trunc and Math.ceil compile statically.

v0.0.10

Choose a tag to compare

@github-actions github-actions released this 24 Jul 15:07
567af93

Features

  • Engine-held values flow through dynamic code: values born in the embedded engine now cross into unknown/object-typed slots and back — typeof, strict equality, String(), keyed reads and writes, calls, and method dispatch route through the engine (its own prototypes run, JS-exact), with reference-preserving identity on the round trip. Unions like string | object compile wholesale into the checked-dynamic representation, and nullish coalescing and optional chains work on every dynamic value. Operations not yet routed fail loudly by name — the boundary's silent wrong answers (typeof misreporting, phantom .length) are gone.
  • Object.create(null), array entries()/keys(), and variadic Object.assign: real null-prototype dictionaries with Node's inspect/toString/comparison behavior (the dynamic tier delegates to the engine's own Object.create for live prototypes); live index-walking pair iterators; Object.assign(target, ...sources) with JavaScript's exact evaluation order and V8's position-dependent error texts.
  • Erased ambient declarations behave like Node: chains rooted in declared values compile and throw the catchable ReferenceError Node produces at first touch; never-read unmappable bindings vanish; nullish-cast bindings answer Node's exact TypeError on member access; assertion-shaped generic signatures monomorphize per call.
  • Misuse of fs, net, dgram, tls, and stream APIs throws Node's validation ladders: argument checks run in Node's order with ERR_* codes and message-exact texts; fs.exists is genuinely async (including its no-error-argument wart), and mkdtempSync and lchmod are real.
  • Keyed writes land on dynamic receivers (bag[key] = value on objects built up dynamically, with ToPropertyKey-exact key handling), and array destructuring walks dynamic sources with V8's exact non-iterable error wordings.
  • Library mode: profiles deny surfaces by manifest id — a fences array refuses fenced surfaces reached by the compiled graph, with the profile's guidance attached as a visibly-attributed note; teachings generalize to any refusal; fence evaluation reads the same dead-stripped graph as the determinism attestation, so full fences imply a deterministic attestation by construction.

Fixes

  • Mixed engine-vs-native deepStrictEqual comparisons fence loudly instead of fabricating a failure result.
  • The LLVM code generator marshals dynamic values in jsMarshal positions identically to the C backend (a latent gap).
  • Concurrent plain and sanitized test-suite runs no longer race each other's scratch directories (a test-infrastructure fix).

v0.0.9

Choose a tag to compare

@github-actions github-actions released this 24 Jul 05:35
242ad7e

Features

  • API misuse throws Node's exact errors: argument-validation ladders on Buffer (compare/equals/constructors), URLSearchParams (WHATWG brand checks, arity, ToPrimitive coercion running user toString/valueOf), the max-listeners family, and range checks across bytes/fs — ERR_INVALID_ARG_TYPE, ERR_OUT_OF_RANGE, and ERR_MISSING_ARGS with Node's message texts, catchable and assertable.
  • Strings destructure: array patterns over strings split by code point (positions, holes, defaults, rest, nesting, for-of heads); destructured built-in globals (const { subtle } = globalThis.crypto) bind with Node-agreeing identity.
  • Spread arguments land anywhere: f(...args) outside typed rest slots builds the argument list with JavaScript's exact evaluation order on both backends, including under --dynamic, with V8's spread-TypeError texts for non-iterable sources.
  • Record shapes widen further: hybrid declared-plus-index-signature records width-coerce in both directions; index signatures carry function, Map, and Set values (the command-registry pattern); per-field lifts cover unknown destinations, upcasts, and function adapters.
  • DataView setters, Object.is, and an exact Intl slice: the full DataView setter family; fresh ArrayBuffers erase into zero-filled views; Object.is with the spec's SameValue; new Intl.NumberFormat("en-US").format() and toLocaleString("en-US") print byte-identically to Node without linking ICU.
  • stream/promises compiles statically, and out-of-scope modules (v8, domain, node:sqlite, Node's underscore-internals) refuse with reasons instead of a generic unsupported-module message.
  • Bundler interop: esbuild's __toESM(require(...)) external-dependency wrapper compiles statically under --npm-static, with build-time .default semantics matching Node's interop rules; unrecognizable variants degrade to the embedded engine with the construct named.
  • Library mode: runtime-detected traps deliver the structured teaching encoding unconditionally (code, trapping symbol, optional profile remediation); bare npm specifiers compile statically when eligible or refuse with the failed bar named.

Fixes

  • The C code generator compiles with strict aliasing disabled: the refcounted object header is accessed through base- and derived-typed views by design, and optimizer type-based alias analysis could elide refcount updates, freeing objects still in use. The LLVM lane was unaffected.
  • Promise.reject with an untyped reason no longer crashes the LLVM code generator; rest-parameter arrows forwarding their rest via spread no longer trip an internal error.
  • Two readable-stream lifecycle bugs: the emittedReadable flag now clears at Node's moment, and absent-size reads clear pending state correctly.
  • String-typed 'data' listeners (the setEncoding shape) received raw byte headers as string content on sockets, http requests, and http2 streams; they now decode UTF-8 correctly.

v0.0.8

Choose a tag to compare

@github-actions github-actions released this 24 Jul 00:14
33178e7

Features

  • Destructuring completes its static surface: nested patterns and property/element targets in assignment position ([c.x, c.y] = arr, ({ a: rec.f } = o)) with JavaScript's exact evaluation order, destructuring from class instances (getters called once per element), rest over class instances packing the inheritance chain in Node's key order, and defaults on destructured accessor results.
  • The monomorphization frontier widens: keyof-constrained generics specialize per literal key (pick<T, K extends keyof T> and keyed writes), generic methods called through interface-typed receivers compile against the proven class, and generic-signature annotations, aliases of generic functions, and generic arrow initializers all monomorphize per pinned signature.
  • #private statics resolve through class values: X.#m() calls, const-bound class expressions with static initializers, decorated class names, and aliases of the class all reach static private members when the receiver provably holds the declaring class.
  • Named type-shape diagnostics: the former catch-all "unsupported type" diagnostic splits into SC2005 (generic call signatures), SC2006 (index-signature shapes), SC2007 (overloaded function types), SC2008 (unresolved intersections), and SC2009 (a supported shape whose named component is the blocker — the message points at the exact offending piece).
  • Library builds speak the structured trap encoding: trap messages carry a diagnostic code, the trapping export's symbol, and optional profile-supplied remediation inside the frozen sink signature, degrading gracefully to plain text; contract sidecars refuse order-ambiguous type declarations (multi-site merging, conditional/mapped types) with teachings naming every site, and spread-composed unions pin depth-first declaration order.
  • Broader dynamic-tier interop: Object.hasOwn/Object.assign on records and engine values, runtime-keyed writes to fixed shapes, regex union arms with instanceof RegExp narrowing, tagged templates receiving a real TemplateStringsArray, getters and spreads in island object literals, and JavaScript variadics binding the engine's arguments array.

Fixes

  • Arrays that grow from an empty any[] no longer break compilation under --dynamic when they flow into typed array methods (map/filter/forEach and family).
  • A latent double-getter-call in destructuring defaults over accessor results is fixed.