char/avril
(wip) why'd you have to go and make things so complicaaaaated?
git clone https://git.t4t.associates/char/avril
b862289
main
HTTP(S) modules
Import modules directly or through a local import map:
import { value } from "https://example.com/lib/mod.ts" ;
URLs can also be entry points:
avril run https://example.com/app/main.tsavril update https://example.com/app/main.ts
Static imports are acquired before execution. Computed dynamic imports acquire
and prepare their static dependencies asynchronously. Relative and root-relative
imports resolve against the final response URL after redirects. Remote modules
do not inherit local package aliases or resolve filesystem imports; explicit
jsr: and avril: imports remain available.
Module identity and import.meta.url use the requested URL, not the cache path
or redirect destination. Queries and fragments distinguish module identities;
fragments are not sent to the server. Consequently, constructing a URL relative
to import.meta.url can differ from a relative import after a redirect.
TypeScript is transpiled according to the final URL's .ts or .mts extension,
ignoring its query and fragment. Content-Type does not select the source language.
Registry URLs retain JSR's manifest verification and package confinement.
Cache and integrity
HTTP sources are reused until avril update. The cache defaults to
$AVRIL_CACHE_DIR, $XDG_CACHE_HOME/avril, or $HOME/.cache/avril, with
--cache-dir=PATH as an override. Source blobs are content-addressed; updating one
project does not overwrite another project's pinned source.
The root avril.lock records the SHA-256 checksum and final response URL for each
requested URL. Successful graph preparation saves new pins; update explicitly
replaces encountered HTTP pins. If a pinned source is missing from the cache, an
online download must match both its checksum and final URL. Corrupt cached sources
fail integrity checks rather than silently being replaced.
--offline prohibits downloads. --frozen requires existing pins and does not
modify the lockfile. cache, info, --include, pruning, vendoring, and editor
support also work with HTTP sources. Vendor trees store sources beneath http/;
the lockfile supplies their checksums and redirect bases for offline use.
Permissions and redirects
Acquisition uses host tooling authority, independently of guest net, read,
and write permissions. Each requested module needs js-exec authority, even on
cache hits. Like local entry files, a URL entry point receives an exact execution
grant; explicit denials still override it.
Redirect chains check execution permission only for the initial requested URL, not the destinations. Granting a URL therefore trusts its server to redirect to any HTTP(S) destination, including other origins and local services. A denial for a destination does not block a redirect to it. Relative dependencies resolve to their own requested URLs and need their own execution grants.
The initial URL's execution permission is rechecked during asynchronous work and before linking cached modules, so revocation still takes effect. Redirects are limited to ten hops. Credentials and non-HTTP(S) destinations are rejected; responses are bounded to 32 MiB and downloads to 30 seconds. HTML responses are rejected as modules.
HTTP(S) packages
A directory URL ending with / in deps fetches avril.conf beneath that URL:
deps: [
'https://example.com/math/',
{from: 'https://example.com/format/', name: 'format'},
],
The first entry binds the package's declared name; the second overrides it.
Import that binding or an exported subpath, just like a local package.
The remote config uses the same schema, including exact exports, self-imports,
imports, scopes, and private deps. Relative remote dependencies are directory
URLs too: '../numeric/'. Remote configs cannot declare filesystem dependencies.
Exports and config-relative targets resolve against the config's final response URL after redirects. Export targets must stay within that URL's package directory; redirects follow the ordinary HTTP module rules. Dependencies do not grant execution permission to their exports or transitive dependencies.
The requested config URL requires js-exec permission, including when reading a
dependency's declared name and on cache hits. A directory URL execution grant
covers its config and modules. Configs and sources are pinned together in
avril.lock; update, --offline, --frozen, pruning, and vendoring apply to both.
Package ownership follows the importing module's config, not a global registry.
A package export starts in that package. Other URL imports match the importing
package's declared HTTP dependencies or its own requested/final directory, choosing
the most specific match. Nested package boundaries must be declared in the parent
package's deps; their configs are loaded only when a module crosses that boundary.
An unrelated package's private dependencies cannot change another module's maps.
Each requested module URL keeps its first owner, including plain modules. Reaching the same URL with a different owner is an explicit conflict, never a silent rebind. Redirected package aliases share ownership only when their final config URL, pinned contents, and module ownership region agree. Modules beneath the final package directory inherit only that canonical region, not an alias's requested directory. Other modules inherit their matching requested directory. All requested config URLs that have claimed a canonical package remain required execution authorities; revoking any of them blocks subsequent imports through every alias. Ordinary redirects still resolve relative imports and scopes against the module's final response URL.
avril does not probe remote ancestors for configs. Direct URL imports beneath a
declared dependency require that dependency's config and its execution permission;
imports from plain remote modules have no package context. Trailing-slash URLs are
package syntax in deps, not a change to direct URL entry points. URLs beneath the
configured JSR registry are reserved for registry packages, not HTTP configs.
An unused dependency whose name must be inferred still needs its config at package initialization. Network, cache, or permission failures are fatal for execution; the language server instead reports package errors and unresolved imports.
1# HTTP(S) modules 2 3Import modules directly or through a local import map: 4 5``` ts 6import { value } from "https://example.com/lib/mod.ts"; 7``` 8 9URLs can also be entry points: 10 11``` sh 12avril run https://example.com/app/main.ts 13avril update https://example.com/app/main.ts 14``` 15 16Static imports are acquired before execution. Computed dynamic imports acquire 17and prepare their static dependencies asynchronously. Relative and root-relative 18imports resolve against the final response URL after redirects. Remote modules 19do not inherit local package aliases or resolve filesystem imports; explicit 20`jsr:` and `avril:` imports remain available. 21 22Module identity and `import.meta.url` use the requested URL, not the cache path 23or redirect destination. Queries and fragments distinguish module identities; 24fragments are not sent to the server. Consequently, constructing a URL relative 25to `import.meta.url` can differ from a relative import after a redirect. 26TypeScript is transpiled according to the final URL's `.ts` or `.mts` extension, 27ignoring its query and fragment. Content-Type does not select the source language. 28Registry URLs retain JSR's manifest verification and package confinement. 29 30## Cache and integrity 31 32HTTP sources are reused until `avril update`. The cache defaults to 33`$AVRIL_CACHE_DIR`, `$XDG_CACHE_HOME/avril`, or `$HOME/.cache/avril`, with 34`--cache-dir=PATH` as an override. Source blobs are content-addressed; updating one 35project does not overwrite another project's pinned source. 36 37The root `avril.lock` records the SHA-256 checksum and final response URL for each 38requested URL. Successful graph preparation saves new pins; `update` explicitly 39replaces encountered HTTP pins. If a pinned source is missing from the cache, an 40online download must match both its checksum and final URL. Corrupt cached sources 41fail integrity checks rather than silently being replaced. 42 43`--offline` prohibits downloads. `--frozen` requires existing pins and does not 44modify the lockfile. `cache`, `info`, `--include`, pruning, vendoring, and editor 45support also work with HTTP sources. Vendor trees store sources beneath `http/`; 46the lockfile supplies their checksums and redirect bases for offline use. 47 48## Permissions and redirects 49 50Acquisition uses host tooling authority, independently of guest `net`, `read`, 51and `write` permissions. Each requested module needs `js-exec` authority, even on 52cache hits. Like local entry files, a URL entry point receives an exact execution 53grant; explicit denials still override it. 54 55Redirect chains check execution permission only for the initial requested URL, 56not the destinations. Granting a URL therefore trusts its server to redirect to 57any HTTP(S) destination, including other origins and local services. A denial 58for a destination does not block a redirect to it. Relative dependencies resolve 59to their own requested URLs and need their own execution grants. 60 61The initial URL's execution permission is rechecked during asynchronous work and 62before linking cached modules, so revocation still takes effect. Redirects are 63limited to ten hops. Credentials and non-HTTP(S) destinations are rejected; 64responses are bounded to 32 MiB and downloads to 30 seconds. HTML responses are 65rejected as modules. 66 67## HTTP(S) packages 68 69A directory URL ending with `/` in `deps` fetches `avril.conf` beneath that URL: 70 71``` text 72deps: [ 73'https://example.com/math/', 74{from: 'https://example.com/format/', name: 'format'}, 75], 76``` 77 78The first entry binds the package's declared `name`; the second overrides it. 79Import that binding or an exported subpath, just like a local package. 80The remote config uses the same schema, including exact `exports`, self-imports, 81`imports`, `scopes`, and private `deps`. Relative remote dependencies are directory 82URLs too: `'../numeric/'`. Remote configs cannot declare filesystem dependencies. 83 84Exports and config-relative targets resolve against the config's final response 85URL after redirects. Export targets must stay within that URL's package directory; 86redirects follow the ordinary HTTP module rules. Dependencies do not grant execution 87permission to their exports or transitive dependencies. 88 89The requested config URL requires `js-exec` permission, including when reading a 90dependency's declared name and on cache hits. A directory URL execution grant 91covers its config and modules. Configs and sources are pinned together in 92`avril.lock`; `update`, `--offline`, `--frozen`, pruning, and vendoring apply to both. 93 94Package ownership follows the importing module's config, not a global registry. 95A package export starts in that package. Other URL imports match the importing 96package's declared HTTP dependencies or its own requested/final directory, choosing 97the most specific match. Nested package boundaries must be declared in the parent 98package's `deps`; their configs are loaded only when a module crosses that boundary. 99An unrelated package's private dependencies cannot change another module's maps. 100 101Each requested module URL keeps its first owner, including plain modules. Reaching 102the same URL with a different owner is an explicit conflict, never a silent rebind. 103Redirected package aliases share ownership only when their final config URL, 104pinned contents, and module ownership region agree. Modules beneath the final 105package directory inherit only that canonical region, not an alias's requested 106directory. Other modules inherit their matching requested directory. All requested 107config URLs that have claimed a canonical package remain required execution 108authorities; revoking any of them blocks subsequent imports through every alias. 109Ordinary redirects still resolve relative imports and scopes against the module's 110final response URL. 111 112avril does not probe remote ancestors for configs. Direct URL imports beneath a 113declared dependency require that dependency's config and its execution permission; 114imports from plain remote modules have no package context. Trailing-slash URLs are 115package syntax in `deps`, not a change to direct URL entry points. URLs beneath the 116configured JSR registry are reserved for registry packages, not HTTP configs. 117 118An unused dependency whose name must be inferred still needs its config at package 119initialization. Network, cache, or permission failures are fatal for execution; 120the language server instead reports package errors and unresolved imports.