char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
b862289
main
Module workers
Each worker runs on its own thread and V8 isolate. Workers have the same module loader, TypeScript support, built-in modules, and network APIs as the parent.
import { avril } from "avril:std" ; const worker = new Worker ( new URL ( "./worker.ts" , import . meta. url ), { type :"module" , name :"background" , [ avril ] :{ caps :{ env :false , write :false , net :{ allow :[ "example.com:443" ] }, }, }, }); worker . onmessage = ({ data}) => { console . log ( data ); worker . terminate (); }; worker . onerror = ( event ) => { event . preventDefault (); console . error ( event . message ); }; worker . postMessage ({ value :42 });
In worker.ts:
onmessage = ({ data}) => { postMessage ({ doubled :data . value * 2 }); close (); };
Only type: "module" is supported. Relative worker URLs resolve against the
parent's entry URL; new URL("./worker.ts", import.meta.url) is preferable when
the constructor is called from an imported module. A worker exposes self,
name, read-only location, postMessage, onmessage, onmessageerror, and
close. Workers may create nested workers.
Capabilities and environment
The avril export is Symbol.for("runtime:avril") and keys avril-specific
worker options. Omitting caps inherits the parent's capabilities. The object
uses the same restrictions as pledge: net, env, sys, read, write, jsExec, and run, each
either false or { allow, deny }. Restrictions apply before the entry module
loads. They cannot grant authority that the parent lacks.
A worker receives an independent snapshot of its parent's effective capabilities at construction; later parent or ancestor pledges do not restrict existing workers or their descendants, while workers spawned later from the pledged context inherit the narrowed policy. A worker's own pledge does not restrict its parent or siblings.
Workers receive an independent snapshot of the parent's runtime environment at construction time. Environment mutations are local, and access remains subject to capabilities. Worker standard input is unavailable; console and standard output/error remain available.
Messages and transfers
postMessage(value, transfer) and postMessage(value, { transfer }) support:
- Structured-clone graphs, including cycles, maps, sets, typed arrays, errors, blobs, files, DOM exceptions, crypto keys, and WebAssembly modules.
ArrayBuffertransfers, which detach the sender's buffer.SharedArrayBufferandAtomicsfor shared memory.MessagePorttransfers, including queued messages and retransfers.ReadableStream,WritableStream, andTransformStreamtransfers.
Stream transfers lock the sender's stream. Chunks and rejection/cancellation reasons are cloned across the message channel; demand and write acknowledgments preserve backpressure. Byte streams become default readable streams at the destination. Closing an endpoint or terminating its owner rejects outstanding remote operations.
const channel = new MessageChannel (); channel . port1 . onmessage = ({ data}) => console . log ( data ); worker . postMessage ({ port :channel . port2 }, [ channel . port2 ]); const bytes = new Uint8Array ([ 1 , 2 , 3 ]); worker . postMessage ( bytes , [ bytes . buffer ]);
Workers keep their parent alive until they close, fail, or are terminated.
close() finishes the current turn and discards future incoming tasks;
terminate() interrupts execution, including CPU-bound JavaScript. Parent
teardown terminates and joins its workers recursively.
1# Module workers 2 3Each worker runs on its own thread and V8 isolate. Workers have the same module 4loader, TypeScript support, built-in modules, and network APIs as the parent. 5 6``` ts 7import { avril } from "avril:std"; 8 9const worker = new Worker(new URL("./worker.ts", import.meta.url), { 10type: "module", 11name: "background", 12[avril]: { 13caps: { 14env: false, 15write: false, 16net: { allow: ["example.com:443"] }, 17}, 18}, 19}); 20 21worker.onmessage = ({ data }) => { 22console.log(data); 23worker.terminate(); 24}; 25worker.onerror = (event) => { 26event.preventDefault(); 27console.error(event.message); 28}; 29worker.postMessage({ value: 42 }); 30``` 31 32In `worker.ts`: 33 34``` ts 35onmessage = ({ data }) => { 36postMessage({ doubled: data.value * 2 }); 37close(); 38}; 39``` 40 41Only `type: "module"` is supported. Relative worker URLs resolve against the 42parent's entry URL; `new URL("./worker.ts", import.meta.url)` is preferable when 43the constructor is called from an imported module. A worker exposes `self`, 44`name`, read-only `location`, `postMessage`, `onmessage`, `onmessageerror`, and 45`close`. Workers may create nested workers. 46 47## Capabilities and environment 48 49The `avril` export is `Symbol.for("runtime:avril")` and keys avril-specific 50worker options. Omitting `caps` inherits the parent's capabilities. The object 51uses the same restrictions as `pledge`: `net`, `env`, `sys`, `read`, `write`, `jsExec`, and `run`, each 52either `false` or `{ allow, deny }`. Restrictions apply before the entry module 53loads. They cannot grant authority that the parent lacks. 54 55A worker receives an independent snapshot of its parent's effective 56capabilities at construction; later parent or ancestor pledges do not restrict 57existing workers or their descendants, while workers spawned later from the 58pledged context inherit the narrowed policy. A worker's own pledge does not 59restrict its parent or siblings. 60 61Workers receive an independent snapshot of the parent's runtime environment at 62construction time. Environment mutations are local, and access remains subject 63to capabilities. Worker standard input is unavailable; console and standard 64output/error remain available. 65 66## Messages and transfers 67 68`postMessage(value, transfer)` and `postMessage(value, { transfer })` support: 69 70- Structured-clone graphs, including cycles, maps, sets, typed arrays, errors, 71blobs, files, DOM exceptions, crypto keys, and WebAssembly modules. 72- `ArrayBuffer` transfers, which detach the sender's buffer. 73- `SharedArrayBuffer` and `Atomics` for shared memory. 74- `MessagePort` transfers, including queued messages and retransfers. 75- `ReadableStream`, `WritableStream`, and `TransformStream` transfers. 76 77Stream transfers lock the sender's stream. Chunks and rejection/cancellation 78reasons are cloned across the message channel; demand and write acknowledgments 79preserve backpressure. Byte streams become default readable streams at the 80destination. Closing an endpoint or terminating its owner rejects outstanding 81remote operations. 82 83``` ts 84const channel = new MessageChannel(); 85channel.port1.onmessage = ({ data }) => console.log(data); 86worker.postMessage({ port: channel.port2 }, [channel.port2]); 87 88const bytes = new Uint8Array([1, 2, 3]); 89worker.postMessage(bytes, [bytes.buffer]); 90``` 91 92Workers keep their parent alive until they close, fail, or are terminated. 93`close()` finishes the current turn and discards future incoming tasks; 94`terminate()` interrupts execution, including CPU-bound JavaScript. Parent 95teardown terminates and joins its workers recursively.