Limitations
scriptc supports a subset of JavaScript, TypeScript, and the Node.js APIs. This page is a reference for the remaining restrictions and for runtime behavior that differs from Node.js. You don't need to read it front to back: run scriptc coverage on your program, and come here when a diagnostic or a behavior difference needs more context. The Node.js compatibility reference lists support API by API.
Some entries mention checked values. When the type of a value is only known at runtime, such as unknown, any, the result of JSON.parse, or a value passed through untyped JavaScript, scriptc stores it together with its runtime type and checks it when the program converts it back to a specific type. Entries that say a value "retains identity through checked storage" mean the same object comes back out, rather than a copy.
Language and API restrictions
The following sections describe what compiles and what doesn't, area by area. They are not exhaustive; the compiler's diagnostics are the authority for a specific program.
Language features
- Error causes: Accessor constructor options and explicit subclass redeclarations of
causeare unsupported.Error,TypeError,RangeError, andSyntaxErrorotherwise accept{ cause }, including through inherited constructors. Reads, writes, deletion, and"cause" in errordistinguish an absent cause from an explicitly undefined cause. Constructor causes are non-enumerable; assignment to an absent cause creates an enumerable property. Property descriptors and checked-value aliases share the cause, including getters and setters installed after construction. - Class reflection:
JSON.stringifyandObject.keysrequire every declared field to have a representation that can pass through runtime-checked storage. They raise an error for classes with opaque fields such as native Maps. Class fields, inherited accessors, and added properties retain identity through untyped values. - Method values: Borrowing a class method onto an unrelated object is unsupported. Detached methods that use
this, builtin method values, abstract declarations, unspecialized generic methods, and incompatible override signatures produce runtime errors or compilation diagnostics. Supported class methods can be stored and passed as unbound functions. A field call supplies its containing instance asthis;call,apply, andbindwork when the signature supports runtime-checked conversion. Extracted overrides retain the selected method, and receiver validation accepts the declaring class and its subclasses. - Loose equality: Object-to-primitive
==and!=comparisons are unsupported becausevalueOfandtoStringcan execute user code. Convert the object explicitly before comparing. Comparisons between represented primitives and primitive unions support number, string, boolean, and BigInt coercions, includingx == nullandx != null. - Resource disposal: Top-level and switch-clause
usingdeclarations, andDisposableStackconstructors are unsupported. Block- and function-scopedusingandawait usingsupport compiled classes with zero-parameter disposal methods, object literals and otherDisposable- orAsyncDisposable-typed values, and supported FileHandle, timer, immediate, child-process, and readline handles. A class instance reached through aDisposable- orunknown-typed value throws an SC2020 error when its declaration runs; declare the variable with the class type. Arrayfor (using ... of ...)loops also compile.SuppressedErrorvalues exposeerrorandsuppressed;extends SuppressedErrorand castingunknowntoSuppressedErrorare unsupported (narrow withinstanceof). - Async iteration: Async
yield*delegation, stored Web or Node iterator handles, and general structural async-iterator objects are unsupported. Typed async generators support lazy execution,await, directyield, queued.next()/.return()/.throw()requests, andfor await.for awaitalso accepts NodeReadablestreams, WebReadableStreamvalues, and compiled class iterators whose zero-parameternext()returns a promise of a{ value, done? }record. Abrupt completion runs cleanup, including literaldestroyOnReturnandpreventCanceloptions. Thenode:timers/promisessetInterval(delay, value)iterator compiles without AbortSignal options.Array.fromAsyncaccepts arrays of values or of promises with an optional mapping function; async generator sources, athisArg, and arrays that mix values and promises are unsupported. - Generics: Generic functions declared inside other functions, generic class expressions, and generic methods requiring dynamic dispatch are unsupported. Generic classes can extend generic bases when each specialization has a concrete layout. Independent concrete uses have no specialization-count limit; recursively expanding demands and type layouts produce diagnostics. Other generic calls compile when the target resolves statically. Generic function values require a concrete signature at use and a binding that is never reassigned.
- Function values: Immutable aliases of overloaded program functions retain per-call overload resolution and identity. A function stored in a slot with a different signature remains the same function for equality, array searches,
length, and own properties. Typed rest-parameter functions can be stored and called indirectly. Builtin function values have API-specific restrictions; see Builtin function values. - Argument spreads: Non-empty fixed tuples can spread into fixed signatures; arrays, Sets, and compiled class iterables can spread into typed rest parameters. Runtime-length spreads into fixed or rest parameters require types that support checked
unknownconversion. Other JavaScript calls use the checked-value path; unsupported static forms produce a diagnostic. Calls with no native parameter slot are unsupported for runtime-length spreads. Arguments evaluate once, in source order, before defaults run, including surplus arguments. - Dynamic imports: Computed specifiers, import attributes, CommonJS namespace synthesis, and imports of shipped JavaScript packages are unsupported unless the target is a compiled ESM module. Literal
import()of compiled ESM and TypeScript modules and of supported Node builtins compiles. Evaluation is lazy and microtask-delayed, top-levelawaitis honored, repeated imports share namespace identity, exported mutable bindings stay live, and namespace keys use Node's sorted order.
Types and class definitions
- BigInt:
BigInt64Array,BigUint64Array, BigInt filesystem stats are unsupported. Arbitrary-precision BigInts otherwise support literals, operators, conversions, arrays, records, classes, closures, unions, promises, typed Map keys and Set elements, Buffer 64-bit reads/writes, and DataView 64-bit access. Nativeunknownand JavaScriptanystorage preserve BigInts, including checked Map keys and Set elements. JSON serialization throws aTypeErrorunless a replacer converts the value. - Interfaces: Interfaces explicitly implemented by compiled classes retain live object identity through checked native values. Method-signature interfaces and callable-property interfaces structurally implemented by class methods use the same representation. A call to a method signature of such an interface calls the class's method directly when the receiver is an instance of a compiled class, and a read of a property signature reads the class's field directly; object literals, accessors, and methods the program replaces on an instance or prototype use dynamic property lookup. Arrays of such interface values are native arrays whose elements keep their identity; methods without a native form for them run on the array's dynamic view, which shares its elements. Other data interfaces retain native record layouts and their copy-coercion rules. Generic methods require a statically resolved body; a
constinterface binding initialized directly withnewcan keep the concrete class for specialization. Unsupported member representations produce diagnostics. - Record shapes: Records use exact native layouts. Passing
{ a, b }where{ a }is expected can produceSC2002. Accepted flows into a strict field-subset shape copy the record; see Record identity and property order. - Unions: Narrow a union before an operation whose members require incompatible native representations, such as reading
u.lengthonstring | string[]. Some union-to-union widening and unions combining function and data members are unsupported. Same-representation methods on class unions,mapandforEachon array unions, and shared or joinable field reads compile.console.log(u)supports printing a whole union. - Null and optional values:
undefinedandnullcompile as standalone values and union members. Optional record and class fields and optional, default, and rest parameters also compile. - Static field updates: Numeric static fields support
++and--through the declaring class or an immutable alias. Updates through a subclass name are unsupported because JavaScript creates a separate property on the subclass. - Local class expressions: Static members, decorators, private brands, generic members, explicitly generic factories returning local constructors, and references through the class's internal name are unsupported. Supported expressions preserve fresh constructor identity and shared captures across constructors, methods, accessors, and arrow fields. Local inheritance requires a compiled base class. Constructors retain identity,
typeof,name, andlengththroughunknown; cast back to their exact type before construction. Construction and static-member access directly throughunknownare unsupported. - Constructor-function inheritance: Module-level JavaScript classes can extend compiled ordinary constructor functions. Constructors that return replacement objects, spread
superarguments, and reflective static inheritance are unsupported. Supportedsupercalls preserve receiver and field initialization order and capture the base prototype at class evaluation. - Symbol fields: Instance fields require a stable module-level
Symbol()orSymbol.for()binding with a literal description or constant string binding. Reassigned keys, runtime-computed descriptions, distinct symbols with the same description in one class, and copying symbol fields with rest bindings orObject.assignare unsupported. JavaScript object spreads copy represented own symbol fields. Equal registry keys share a field across modules. Uninitialized JavaScript fields start asundefined; TypeScript fields require an initializer or unconditional constructor assignment. Represented symbol fields and methods, including inherited members, remain accessible through checked values.
Promise.all([work(1), work(2)]) infers a tuple. Some tuple operations, such as .join(), are unsupported. If you need array operations on the result, declare the input as an array:
Promise.allSettled and Promise.any take the same Promise<T>[] input and return PromiseSettledResult<T>[] and T.
Builtin APIs
A declaration in the standard library does not guarantee that an API compiles. Unsupported declared APIs produce SC2020, with alternatives where available. Check the Node.js compatibility reference for API-level support.
- Text encoding:
TextEncoderandTextDecodercan be stored in fields, arguments, return values, arrays, and closures. Encoding supports UTF-8, includingencodeIntointo a Uint8Array or Buffer view. Codec properties expose the canonical encoding and decoder flags. Decoding accepts recognized WHATWG labels, including runtime labels and omitted or undefined encodings. Literal constructor options supportfatalandignoreBOM; literal decode options support streaming UTF-8, UTF-16, and single-byte encodings. Other legacy streaming encodings, runtime options objects, inspection, JSON conversion, and module-scope declarations usingvaror lacking an initializer are unsupported. Use initializedletorconstbindings for stored codecs. - EventEmitter: Literal event names use fixed argument tuples. Computed string names require a constant prefix or suffix that excludes
error, meta events, and stream-internal events; their arguments must match the exact arity and support checked conversion. Unrestricted names, symbols, names that may reach internal events, and typedlisteners()/rawListeners()results for names with possible computed registrations are unsupported. - Streams and readline: Stream chunks are Buffers or strings.
Readable.fromaccepts arrays, Sets, Map and Set iterators, generators, async generators, and class iterables and async iterables whose values are strings or Buffers, and in JavaScript any iterable or async iterable of them; a stream that mixes strings and Buffers is unsupported. In JavaScript, a sync iterator value with athenmethod that is not a promise, and an object whose[Symbol.asyncIterator]or[Symbol.iterator]method is a generator method, are unsupported. Object-mode streams of other values (includingReadable.fromover aMap, whose values are entry arrays) are unsupported.pipelineaccepts one run of function stages: async generator functions between streams (async function* (source), iteratingsourcewithfor await), an async generator source function (async function* ({ signal })), and an async function destination whose value resolves the promise form and reaches the callback's second argument. Stages may take the{ signal }argument. An async generator function as the destination, using the PassThrough thatpipeline()returns for a function destination, several runs of function stages, and function stages together with pipeline options are unsupported.Readable.fromacceptsobjectModeandhighWaterMarkoptions. TheReadableoperators (map,filter,forEach,toArray,some,find,every,flatMap,drop,take, andreduce) acceptconcurrency,highWaterMark, andsignaloptions; their callbacks take only the chunk,mapreturns strings or Buffers, andflatMapreturns strings or arrays of them.readable.composeis unsupported.stream.composeaccepts two or more streams, or oneDuplex; functions, iterables, and web streams as stages are unsupported, and theERR_INVALID_ARG_VALUEmessage for a stream that is no longer readable or writable names the stream's class instead of printing the stream.pipelinefromnode:stream/promisesaccepts a trailing{ signal, end }object, andfinishedacceptsreadable,writable,error,cleanup, andsignaloptions, with boolean literals for the flags. Stream constructors accept asignaloption in an options object literal, andstream.addAbortSignalaccepts any stream.node:readlineandnode:readline/promises(also reached asreadline.promises) interfaces, fromcreateInterface(options)orcreateInterface(input, output, completer, terminal), readprocess.stdinor a readable stream:question,prompt,write(with a key object literal ofname,ctrl,meta, andshift),pause,resume,'line'/'close'/'pause'/'resume'/'error'/'history'/'SIGINT'/'SIGTSTP'/'SIGCONT'listeners, andfor awaitcompile. Thehistory,historySize,removeHistoryDuplicates,completer,tabSize, andescapeCodeTimeoutoptions are validated as in Node. Withterminal: true, or with noterminaloption andprocess.stdoutas the output when it is a TTY, the interface runs Node's terminal mode: the editing keys, the kill ring, undo and redo, history recording and recall, Tab completion through the completer, Ctrl+C, Ctrl+D, and Ctrl+Z,TERM=dumb, and the same escape sequences written to the output. The output's'resize'event does not redraw the line. The cursor never stops between the two UTF-16 units of a supplementary character: where Node's Up or Down movement through a multiline line would, the cursor moves to the character's start or end. In JavaScript, a'history'listener receives a copy of the history; its changes are written back when the listener returns, but the copy is notrl.historyitself.rl.history,historySize,historyIndex,crlfDelay,tabSize,escapeCodeTimeout,line,cursor, andterminalread as in Node, except thatrl.cursorof an interface that is not a terminal throws instead of answeringundefined.readline.cursorTo,moveCursor,clearLine, andclearScreenDownwrite toprocess.stdout,process.stderr, a writable stream, or nothing fornullandundefined; their callbacks take no parameters. Thereadline/promisesReadlineclass writes to the same outputs.readline.emitKeypressEventsemits'keypress'events onprocess.stdinor a readable stream, shared with terminal interfaces on that stream as in Node; a listener's first parameter must admitundefined, which it receives for escape sequences. Chained listener registration is unsupported. - CommonJS metadata: The module graph is fixed at build time. Cache deletion or reloading, metadata writes,
module.pathsmutation, andrequire.extensionsare unsupported. Read-only access tomodule.id,filename,path,paths,loaded,isPreloading,parent,children,require.main, andrequire.cachelookup/enumeration compiles. - ESM metadata: Native
import.meta.url,filename,dirname, andmainsupport dot access, statically known keys, and destructuring selected fields. Storing or mutating the metadata object, rest bindings, runtime keys, and storedresolvecallbacks are unsupported. Nativeimport.meta.resolve()requires a literal specifier. Module instances distinguished by URL query strings or fragments are unsupported. - Date: Date unions, year/month constructors, setters, statically typed TypeScript identity comparisons, thrown Date values, and locale/string formatters are unsupported. Zero-argument and single number/string constructors, storage and passing,
getTime,valueOf,toISOString, calendar getters,getTimezoneOffset, and single-stringDate.parsecompile. JavaScript Dates retain identity through checked storage and support Date-copy construction and JSON serialization. See Dates and timezones for parsing restrictions. - URL: Non-ASCII or percent-escaped hosts are unsupported. Absolute inputs and relative inputs with runtime string or URL bases, including optional bases, compile.
URL.canParse,URL.parse,toString(), andtoJSON()compile; the factories use the same parser as construction, returningfalseornullfor rejected inputs while preserving conversion errors.href,protocol,username,password,host,hostname,port,pathname,search, andhashsupport assignment in native code. Invalid component writes are ignored except for invalidhrefvalues, which throw; credentials are percent-encoded and ports accept valid leading digits. Native URL assignments require statically known property keys;+=accepts primitive operands, while other assignment operators and object operands for+=are refused.originis read-only.searchParamsis a live view whose identity survives query and URL replacement. Opaque paths retain their input bytes without WHATWG C0 encoding. - Legacy URL API:
url.parse(),url.format(),url.resolve(),url.domainToASCII(), andurl.domainToUnicode()compile, including Punycode hostnames and theDEP0169/DEP0170warnings. A parsedUrlobject supports reads, writes, and itsformat()method; itsparse(),resolve(),resolveObject(), andparseHost()methods throwSC2020, andurl.Urlandurl.resolveObject()are unsupported.ERR_INVALID_URLerrors have noinputproperty. - Filesystem flags:
fs.openSyncsupports inline bitwise OR expressions ofO_RDONLY,O_WRONLY,O_RDWR,O_CREAT,O_EXCL,O_NOFOLLOW,O_NONBLOCK,O_TRUNC, andO_APPEND, with an optional creation mode. Computed numeric flags are unsupported because bit values vary by target.fstatSync,fchmodSync,fsyncSync, andlinkSyncsupport direct calls. On Windows, numeric opens withO_NOFOLLOWand calls tofchmodSyncthrowENOSYS; use a POSIX target if you require these operations. - Copy:
fs.cpSync,fs.cp, andfs/promisescpsupport every option and follow Node's two implementations:cpSyncreports the native binding's errors, and the callback and promise forms reportSystemErrors. Files, directories, and symbolic links are copied in directory order, as in Node. The callback and promise forms complete the copy before the callback runs or the promise settles. An asyncfiltermust return a promise that is already settled; a pending one throwsSC2020. On Windows, the three functions throwSC2020. - Glob:
fs.globSync,fs.globandfs/promisesglobsupport every option.withFileTypesmust be a literaltrueorfalse, andexcludefunctions cannot be combined withwithFileTypes. Thefs/promisesiterator is supported only as the source of afor awaitloop, and its walk completes when the loop starts.fs.globcallbacks receive file names, not Dirents. - FileHandle and descriptor I/O: Static reads and writes accept Buffer and Uint8Array windows, numeric positions, and UTF-8 strings. FileHandle reads also accept options records and allocate a buffer when omitted. Vector I/O, truncation, syncing, and permission changes compile. Ownership changes, timestamps, and bigint Stats remain unsupported; FileHandle streams and
readLinesare covered under File streams. Dynamic descriptor I/O accepts other ArrayBuffer views and Buffer encodings; read positions outside the safe integer range are refused. File operations complete synchronously before their callbacks or promise continuations. Descriptor permission changes on Windows throwENOSYS. - File streams:
fs.createReadStream,fs.createWriteStream,new fs.ReadStreamandnew fs.WriteStream(in JavaScript sources), and FileHandlecreateReadStream,createWriteStreamandreadLinesreturn Readable and Writable streams. Options are checked when the stream is created, with Node's errors and order;flagsandmodeare checked when the file opens, so their errors arrive as'error'events.bytesRead,bytesWritten,path,pending,close(),close(callback)with a() => voidcallback, and the'open'and'ready'events compile. Numericflags, thefs,signalandwindowsHandleoptions, write streams with an encoding other than UTF-8, andinstanceof fs.ReadStreamorfs.WriteStreamare unsupported. - Crypto: Hashing, HMAC, PBKDF2, and HKDF support every digest
crypto.getHashes()lists in Node 24, with OpenSSL's aliases and object identifiers. Hash and Hmac accept every Buffer encoding and any TypedArray or DataView,createHashandhash.copytakeoutputLength, andcrypto.hashtakes its options object; HMAC, PBKDF2, and HKDF reject the SHAKE and KMAC digests with Node's errors. Hash and Hmac values are also Transforms: they can be written, piped into, used aspipeline()stages, read, and listened to, and they report Node's errors after the stream flushes.copy()of a Hash whose stream flushed, and stream use of a value after its stream closed, throw a coded SC2020 error.timingSafeEqualcompares any view or ArrayBuffer. Secret KeyObjects (createSecretKey,generateKeyandgenerateKeySyncforhmacandaes) supporttype,symmetricKeySize,export(),equals(), andinstanceof KeyObject, and createHmac, hkdf, createCipheriv, and createDecipheriv accept them; asymmetric keys,KeyObject.from(), andtoCryptoKey()are not available.randomFill,randomFillSync(every view kind and ArrayBuffer),randomInt,randomUUID, andrandomUUIDv7follow Node 24.22, including callback timing; arandomIntcallback whose error parameter is typedError | nullreceivesnullwhere Node passesundefined. Scrypt supports its default parameters, numeric options, aliases, and memory limit. Both KDFs accept strings, Buffers, numeric typed arrays, DataViews, and fixed-length ArrayBuffers.createCipherivandcreateDecipherivsupport aes-128, aes-192, and aes-256 in CBC, CTR, and GCM modes and chacha20-poly1305, on native targets, throughupdate(),final(),setAAD(),setAutoPadding(),getAuthTag(), andsetAuthTag(); other ciphers, cipher streams, and wasm32-wasi builds are refused. Decrypting chacha20-poly1305 without an authentication tag fails infinal(); Node 24.22 returns unverified plaintext. Afterupdate()fails, for example past the AES-GCM limit of 2^36 - 32 bytes per message, every later call on that cipher throws; Node still letsfinal()run. An output encoding that is a function or an instance of a class definingtoStringthrows a coded SC2020 error. Public-key operations remain unsupported. Native derivations finish before their deferred callbacks, so computation blocks the caller. - Assertions: Assertion failures throw
assert.AssertionErrorwith Node'smessage,generatedMessage,code,actual,expected,operator, anddiffproperties.new AssertionError(options),instanceof, andassert.throws(fn, AssertionError)compile. WhenstrictEqualcompares function values,actualandexpectedread asundefined; whenassert.throwsorassert.rejectsreports an error that is not an instance of the expected class, or that does not match an expected object,expectedreads asundefined. Values whose type can be cyclic, such as recursive records, also read asundefined.assert.AssertionErrorused as a value outsideinstanceofthrowsSC2020.assert.deepEqualandassert.notDeepEqualfollow Node's loose comparison, including Maps, Sets, Dates, regular expressions, typed arrays, and errors; operands whose type can be cyclic or holds functions inside a structure are refused.assert.partialDeepStrictEqualfollows Node's partial comparison over the same values, with the same refusals. Checked-dynamic values compared deeply have no cycle detection. Errors in failure messages print as[Name: message], where Node prints the stack when only one side is an error.new Assert(options)compiles when it initializes aconstwith literaldiff,strictandskipPrototypeoptions, or none, and the binding is only used to call assertion methods. Other instances, such as ones passed as values, destructured, bound withlet, or built from options that are not a literal, throwSC2020. WithskipPrototype,deepStrictEqualandnotDeepStrictEqualcompare class instances, and operands of different static types, as checked-dynamic values. - Concurrent tests: with
{ concurrency }above 1, subtests run on their own fibers, and results are reported in declaration order, as in Node. Concurrent bodies resume in Node's order aroundbeforeEachhooks and nested suites. Other runner steps, such asafterEachandafterhooks, take no microtask turns between bodies, so code that observes the interleaving of concurrent bodies across those steps can see a different order than Node. - Test mocks:
mock.fn,mock.method,mock.restoreAllandmock.resetcompile, on the module'smockand ont.mock.mock.methodmocks a function-valued field of a record, such as an object literal or an interface-typed object. Class instances, builtin objects, and object literals whose methods usethisthrowSC2020. Calls through the object record it asthis, including calls of a method read off the object and called on its own, where Node recordsundefined.object.method === mockisfalse, because the field holds a wrapper of the mock.mock.fn()without an original,mock.getter,mock.setter,mock.property,mock.module,mock.timersand mock options throwSC2020. - Exit status: Numeric
process.exitCode = valuewrites in statement position set the implicit exit status, whichprocess.exit()uses when called without an argument. Reads, resets, and assignments used as values are unsupported. - Process memory:
process.memoryUsage()readsrssfrom the operating system andheapTotalandheapUsedfrom the runtime's allocator, so the heap figures start near zero and grow as the program allocates.externalandarrayBuffersare0, because Buffer and typed-array storage is part of the same heap. - Performance entries:
performance.mark(),measure(), and thegetEntriesmethods return entries with Node's fields,toJSON(), inspection, and identity.Object.keys,for...in, object spread, andhasOwnPropertyon an entry are unsupported, and an entry stored in anunknownslot prints as a plain object. - Builtin module lookup:
process.getBuiltinModule()exposes native subsets ofpath,path/posix,path/win32,os, and current-threadworker_threadsmetadata. Stored module references and functions retain identity. Other modules and exports, including storedWorkerconstructors, throwSC2020. DirectWorkerimports use the native worker support described below.process.versionsis a shared dictionary containingnodeandopenssl; other component versions are absent unless defined by the program. - ArrayBuffers and typed arrays: Fixed-length ArrayBuffers support shared typed-array and DataView storage. Resizing, transferring, Float16 arrays, and BigInt arrays are unsupported. Numeric typed arrays and Buffers preserve their kind and shared storage through
unknown, including when nested in records and arrays. Numeric typed-array constructors can be stored and used withnew, including constructors read from an array'sconstructorproperty. JavaScript numeric-array parameters and returns preserve typed-array storage.Buffer.from,Buffer.allocUnsafe, andBuffer.concatreturn views into a per-thread pool ofBuffer.poolSizebytes (64 KiB by default) when the size is belowBuffer.poolSize >>> 1, as in Node; a pool slab stays in memory while any of its Buffers does. Node's own startup code allocates from the first slab, so thebyteOffsetof Buffers in that slab differs from Node's. Buffers returned by other Node APIs, such asfs.readFileSyncandzlib, own theirArrayBuffer, where Node allocates small ones from the pool. - Blob and File:
new Blob()andnew File()accept arrays, typed arrays,Set, andMapas sources. Other iterables throwSC2020.blob.stream(),blob.textStream(),URL.createObjectURL(),stream/consumersblob(), and Blob or File fetch bodies are unsupported. Blobs cannot be sent to workers. - Prototypes: Named properties and methods on program class prototypes support replacement, inheritance, and deletion. Bare prototype reflection, accessor replacement, and prototype storage on local, generic, mixin, or runtime-provided classes are unsupported.
- Intl.Segmenter: Default Unicode grapheme segmentation, iteration, and
containing()compile. Locale negotiation, word and sentence segmentation,resolvedOptions(), and detached methods are unsupported. - Globals: Stored
globalThisreferences support identity and probes for absent capabilities. Most builtin members require direct global access; access through a stored global object can raiseSC2020. - Map and Set: Keys and elements support numbers and strings by value, and records, classes, arrays, symbols, server handles, and unions of these reference types by identity.
unknownslots use native checked values, comparing supported primitives by value and retaining supported object references. Typed nested collections other thanMap<unknown, unknown>andSet<unknown>, and promises requiring payload adapters, cannot pass into these slots.Promise<unknown>retains its native representation. Storedkeys(),values(), andentries()iterators compile, retain element identity, and observe live collection mutations until exhausted. They support.next(),for...of, array spreads, and mapper-lessArray.from. Detached collection methods and iterator helper methods such as.map()and.take()are unsupported. The Set composition methods (union,intersection,difference,symmetricDifference,isSubsetOf,isSupersetOf,isDisjointFrom) accept a Set of the same element type or a Map keyed by it; other set-like arguments are unsupported. - Compression: The one-shot
deflate,inflate,deflateRaw,inflateRaw,gzip,gunzip, andunzipfunctions and theirSyncforms accept Node's options, validated at run time, includingdictionary,maxOutputLength, andrejectGarbageAfterEnd. Typed inputs are strings, Buffers, and Uint8Arrays; untyped JavaScript values may also be other TypedArrays, DataViews, and ArrayBuffers. Theinfooption is unsupported. TheDeflate,Inflate,Gzip,Gunzip,DeflateRaw,InflateRaw, andUnzipstreams, fromcreateGzip()and the other factories ornew zlib.Gzip(), accept Node's options and support writes, piping,pipeline, async iteration,flush,params,close,reset, andbytesWritten. Each output chunk is its own Buffer rather than a slice of a shared chunk-size buffer.zlib.constantsmembers and their module-level copies read as Node's values.util.inspect,instanceof zlib.Gzip, and Brotli and Zstd compression are unsupported. - Synchronous iteration: Checked
for...offollows live iterator methods, including compiled class methods and abrupt-completion cleanup. Mapper-less checkedArray.fromaccepts those iterators and plain array-like objects. Sparse checked arrays and general borrowed iterator factories are unsupported. Direct statically typed class loops also restrict iteratorreturnandthrowmethods. - Regular expressions: Native checked storage preserves identity,
source,flags, flag properties, and statefultest. Staticexec, globalmatch, and numericlastIndexaccess use the native matcher. Runtime constructors accept checked strings and native regex copies;replaceandreplaceAllaccept native regex values with string templates or callbacks, including captures, named groups, and UTF-16 offsets. Non-numericlastIndex, detached methods, andexecthrough an untyped receiver are unsupported. Thed(match indices) andv(unicode sets) flags are unsupported: regex literals andnew RegExpcalls with a literal flag string containing them fail to compile with SC1120, andnew RegExpwith a computed flag string containing them throws an error naming the flag. - Object freezing:
Object.freezeandObject.isFrozensupport plain checked dictionaries and primitives. Freezing is shallow and preserves accessors. Aliased typed records, arrays, proxies, and other native objects cannot be frozen.
Builtin function values
Some builtins can be stored and passed as functions:
- Lowered
node:pathfunctions across the bare, POSIX, and win32 modules, including optionalbasenameand variadicjoin/resolve. - Supported zero-argument
node:osfunctions andquerystring.escape/unescape. util.isDeepStrictEqual,styleText,stripVTControlCharacters,toUSVString,inherits,deprecate,callbackify,debuglog, anddebug.fs.existsSync,unlinkSync,chmodSync,chownSync,renameSync, andcloseSync, andfs/promises.unlink,chmod, andrename.
Other immutable aliases of table-backed Node builtins support direct calls, but cannot be passed elsewhere. util.promisify supports compile-time conversions of child_process.execFile, child_process.exec, setTimeout and setImmediate (to the timers/promises functions, as in Node), stream.finished and stream.pipeline (to the stream/promises functions, as in Node), the zlib callback one-shots deflate, inflate, deflateRaw, inflateRaw, gzip, gunzip and unzip (with or without options), and the fs callback functions that have an fs/promises counterpart (access, appendFile, chmod, chown, copyFile, lchown, link, lstat, lutimes, mkdir, mkdtemp, readFile, readdir, readlink, realpath, rename, rm, rmdir, stat, statfs, symlink, truncate, unlink, utimes, and writeFile); calls through the converted function lower as the fs/promises call.
util.styleText supports standard formats and aliases, #RGB and #RRGGBB hex colors, arrays of formats, nested ANSI resets, and explicit color enabling with { validateStream: false }. Native calls accept standard process streams; custom native streams and mutations to util.inspect.colors remain unsupported.
util.inherits links the prototypes of constructor functions, and util.deprecate, util.callbackify, and util.debuglog return native function values that forward receivers and arguments. Class constructors passed to util.inherits or util.deprecate are refused. Deprecation warnings are emitted on the next tick and follow assignments to process.noDeprecation and process.throwDeprecation; compiled binaries take no Node command-line flags such as --no-deprecation or --trace-deprecation, and process.traceDeprecation is unsupported. A stored util.deprecate reports a length of 4, where Node reports 3. In TypeScript, a util.callbackify result must reach a callback whose error parameter accepts null; the @types/node overloads that type it as non-null are refused. util.debuglog reads NODE_DEBUG as the process started. Its %s refuses functions and objects with symbol-keyed members, %o refuses objects, and object arguments are refused on a color terminal.
util.isDeepStrictEqual supports primitives, ordinary records and arrays, cycles, enumerable string and symbol properties, and byte views. Its optional third argument skips prototype and constructor comparisons. Structural comparisons of native Maps, Sets, class instances, Errors, proxies, accessor properties, and function-valued own constructor properties remain refused.
Synchronous and promise filesystem APIs with trailing arguments that affect behavior remain call-only. This includes writers, open, directory creation/removal, metadata readers, and directory readers. Passing them as values could discard modes, flags, encodings, or options during function-signature adaptation.
Native error-first filesystem callbacks can be stored and passed to platform adapters. Reads support Buffer and UTF-8 results; writes preserve string flags and modes; copy follows fs.cp. Reads and writes reject already-aborted signals, but native file operations complete synchronously before the deferred callback, so cancellation cannot interrupt I/O in progress. Recursive directory reads and Dirent results report a native limitation. fs.glob compiles only as a direct call; a stored fs.glob value throws SC2020.
Native worker threads
node:worker_threads runs workers as native threads. Worker entry points must resolve at build time: use a source-relative new URL("./worker.ts", import.meta.url), the current module URL, an absolute path, or CommonJS __filename. Each worker initializes its own module state, event loop, environment snapshot, and reference-counted heap. Nested workers inherit their parent's environment snapshot. Supported constructor options are workerData, argv, and a transferList of MessagePorts; runtime paths, eval, loaders, custom stdio, shared environments, and resource limits are unsupported. Worker argument strings containing null bytes are also unsupported.
Workers support online, message, error, and exit events, postMessage, terminate, ref, and unref. new MessageChannel() from node:worker_threads makes two entangled MessagePorts, in one thread or across threads once a port is transferred, with receiveMessageOnPort. Port messages arrive in Node's order: each port's queued messages as one batch before setImmediate callbacks, a port's own 'close' after the poll phase, and the other port's 'close' after its queued messages while the loop keeps running. A port's onmessage property, addEventListener, receiveMessageOnPort(parentPort), and BroadcastChannel are unsupported. The parent port supports message listeners, postMessage, close, start, ref, unref, and hasRef. Messages clone primitives, plain object graphs, arrays, errors, ArrayBuffers, typed arrays, and DataViews, preserving cycles and aliases. Program class instances arrive as plain objects with their own data properties, without their prototype, methods, accessors, or private fields, as in Node. A MessagePort travels with a message when the message's transfer list (an array or { transfer }) names it, and the sending port is unusable afterwards; a port in a message without that listing throws DataCloneError. Other transferable values, functions, proxies, and other native handles are refused. SharedArrayBuffers share their backing storage while retaining separate wrappers in each thread. Graphs made immutable with @scriptc/threads are passed by reference instead of cloned; see Sharing Data Between Workers.
SharedArrayBuffer storage is fixed-length. Atomics supports integer load, store, exchange, compareExchange, add, sub, and, or, and xor over 8-, 16-, and 32-bit integer arrays. wait and notify use Int32Array views; BigInt atomics, waitAsync, and growable buffers are unsupported. Atomics operations run as sequentially consistent atomic instructions and take no lock. Other reads and writes of shared storage access each element atomically; a copy, fill, or conversion that runs while another thread writes the same storage can observe some of those writes, as in Node. terminate unwinds at runtime checkpoints, including loops and parked atomic waits, without running JavaScript catch or finally blocks. Blocking native calls finish before the next checkpoint.
Workers are unsupported in WASI, compiled libraries, and executables that use foreign-thread native callbacks. Ordinary callbacks that run on their owning script thread remain supported. Shared byte storage cannot expose unmanaged FFI pointers; copy it into an ordinary Buffer before passing it to native code.
Child-process workers
child_process.fork() requires a worker path resolved at build time from new URL("./worker.ts", import.meta.url) or fileURLToPath(new URL("./worker.ts", import.meta.url)). Never-reassigned const aliases and statically resolvable template parts are accepted. The worker and its imports are embedded in the executable, which re-executes itself to start that module. Worker arguments begin at process.argv[2].
Supported options are default inherited stdio or an inline object with cwd, env, silent, windowsHide, or [stdin, stdout, stderr, "ipc"]. execArgv is accepted but has no native effect. Runtime worker paths, custom execPath, advanced serialization, transferred sockets or servers, uid/gid, timeout/signal options, and other stdio arrays are unsupported.
Parent and child channels support send(message, callback?), connected, disconnect(), and on/once for message and disconnect. Message listeners may return void or Promise<void>. Messages use newline-delimited JSON, so their static types must be JSON-stringifiable or unknown backed by a checked JSON tree. send() returns the channel's backpressure state and invokes its callback later with null or an Error. disconnect() changes connected synchronously, before the later disconnect events.
Untyped values
Supported uses of any use native checked values. Operations without native lowering produce diagnostics such as SC2011. Use unknown with a checked cast where an operation needs a concrete type. Map and Set type arguments may use any, with the same checked storage as unknown.
Locals, parameters, and returns can carry untyped values; record and tuple fields can hold unknown. JavaScript instance fields and TypeScript class fields declared unknown or object (also with null or undefined, or as arrays of those) can also hold native checked values. Bare fields start as undefined, and redeclaring a field with the same checked-value type resets it in initialization order. Explicit TypeScript any class fields, other checked-value static fields, statically typed array elements, and union members are unsupported.
Program class instances retain identity through unknown and casts back to their exact class or a base class, including classes with internal collections. Inspecting dynamic properties throws a catchable TypeError if the class's fields cannot pass through checked storage. Supported native handles also retain identity. JavaScript argument and return conversions preserve native array references; other JSON-shaped record and array conversions can copy values.
Supported operations on unknown include truthiness, typeof narrowing, property access, +, switch, and throw. Cast before using other operations.
Type checking
scriptc checks programs against the es2025 standard library, the ESNext declarations for Array.fromAsync, explicit resource management and Error.isError, and its own ambient declarations. Some declarations differ from TypeScript's standard library or @types/node: JSON.parse returns unknown, and a Promise executor's reject reason is typed as Error.
A program that passes its project's TypeScript check may still use unsupported operations. A second preflight using the project's declarations distinguishes those sites from ordinary type errors and reports scriptc diagnostics with rewrite hints. Declared APIs without a compiler implementation, such as unsupported console members, produce SC2020.
Contract types
Contract types are checked only where they are written as the annotation of a parameter, variable, class instance field or function result, Acyclic only on classes, interfaces and object type aliases, and ProgramLifetime only in the implements clause of a class declaration; other aliases, interface members and nested type positions are reported. In programs that use worker threads, a surrounding try/catch does not discharge NoThrow. Int32 refuses parameters of functions used as values and fields of classes whose instances are stored in any or unknown values. Int32[] refuses arrays that can come from or escape to code scriptc cannot see, does not follow callback results (such as map results), and checks a copy made by slice or a spread as if it were its source array. Element reads that find a value are int32s, but a scalar Int32 slot still needs a[i] | 0, because a read can miss and produce undefined. Immutable refuses values stored in any or unknown or that another reference can still change. ProgramLifetime applies to root classes of executables only; instances the program drops are never reclaimed unless they belong to a released lifetime region.
three.js
With --npm-static=three, native and WASI builds support published package imports and tested CPU workflows for math, bounds, procedural geometry, curves, shapes, extrusion, text geometry, scene graphs, cameras, lights, materials, textures, and render-target data. Mesh workflows include instancing, batching, morph targets, skeletal deformation, LOD, and sprites. Raycasting includes mesh intersections, sorted results, recursive traversal, layers, distance limits, camera rays, lines, and points.
Animation coverage includes tracks, clips, property binding, mixer playback, blending, and fading. In-memory loading covers scene, material, geometry, and animation JSON, OBJ, STL, PLY, and self-contained glTF/GLB scenes with buffers, PBR material data, and animation. This establishes the exercised workflows, not every loader extension or overload.
Tested CPU graph construction from three/webgpu and three/tsl includes scalar/vector nodes, mutable uniforms, Fn layouts and calls, and MeshBasicNodeMaterial data.
WebGL/WebGPU rendering, DOM controls, image and video resources, audio, and worker-based decoders require external host bindings. A browser or native application can render geometry and material state produced by a compiled library and receive its resource lifecycle notifications. Compressed model and texture decoding belongs to that host; shader execution and rendered output are outside the CPU coverage described here.
Runtime differences from Node.js
Compiled code has runtime behavior that can differ from Node.js. Account for the following differences when porting a program.
Array bounds and runtime errors
Typed-array reads at an index that is not an integer in the array's range return undefined, as in Node.js, and invalid numeric indexed writes are ignored, while the assignment expression retains its original value. A non-null assertion on such a read (bytes[i]!) yields NaN instead of undefined.
Ordinary arrays track holes separately from present undefined values. Missing reads and empty pop()/shift() return undefined, indexed writes can grow the array, and length growth creates holes.
Runtime traps cannot be caught. User-thrown values and supported exceptions, including JSON parse, checked-cast, filesystem, regex, and String.prototype.repeat count errors, can be caught; hard traps such as out-of-range reads of statically typed ordinary arrays terminate the process.
Deep recursion in Linux and macOS executables throws Node's catchable RangeError: Maximum call stack size exceeded, on the main thread, in worker threads, and inside async functions and generators. The depth at which it is thrown differs from Node: the main thread uses the process stack limit (usually 8 MiB), worker threads get an 8 MiB stack, and async functions and generators run on 512 KiB stacks, so native code usually recurses deeper than Node on threads and somewhat less deeply inside async bodies. Recursion inside runtime library operations, such as serializing deeply nested data, is not checked. Windows executables, WASI builds and library builds do not check the stack, and exhausting it there terminates the process.
Runtime type checks
Casts from values whose type is only known at runtime validate the value. For example, JSON.parse(s) as Config throws a catchable error if the data does not match Config, identifying the offending path, such as expected number at $.port, got string. A TypeScript assertion alone does not perform this validation when run under Node.js.
Casts between program classes are checked too: casting an instance to a class it does not extend throws a TypeError, where Node.js reads the members structurally. SC6004 reports calls that pass such an instance to a function that casts it.
A Promise converted from unknown to a typed result validates its fulfilled value. A mismatch rejects with a TypeError. Rejection reasons and reference equality are preserved across conversions.
Record identity and property order
A record converted to a record type with a different set of properties, such as a narrower shape or one that adds optional properties, is copied. Mutations through the converted reference do not affect the original, and the copy is not === to it. Empty record layouts are also snapshots because they have no property storage. scriptc coverage and scriptc build report SC6001 where a copied value is then written or compared, whether the record was passed as an argument, stored in a typed binding, asserted with as, assigned to a typed binding later, or stored as an element of a typed array literal.
Typed records with declared fields, indexed records, and arrays retain identity and mutations through native checked storage. Class instances retain identity at their exact type or a base class, and at any interface or object type that a class instance is passed, stored, returned, or asserted as when the program could tell a copy from the instance: values of such a type are checked views of the original object, so writes, identity comparisons, Set and Map keys, util.inspect, and JSON.stringify through them reach the instance, as in Node.js. These types use checked dynamic storage, which is slower than native record fields, for all of their values, including plain objects. A type whose values are only read field by field, from fields the class does not write after construction and does not implement as accessors, stays a native record and holds a copy. Object spread of a class instance is refused. Dense array literals created directly in checked storage preserve identity, and supported native handles pass by reference.
Object.keys, Object.values, Object.entries, and JSON.stringify use a record's declaration order rather than per-object insertion order. Their order matches Node.js when objects are built in declaration order. SC6002 reports object literals whose order differs where the program observes it.
A record converted from a checked value, such as const rows: { score: number }[] = JSON.parse(text), keeps the properties its type does not declare. JSON.stringify, Object.keys, Object.values, Object.entries, util.inspect, and untyped views of the record see them, together with the declared fields, in the source object's key order. Object.values and Object.entries check those values against their static result type and throw a TypeError if one does not fit. Copies of such a record made by object spread, Object.assign, rest destructuring, or conversion to another record type contain only the declared fields. Index-signature records list declared fields before the other keys.
Optional fields and properties added through a record's unknown view can be deleted. A required field has no absent state, so deleting it through the view throws TypeError: Cannot delete property 'x' of #<Object> and leaves the record unchanged, where Node.js removes the property.
Buffer construction
Buffer.from accepts untyped strings, byte arrays, arrays, and plain array-like or Buffer JSON objects. Encoding arguments must be supported literals. Custom input valueOf hooks and opaque class or native-handle inputs throw an unsupported-operation error.
HTTP headers
Without @types/node, the bundled declarations type every req.headers value as a string. Reading headers["set-cookie"] is then refused, and a { ...req.headers } copy holds set-cookie as one string joined with ", ", where Node holds an array. Read headersDistinct["set-cookie"], or install @types/node, whose headers["set-cookie"] is string[].
JSON callbacks
Function replacers and two-argument revivers support nested replacements, object-property deletion, and thrown exceptions. Omitting the root through a replacer returns undefined. Array replacers list the object keys to serialize, as in Node.js. Stored JSON.stringify functions accept numeric and string indentation; direct calls require literal indentation.
Reviver source contexts are unsupported. A reviver that deletes an array element throws, because checked arrays cannot represent holes.
Callback values use checked storage. Typed records and arrays retain identity and mutations; record fields use declaration order; typed-array views retain backing storage and brands. Buffer.isBuffer preserves the Buffer brand through unknown. JavaScript callbacks receive the holder as this; TypeScript callbacks that access dynamic this are unsupported.
Strings and sorting
Strings are stored as UTF-8, with lone surrogates kept as their own code units. Length and string methods use UTF-16 semantics, including for lone surrogates, but relational comparisons such as < and > use code-point order. split with a string separator and replace or replaceAll with a string pattern don't match a lone surrogate against half of a surrogate pair; regular-expression patterns do. Output, file contents, and other encoded text write each lone surrogate as U+FFFD, as Node does. File system paths and network host names that contain a lone surrogate reach the operating system unconverted.
One-argument localeCompare follows Node's default root-locale collation for Latin-script text (ASCII, Latin-1 Supplement, Latin Extended-A, combining diacritical marks, and U+2044 FRACTION SLASH): letters order before case and accents, so "a".localeCompare("B") is -1. Strings containing other characters compare by code point, which can differ from Node's ICU collation; SC6003 reports such string literals. The locales and options arguments are unsupported.
sort and toSorted use stable natural merge sort. Default ordering supports string, number, and boolean arrays, comparing their string forms in UTF-16 order; for example, [2, 10, 1].sort() produces [1, 10, 2]. sort preserves holes at the end, while toSorted produces a fresh array with holes filled by undefined. With an explicit comparator, consistent comparators produce the same sorted results as Node, but callback order and count can differ.
Typed-array sort and toSorted order numbers by default, with -0 before 0 and NaN last. With a comparator, they call it in the same order as Node and write the sorted values back after the last call.
Published graphs
Graphs published with @scriptc/threads are immortal: scriptc never frees them, even after every thread has stopped using them. Publish long-lived data, not per-request messages.
A receiving thread reads the sender's objects, so they keep their classes, methods, and identity across threads and across messages. Node.js delivers clones without prototypes, a new clone for every message.
Writes into published objects throw Node's frozen-object TypeErrors. In Node.js, o.x = f() evaluates f() before the write fails, and scriptc does the same, except for writes to union-typed class fields and for Map, Set, and array mutator methods, where the write check runs before the arguments are evaluated. Private fields (#x) of published objects cannot be written either, although Node.js allows writing private fields of frozen objects.
Dates and timezones
String constructors and Date.parse accept ECMAScript date-only forms, date-times with an explicit Z or numeric offset, and GMT certificate-validity strings from the supported X509 APIs. Other V8-specific forms and offset-less local date-times produce an Invalid Date or NaN; SC6005 reports string literals in those forms.
Local calendar getters use the operating system's timezone database. Historical results can differ from Node.js when timezone data differs. For valid extreme years outside a platform calendar API's range, scriptc uses a calendar-equivalent year in the 400-year Gregorian cycle to obtain the timezone rule.
Weak collections and memory
WeakMap and WeakSet accept checked native objects and arrays, functions, numeric typed arrays, ArrayBuffers, native weak collections, and typed records, arrays, tuples, and classes that preserve identity through checked storage. Copied values, other native handles, and symbol keys are unsupported. Constructor seeds support arrays; custom iterators and detached methods are unsupported. Weak collections do not retain their keys, but values that refer back to a key can keep it alive until deletion or collection release.
Memory uses reference counting. Acyclic values are freed deterministically, and cycles are collected at defined collection points. Native checked objects, arrays, Sets, and captured closures participate in cycle collection. Cycles through opaque native capsules can remain allocated.
Foreign-thread callbacks
FFI format 5 accepts retained, context-bearing void callbacks invoked by library-owned threads. The native callback copies arguments and queues work; the script closure runs on the event loop at least one turn later. These callbacks are not suitable for real-time execution.
Value-returning callbacks and direct script execution on foreign threads are unsupported. Reference counting and exception state belong to the script thread, and waiting for the event loop can deadlock.
TLS ciphers
Before the handshake Node's tlsSocket.getCipher() returns undefined, and after close null. Its declared result is the { name, standardName, version } record, so a typed read there throws a TypeError instead. After the handshake the record matches Node, with OpenSSL's suite name in name. The suite itself is the one the bundled mbedTLS negotiates, which can differ from OpenSSL's choice for the same peers.
Console and process streams
console.log, info, and debug write to stdout; error and warn write to stderr. They accept unknown, printing strings verbatim and other values through native util.inspect. Direct calls support global console and node:console imports. Stored global console values and detached output methods retain identity and accept ordinary arguments. Stored methods do not support format specifiers with substitution arguments. Other stored console APIs, custom Console instances, and console mutation are unsupported.
JavaScript can store process.stdin, stdout, and stderr, replace output write methods, and call saved methods with their stream receiver. Input supports data/end/error listeners, pause/resume, buffered reads, and TTY raw mode. Output writes are synchronous, with successful callbacks on the next-tick queue; queued backpressure is not modeled. Stored streams do not support piping, encoding changes, arbitrary properties, or other events. TypeScript output parameters support write(string).
DNS lookup errors
After a failed dns.lookup or dns.lookupService, Node calls the callback with the error alone, so the address and family parameters are undefined. A callback whose address parameter is typed string (as Node's own type declarations type it) receives "" and NaN there, or an empty array for all: true, because a typed string or number cannot hold undefined. An untyped callback receives the error alone, as in Node.
UDP socket options
socket.addMembership() and socket.dropMembership() on a dgram socket that is not bound yet throw SC2020; Node binds such a socket to an ephemeral port first, so bind the socket before joining a group. The SystemError that the buffer size methods throw (ERR_SOCKET_BUFFER_SIZE, for example from getRecvBufferSize() before bind()) has Node's message, code, errno and syscall, but no info object.
Process arguments and errors
process.argv[0] is "scriptc", process.argv[1] is the binary's path, and program arguments begin at index 2. process.version and process.versions.node report the Node.js release the runtime is verified against.
Uncaught exceptions print Uncaught <value> to stderr instead of Node.js's source excerpt and stack-trace block; thrown strings and numbers print their value. Exit codes and output written before the exception are preserved. Runtime errors expose message and Node's code, but not errno, syscall, or path.
Errors carry no stack frames. console.log and util.inspect print an Error in Node's stackless form, [TypeError: message], where Node prints TypeError: message followed by stack frames; the two agree when Error.stackTraceLimit is 0.
Runtime code evaluation
eval, new Function, and other ways of running JavaScript source at runtime are unsupported, in application code and in packages. Rewrite code that depends on them, or replace the package. To compute a value from code at build time instead, use comptime. See npm Dependencies for which packages compile.
Process events
Static signal listeners resolve names on the target platform, including SIGWINCH on POSIX. on, once, off, and removeListener accept computed signal names and deliver the signal name and number. Computed names for other event families and chained registrations are unsupported. Windows registration is limited to CRT signals; WASI has no OS signals.
Literal uncaughtException and uncaughtExceptionMonitor registrations compile. Handled exceptions resume queued native work; monitors alone do not suppress failure. Error objects and primitive exceptions can reach listeners, while arbitrary native objects remain subject to exception-value restrictions. Exception capture callbacks are unsupported.
Native addons
Node-API (N-API) and V8 .node addons depend on Node.js itself, so compiled programs can't load them. Direct createRequire calls to local addons are rejected at compile time. A package that requires an addon needs a JavaScript implementation that compiles, or a replacement through native FFI.
Use Native FFI to call a plain C ABI function linked from an object or static archive. The guide includes a replacement for a small Node-API helper.
WASI target
The wasm32-wasi executable target supports async/await, promises, generators, timers, portable event-loop work, stdin/readline, filesystem callbacks and promises.
WASI Preview 1 does not provide sockets, process spawning, OS signals, network interfaces, or filesystem notifications. Networking/fetch, child processes, signal APIs, os.networkInterfaces(), the os host facts without a WASI equivalent (cpus(), hostname(), freemem(), loadavg(), uptime(), getPriority()), and fs.watch are rejected before linking with SC3002. --sanitize and native FFI are unavailable.
Library mode emits an async-free Wasm reactor with named host imports. Native runtime localization and thread instances are unsupported. Each Wasm instance owns independent state. Filesystem access is limited to directories opened by the host; scriptc run exposes the current working directory and /tmp. See Platform Support for build and run details.
Tooling and native FFI
scriptc run does not forward extra CLI arguments to the program. Build an executable and invoke it directly to pass arguments.
Native FFI links C functions declared in a manifest. Formats 2–5 support call-scoped callbacks, copied string/byte callback parameters, explicitly released retained callbacks, and asynchronous foreign-thread delivery. Format 6 adds single-precision floats, signed 8-bit and signed/unsigned 16-bit integers, and borrowed writable byte spans. Variadic calls, structs by value, owned pointer/string/byte returns, runtime dynamic-library loading, and library-mode builds are unsupported. See Native FFI.
Numbers follow JavaScript's double-precision semantics.
Browser embedding
Wasm reactors require a host-provided WASI Preview 1 adapter. A reactor can run supported three.js CPU operations and send animated geometry, material state, and resource lifecycle notifications to an external web application through declared imports. The application supplies DOM, graphics, media, audio, and decoder bindings, including the renderer.
Library mode excludes promises, async functions, timers. See WebAssembly Modules for the embedding contract.
Native debugging
Executable builds with --optimization=dev support source breakpoints and native stack frames for compiled TypeScript and JavaScript. LLVM builds include source names and lexical scopes for locals, parameters, captured bindings, and module globals. Release builds and builds with --strip omit these source mappings. On macOS, executable builds produce an adjacent .dSYM bundle using the Command Line Tools' dsymutil.
Debugger values use native representations. Numbers and booleans display directly. Strings expose their ScrStr layout, including UTF-8 data and byte len; tagged unions expose their tag and slot fields. Other heap values and scalar bindings captured before initialization can appear as opaque pointers.
Debuggers can't evaluate TypeScript expressions or format values as JavaScript objects.