PJS runs explicitly registered CPU work in persistent Node workers, with bounded admission and explicit memory ownership. Your application keeps its event loop for I/O; PJS provides a separate compute plane. There are no runtime dependencies.
v1.0.0-rc.2 is the
current published prerelease, available on npm as @pjavascript/runtime under next.
Windows and Fedora/Linux x64 qualification completed;
macOS and ARM64 remain unclaimed. Final v1.0.0 has not been released.
RC readiness records the release gates and
platform boundaries. The immutable v0.15.0 release remains available.
API stability distinguishes core candidates, supported
ownership helpers, experimental range APIs and diagnostic statistics.
RC2 established the permanent package identity @pjavascript/runtime@1.0.0-rc.2.
The runtime implementation and public API are unchanged from RC1.
See the RC2 release note.
This branch prepares the RC4 candidate with the same R1A runtime qualified in RC3. RC3 reached a GitHub prerelease, but its npm workflow stopped before publication because the release validator assumed the wrong npm CLI JSON shape. RC4 corrects that release contract; execution leases and the published npm version remain unchanged.
Install the current prerelease from the public npm package:
npm install @pjavascript/runtime@nextUse @next deliberately until stable v1.0.0 exists; RC2 is a prerelease.
Qualified versions: Node 22.13+ within 22.x and 24.x. TypeScript tasks must be
compiled to JavaScript first. No CommonJS entrypoint is supplied.
Create tasks.mjs:
export function square(value) {
return value * value;
}Create basic-run.mjs:
import { PjsRuntime, PjsTaskRegistry } from '@pjavascript/runtime';
const registry = new PjsTaskRegistry();
const square = registry.register(
'square',
new URL('./tasks.mjs', import.meta.url),
'square',
);
const runtime = new PjsRuntime({ registry, workers: 1 });
try {
await runtime.ready();
console.log(await runtime.run(square, 12)); // 144
} finally {
await runtime.shutdown();
}Run node basic-run.mjs. The repository version is
executable and package-tested, or use
npm run example:basic from the checkout. Squaring a number teaches the contract;
it is too small to benefit from workers.
Node application
├─ event loop / asynchronous I/O
└─ PJS: bounded admission → fixed worker pool → registered module tasks
Register trusted local file exports before creating the runtime. Each worker imports those modules and keeps its own globals. PJS does not serialize closures, eval source strings, infer parallel safety or replace Node's event loop. Task handle types describe your declared schema; they cannot verify the loaded export.
| API | Use it for | Status |
|---|---|---|
| run | One explicit task, one promise | Core candidate |
| ready / shutdown | Startup and resource lifetime | Core candidates |
| partitionRange | Lazy numeric partitions, ordered per-partition outputs | Experimental |
| parallelFor | Completion-only ranges and deliberate side effects | Experimental |
| parallelMapRange | Flat ordered element output from validated array/typed blocks | Experimental |
| streamRange | Incremental completion-order results with count/optional byte backpressure | Experimental |
| transfer / sharedReadonly | Explicit moved buffers / reusable shared input | Specialized but supported |
| stats | Copied state and cumulative diagnostic counters | Diagnostic surface |
See the core API guide for contracts and options. Streams carry partition metadata so your application can reconstruct logical order; PJS does not promise ordered stream delivery.
Clone is the default: easy separation with copying/transport cost. transferList
moves input ArrayBuffers at dispatch and detaches every sender view; failures or
cancellation after dispatch cannot restore ownership. sharedReadonly makes one
copy into native SharedArrayBuffer backing; readonly is a contract, not freezing.
See memory ownership.
maxQueue bounds waiting logical tasks and rejects overflow with PjsQueueFullError.
A deeper queue is not more CPU capacity. Streams separately limit result count
and optionally reserve exact or maximum visible binary bytes. Upper-bound success
refunds slack on arrival; actual credit lasts until yield. Result credits do not
bound RSS, worker allocations, inputs or consumer-retained values. See
backpressure.
Cancellation/timeout can settle a caller while its worker is still busy. There
is no rollback. run timeouts include remaining startup and queue wait; stream
timeouts also include consumer delivery. A crash fails affected work and may
replace the worker without retrying the task. Omitted physical leases preserve
unbounded execution. The experimental R1 development API adds exclusive
run({ executionLease }), restartPolicy, and graceful shutdown({ forceAfter });
these are not in the already-published RC4 artifact. Leases initiate asynchronous
containment and retain occupancy until valid completion or confirmed exit.
Shutdown still drains indefinitely when escalation is omitted. See
lifecycle and errors.
Coarse CPU work can amortize worker overhead; tiny transforms usually cannot. Ordinary async I/O, cheap native calls and workloads already served well by native async APIs should generally stay there. Independent-block processing does not preserve one continuous compression context.
Choose workers as a resource policy. availableParallelism() is a default input, not a universal optimum: physical cores, SMT, native threads, application headroom and memory matter. More workers can improve throughput while hurting timer or filesystem latency. Measure your workload's crossover, transport and surrounding application rather than relying on a universal size threshold. The performance guide uses retained Windows/Fedora v0.13 and v0.14 evidence without general speedup claims.
The Science of PJS teaches concurrency, Node execution, and the cost of parallelism from first principles, using the runtime and its retained experiments as a case study. Later topics include scheduling, memory, and backpressure; you do not need PJS to learn from the material.
- Basic run: registration, execution, shutdown.
- Range work: typed map, completion-only shared output, and a synchronous native compute task.
- Shared input: immutable reusable numeric backing.
- Binary streaming: exact/maximum declarations, refunds and application-owned reconstruction.
- Cancellation: caller settlement versus occupancy.
- Transfer: move and return dedicated backing buffers.
Statistics and glossary · Architecture · Full inventory · 1.0 readiness · Stabilization report
From a checkout, build and pack a local artifact:
npm ci
npm run build
npm pack --workspace @pjavascript/runtime --pack-destination /tmpThen install that artifact in your ESM application:
npm install /tmp/pjavascript-runtime-1.0.0-rc.4.tgzReplace /tmp with an absolute temporary directory on your system (for example
$env:TEMP in PowerShell). Use npm.cmd if your PowerShell policy blocks npm.ps1.
npm test
npm run test:contracts
npm run test:types
npm run typecheck:compat
npm run lint
npm run format:check
npm run test:docs
npm run test:packageThe package gate packs and installs outside the repository, tests workers/errors, compiles and runs a TypeScript consumer, and executes the examples. test:contracts records individual-test totals even when the local --test runner reports file summaries. Historical research lives under docs and benchmarks; production code imports none of the workload harnesses. See toolchain and the benchmark methodology for their separate purposes.
Start with the contributor guide for setup, validation, and runtime/API change expectations. See support for questions and issue reporting, the Code of Conduct for community expectations, and the security policy for private vulnerability reporting.
Maintainers: see releasing for trusted npm publication.
MIT licensed. RC2 is published as a prerelease; final v1.0.0 has not been released.