Node API compatibility and imports

Scripting runs JavaScriptCore with a Node compatibility layer. This page describes the built-in modules registered by Scripting, their useful API subsets, and important limitations. The node command in Scripting's shell uses this environment; it does not launch a desktop Node executable. process.version / process.versions.node report a compatibility baseline, not complete support for that Node release. Availability in widgets, keyboards, Safari and isolated vm contexts can differ; the network examples linked here target full App scripts.

Where to import from

SourceExamplesUsage
Built-in Node modulenode:net, node:tls, node:crypto, node:buffer, node:timers/promisesimport { createServer } from "node:net" or require("node:net"); no npm install
Runtime globalcrypto, Buffer, process, console, TextEncoder, TextDecoder, AbortController, setTimeout, setInterval, setImmediate, clearTimeout, clearInterval, clearImmediate, queueMicrotask, BonjourUse directly; no import. Bonjour operations require the full App runtime
Scripting SDK exportScript, Text, VStackImport the documented export from "scripting"; this is not a source for Node modules or WebCrypto
Third-party npm packageAn installed package and its dependenciesInstall through Scripting's npm tools, then import the package by its actual name

For registered built-ins, "net" and "node:net" resolve to the same module. A subpath needs its own registration: support for "stream" does not imply "stream/web". Both ES import syntax and CommonJS require() are supported through Scripting's module loader. Module evaluation uses CommonJS-style loading after transpilation; it is not a complete native Node ESM loader. Top-level await is supported in the script entry, not arbitrary required modules.

Each code block in the linked new API pages is an independent App script. Import declarations are at the top; awaiting work keeps its example active. Calling Script.exit() early closes owned resources and cancels pending timers.

Complete built-in-only example

This example needs no package installation, server or filesystem setup. It prints hello and its SHA-256 hexadecimal digest after a short delay.

import { Buffer } from "node:buffer"
import { createHash } from "node:crypto"
import { setTimeout as sleep } from "node:timers/promises"

// process and console are globals; no import from "scripting".
const message = Buffer.from("hello", "utf8")
await sleep(10)
console.log(message.toString("utf8"))
console.log(createHash("sha256").update(message.toString("utf8")).digest("hex"))
console.log(process.version, process.platform, process.cwd())

Functional modules and implemented subsets

“Subset” means the listed operations work, with the limitations described here and in the linked reference. It does not promise every API of current Node. Table names can be used with the node: prefix.

ModuleSupported entry points / usesLimits and reference
assertAssertions, equality/deep equality, strict assertions through .strictBrowser-compatible implementation; assert/strict is not separately registered
bufferBuffer.from/alloc/concat/isBuffer, encodings and byte viewsAlso global Buffer; not the Data API
string_decoderStringDecoder.write/end for incremental text decodingJavaScript Buffer-based implementation
eventsEventEmitter, on/once/off/emit, listener managementJavaScript event handling, not OS events
pathPOSIX path join/resolve/dirname/basename/extname/relativePath calculations do not grant file access; path/posix and path/win32 subpaths are not registered
url, querystring, punycodeURL/query parsing and formatting, query-string and punycode conversionsBrowser-compatible implementations; global URL/URLSearchParams are also available
util, util/typesFormatting/inspection, promisify/callbackify, type predicates, styleTextstyleText formatting does not create a real TTY; not every modern Node utility is present
streamReadable/Writable/Duplex/Transform/PassThrough, pipe, callback pipeline/finishedJavaScript stream implementation; not OS stream handles or full Web Streams interop
stream/promisesPromise wrappers for pipeline/finishedBuilt on the provided JS streams; use the documented subset rather than all recent Node overloads
stream/consumersbuffer/text/json/arrayBuffer/blob consumptionblob also requires a global Blob implementation; stream/web is not registered
cryptoHash/HMAC/PBKDF2, random bytes, supported AES/signing helpers; .webcryptoBrowser-compatible Node crypto subset plus Scripting WebCrypto; no blanket support for all Node algorithms or KeyObject features
zlibgzip/gunzip/deflate/inflate, raw variants, sync/callback/stream formsPure JavaScript compression; no Brotli or Zstd
fs, fs/promisesFile reads/writes, directories, stats, logical file handles, streams, opendir/DirSandboxed paths and host permissions apply. Callback/Promise forms may wrap synchronous work; they do not promise background-thread I/O. Watch APIs do not observe changes; chmod/chown/time setters include no-op compatibility methods
oshomedir/tmpdir, CPU count, memory and uptime/system informationhomedir maps to App documents, freemem describes App-available memory; per-CPU speed/times and some Unix fields are placeholders
httprequest/get, request/response events; buffered createServer adapterFull-runtime server uses Scripting HttpServer; request/response buffering, simplified Agent/socket fields, no Node raw-socket/upgrade contract
httpsrequest/get with system HTTPS networkinghttps.createServer shares the HTTP adapter and does not configure certificate TLS. Use Scripting's separate HttpServer TLS API for HTTPS hosting
netTCP Socket/connect/createConnection, streams, Server/createServer, numeric IPv4/IPv6 listeningFull App main-context server, bounded resources, no Unix sockets/UDP/cluster. Complete local echo example
tlsVerified certificate TLS client connect, secureConnect, streams, SNI/ALPN/custom CANo TLS server, STARTTLS/socket wrapping, PSK or insecure certificate bypass. Complete HTTPS example
timers, timers/promisesTimeout/Immediate handles, abortable delay, async interval, scheduler.wait/yieldGlobal timers return numbers; module timers return handles. No real-time or iOS background execution guarantee. Examples
processGlobal process metadata/env/argv/cwd, nextTick, hrtime, shell I/O adapters where providedNo OS process management; nextTick uses the JSC microtask queue rather than V8's separate priority queue
vmScript, createContext/isContext, runInContext/runInNewContext/runInThisContextSame VM with isolated globals; not a security boundary or worker. compileFunction is unsupported
modulecreateRequire with path-relative resolution/cacheMinimal module loader helpers; builtinModules is not a complete capability inventory
console, constantsRuntime logging, compatibility constantsNo real terminal or guarantee that all Unix constants describe available OS operations

