char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
b862289
main
Environment variables
Import env from avril:std:
import { env , pledge } from "avril:std" ; const token = env . get ( "API_TOKEN" ); env . delete ( "API_TOKEN" ); pledge ({ env :false }); // Pass the captured token explicitly to code that needs it.
env starts with a snapshot of the inherited process environment. Its mutations
are local to avril: they do not change the host process environment or native
libraries' configuration.
env.get(name)returns a string, orundefinedif the variable is absent.env.has(name)tests presence; an empty string is still a present value.env.set(name, value)creates or replaces a variable.env.delete(name)removes a variable; removing an absent variable is a no-op.env.toObject()returns an independent, mutable, null-prototype object containing only permitted variables. Changing it does not change the environment store.
All four named operations require permission for that name, even when the
variable is absent. Permission failures use errors.PermissionDenied from
avril:std.
Names must be nonempty and contain neither = nor NUL. Values may be empty but
cannot contain NUL. Invalid names and values use errors.InvalidInput. Names
and values are converted to well-formed strings; symbols are rejected. Host
variables with non-UTF-8 names or values are omitted rather than lossily decoded.
Names are case-sensitive on Unix and ASCII case-insensitive on Windows.
Permissions
Environment access is allowed by default. -0 disables it along with the other
ambient capabilities. Grant individual names with repeatable flags:
avril run-0 --allow-env=API_TOKEN --allow-env=MODE main.tsavril run--deny-env=API_TOKEN main.ts
Names are exact, not patterns or comma-separated lists. Explicit denials win over grants, regardless of flag order. Granting environment access does not grant filesystem, network, or module execution access.
pledge narrows environment authority just like other capabilities:
pledge ({ env :{ allow :[ "MODE" ], deny :[ "API_TOKEN" ] } }); pledge ({ env :false });
Omitted categories are unchanged. Successive pledges intersect allowed names and accumulate denials; they cannot restore authority. An invalid pledge does not partially change permissions. Retained methods recheck current permissions, but previously captured strings and snapshots remain usable.
Static imports execute before the importing module's body. Use startup permissions if dependencies must never see a secret, or capture and delete secrets before loading dependencies with dynamic imports.
Environment files
avril run accepts repeatable --env-file=PATH or --env-file PATH flags. Paths
are relative to the current working directory, not the entry module's directory.
Use the equals form (or a ./ prefix) for filenames beginning with -.
avril run-0 --allow-env=API_TOKEN --env-file=.env --env-file=.development.env main.ts
Inherited environment values take precedence, including empty strings. Later
files override earlier files, and the last assignment to a name within a file
wins. There is no implicit .env discovery. Missing, unreadable, non-UTF-8, or
NUL-containing files stop startup before JavaScript runs; diagnostics do not echo
file contents.
Naming an env file authorizes the CLI to load it, even with -0 or read denials,
but grants no environment or filesystem authority to JavaScript. Under -0,
each variable still requires --allow-env=NAME, whether its value comes from a
file or the inherited environment. Explicit --deny-env rules still win, and
pledge can subsequently remove authority. Loading values and granting access
are separate operations.
The dotenv syntax follows Node 24's conventions, with more predictable handling of indented comments, empty names, and whitespace-only empty values:
- Assignments use
NAME=value; surrounding spaces and tabs are trimmed. - Blank lines, indented comments, lines without an assignment, and assignments with empty names are ignored.
#begins a comment outside a quoted value.- Values enclosed in single quotes, double quotes, or backticks retain their interior whitespace and may span multiple lines.
- Double-quoted values expand literal
\nsequences into newlines. Other escapes and variable references such as$NAMEor${NAME}remain literal. - An
exportprefix is ignored. Empty values are empty strings, including exported assignments and values followed only by whitespace. - CRLF is supported, and an initial UTF-8 BOM is ignored.
- Text after a closing quote on the same line is ignored. If no matching closing quote exists anywhere later in the file, the value is kept literally through the end of its first line.
File values enter only the runtime-local env store. Unlike Node's flag, they do
not configure native libraries or CLI settings such as AVRIL_CACHE_DIR, and
NODE_OPTIONS has no special meaning.
1# Environment variables 2 3Import `env` from `avril:std`: 4 5``` ts 6import { env, pledge } from "avril:std"; 7 8const token = env.get("API_TOKEN"); 9env.delete("API_TOKEN"); 10pledge({ env: false }); 11// Pass the captured token explicitly to code that needs it. 12``` 13 14`env` starts with a snapshot of the inherited process environment. Its mutations 15are local to avril: they do not change the host process environment or native 16libraries' configuration. 17 18- `env.get(name)` returns a string, or `undefined` if the variable is absent. 19- `env.has(name)` tests presence; an empty string is still a present value. 20- `env.set(name, value)` creates or replaces a variable. 21- `env.delete(name)` removes a variable; removing an absent variable is a no-op. 22- `env.toObject()` returns an independent, mutable, null-prototype object containing 23only permitted variables. Changing it does not change the environment store. 24 25All four named operations require permission for that name, even when the 26variable is absent. Permission failures use `errors.PermissionDenied` from 27`avril:std`. 28 29Names must be nonempty and contain neither `=` nor NUL. Values may be empty but 30cannot contain NUL. Invalid names and values use `errors.InvalidInput`. Names 31and values are converted to well-formed strings; symbols are rejected. Host 32variables with non-UTF-8 names or values are omitted rather than lossily decoded. 33Names are case-sensitive on Unix and ASCII case-insensitive on Windows. 34 35## Permissions 36 37Environment access is allowed by default. `-0` disables it along with the other 38ambient capabilities. Grant individual names with repeatable flags: 39 40``` sh 41avril run -0 --allow-env=API_TOKEN --allow-env=MODE main.ts 42avril run --deny-env=API_TOKEN main.ts 43``` 44 45Names are exact, not patterns or comma-separated lists. Explicit denials win over 46grants, regardless of flag order. Granting environment access does not grant 47filesystem, network, or module execution access. 48 49`pledge` narrows environment authority just like other capabilities: 50 51``` ts 52pledge({ env: { allow: ["MODE"], deny: ["API_TOKEN"] } }); 53pledge({ env: false }); 54``` 55 56Omitted categories are unchanged. Successive pledges intersect allowed names and 57accumulate denials; they cannot restore authority. An invalid pledge does not 58partially change permissions. Retained methods recheck current permissions, but 59previously captured strings and snapshots remain usable. 60 61Static imports execute before the importing module's body. Use startup permissions 62if dependencies must never see a secret, or capture and delete secrets before 63loading dependencies with dynamic imports. 64 65## Environment files 66 67`avril run` accepts repeatable `--env-file=PATH` or `--env-file PATH` flags. Paths 68are relative to the current working directory, not the entry module's directory. 69Use the equals form (or a `./` prefix) for filenames beginning with `-`. 70 71``` sh 72avril run -0 --allow-env=API_TOKEN --env-file=.env --env-file=.development.env main.ts 73``` 74 75Inherited environment values take precedence, including empty strings. Later 76files override earlier files, and the last assignment to a name within a file 77wins. There is no implicit `.env` discovery. Missing, unreadable, non-UTF-8, or 78NUL-containing files stop startup before JavaScript runs; diagnostics do not echo 79file contents. 80 81Naming an env file authorizes the CLI to load it, even with `-0` or read denials, 82but grants **no environment or filesystem authority** to JavaScript. Under `-0`, 83each variable still requires `--allow-env=NAME`, whether its value comes from a 84file or the inherited environment. Explicit `--deny-env` rules still win, and 85`pledge` can subsequently remove authority. Loading values and granting access 86are separate operations. 87 88The dotenv syntax follows Node 24's conventions, with more predictable handling 89of indented comments, empty names, and whitespace-only empty values: 90 91- Assignments use `NAME=value`; surrounding spaces and tabs are trimmed. 92- Blank lines, indented comments, lines without an assignment, and assignments 93with empty names are ignored. 94- `#` begins a comment outside a quoted value. 95- Values enclosed in single quotes, double quotes, or backticks retain their 96interior whitespace and may span multiple lines. 97- Double-quoted values expand literal `\n` sequences into newlines. Other escapes 98and variable references such as `$NAME` or `${NAME}` remain literal. 99- An `export ` prefix is ignored. Empty values are empty strings, including 100exported assignments and values followed only by whitespace. 101- CRLF is supported, and an initial UTF-8 BOM is ignored. 102- Text after a closing quote on the same line is ignored. If no matching closing 103quote exists anywhere later in the file, the value is kept literally through 104the end of its first line. 105 106File values enter only the runtime-local env store. Unlike Node's flag, they do 107not configure native libraries or CLI settings such as `AVRIL_CACHE_DIR`, and 108`NODE_OPTIONS` has no special meaning.