Uppercase global Crypto operates on Scripting Data; lowercase global crypto is WebCrypto. For HKDF and the explicit ChaCha20-Poly1305 extension, use crypto.subtle / crypto.chacha20Poly1305, or import webcrypto from node:crypto. Do not assume createCipheriv("chacha20-poly1305", ...) or Node hkdfSync is provided. See HKDF/ChaCha and Curve25519.

Bonjour is a Scripting global, not a Node built-in; see its complete publish/browse/resolve example. The web-globals helper resource supplies globals internally; use the documented global APIs directly.

Importable compatibility placeholders

These modules can load so optional dependency paths can be detected, but their existence is not proof of functionality. Some operations throw; others return empty/no-op results.

ModuleActual behavior
dnslookup reports an error; query/resolver operations are unavailable. Native TCP/HTTP/TLS still resolve hostnames themselves. dns/promises is not a separately registered subpath; require("dns").promises is also a placeholder
http2Session/connect/server methods throw; constants/settings helpers have placeholder values. No Node HTTP/2 session API
child_processspawn/exec/execFile/fork and sync variants throw; no child processes
clusterSingle-process flags and no-op management helpers; fork throws
worker_threadsMain-thread flags; Worker construction throws, MessageChannel/MessagePort are placeholders
async_hooksHooks are no-op; AsyncLocalStorage callbacks run, but stores are not propagated and getStore returns undefined
diagnostics_channelNo subscribers or real event publication; tracing wrappers call the supplied function
perf_hooksBasic performance timing, placeholder observation/entries; no full PerformanceObserver collection
ttyisatty returns false; ReadStream/WriteStream placeholders
readline, readline/promisesNo interactive terminal input. Callback question does not receive user input; Promise question resolves an empty string. Use global Dialog for App prompts
v8Basic empty/default introspection values; serialization, heap snapshots and other V8 operations throw

dgram, inspector, repl and wasi reject when loaded. Other Node names or private internals absent from the registered inventory are unsupported, including domain, sys, trace_events, inspector/promises, assert/strict, path/posix, path/win32 and stream/web. A reserved resolver name or an editor completion is not an implementation.

Third-party npm packages

Use Tools → npm Packages or npm install <actual-package-name> in Scripting's shell. Pure-JavaScript parsers, formatters, validation and data-processing libraries are good candidates when their dependencies use the functional APIs above. Compatibility depends on the installed version, dependency tree and executed code path; there is no universal npm whitelist. Loading a package successfully does not verify its networking, subprocess or native paths.

Before adopting a package:

  1. Check its direct and transitive Node imports against this table, especially the placeholder section. A package that requires AsyncLocalStorage semantics, DNS queries, Worker or child processes needs a different code path.
  2. Prefer pure JavaScript distributions. .node native addons, downloaded executables, browser automation engines and OS build tools cannot run through this compatibility layer.
  3. Automatic dependency preinstall/install/postinstall/prepare scripts are skipped. Optional dependencies are not automatically installed. An installation can therefore succeed while an optional native feature is absent.
  4. Run the actual operation and inspect its payload/result, errors and cleanup; do not stop at require() success, an engine-version check or typeof fn === "function".
  5. Keep network/file permissions and iOS foreground/background limitations in mind. A package cannot acquire capabilities that its host script does not have.

For the complete callable signatures of the shipped subset, use Scripting's built-in TypeScript declarations and the linked API pages. This overview describes Scripting's implementations; it does not claim conformance to every API in desktop Node documentation.