# Packages and imports Module resolution is owned by `ModuleGraph` in `runtime/src/modules.rs`; package configuration is defined by `runtime/src/package_config.rs`. Each local `avril.conf` establishes a package boundary. Its `imports` and `scopes` apply to modules in its directory and descendants, until another config is encountered. An imported sibling library is discovered automatically; workspace registration is not required. Maps do not inherit across package boundaries. Targets and scope URLs are relative to the config file, not the working directory. Imports use exact matches or longest matching slash-terminated prefixes. Prefix targets must end with a slash. A `null` target blocks an import. Matching scopes are searched from most specific to least specific, followed by the package's default `imports`. Mapping is a single step, not recursive alias substitution. URL-like keys are normalized relative to the config, and URL-like specifiers are normalized relative to the importing module. Local module identity follows the canonical file path, including when reached through an alias or symlink. A module never changes ownership based on which consumer imported it. Explicit relative file imports remain available. Discovery walks canonical ancestors only while they are executable under the current capability policy. A directory execution grant permits config discovery inside that directory; an entry-file-only grant does not. Discovery stops at the first unauthorized ancestor. On Unix, discovery also stops before directories owned by neither the current user nor root, or writable by everyone, including shared temporary directories. Config files must also be owned by the current user or root, must not be world-writable, must be executable under the capability policy, must be regular files, and must not be symlinks. Successfully discovered maps and absent configurations are snapshotted for the lifetime of the loader; failed discovery can be retried. No map grants permission to execute its target; normal module access checks still apply, including to cached imports. On a terminal, `avril run` and `avril cache` write append-only acquisition progress to stderr: registry/source downloads, npm resolution, and package extraction and verification. Cached artifacts do not produce download messages. Progress is disabled for redirected stderr and `TERM=dumb`. The REPL reports only during foreground evaluation, not while waiting for input. Progress action words, including those printed by `avril add`, use color unless `NO_COLOR` is nonempty; package names and URLs in progress messages remain plain. The supported package schema is described in [configuration](config.md). Unknown options, malformed maps, normalized duplicate keys, and blocked imports are reported as errors. ## Inline modules `data:` URLs can name JavaScript or TypeScript ES modules, including entrypoints and module workers. Use `text/javascript` or `application/javascript` for JS, and `text/typescript` or `application/typescript` for TS. Payloads may be percent-encoded or marked `;base64`; module text is decoded as UTF-8 regardless of the MIME charset parameter. Missing MIME types default to `text/plain`, which is not executable. JSON and other non-script MIME types are rejected. ```ts import { answer } from "data:text/typescript,export%20const%20answer%3Anumber=42"; ``` A data module has no directory or package bindings: relative imports and bare package names are unsupported. Absolute `file:`, HTTP(S), `jsr:`, `npm:`, `data:`, and public `avril:` imports use normal resolution and authority checks. Inline source itself needs no filesystem or network grant and grants none to its code. The serialized URL is the module identity and `import.meta.url`. Repeated imports of the same URL share an instance; different percent/base64 encodings or fragments remain distinct identities. Fragments are not source text. Inline payloads are not stored as cache artifacts or lockfile entries; acquired dependencies retain their usual caching and locking. Checking and bundling use the same MIME-selected language; editors show decoded sources as read-only `avril-builtin:/data/` documents. This does not add `fetch(data:)` or synchronous `require(data:)` support. ## Named local packages and interfaces A consumer imports a dependency by the name it declares, or by a name the consumer chooses: ```text name: '@app/demo', deps: [ 'jsr:@std/assert@^1.0.19', '../math', {from: '../math-v2', name: 'math-next'}, {from: '../format', name: '@app/format'}, ], ``` Each dependency directory contains its own config defining its interface: ```text name: '@acme/math', version: '0.1.0', description: 'Shared math utilities', exports: { '.': './mod.ts', './vector': './src/vector.ts', }, deps: [{from: '../numeric', name: 'numeric'}], ``` The application imports `@acme/math` or `@acme/math/vector`; with `{from: '../math', name: 'math'}` it would import `math` and `math/vector` instead. Inside that library, `@acme/math` and `@acme/math/vector` are self-imports using the same exports, whatever its consumers call it. A consumer does **not** get the library's `numeric` dependency. Every imported file uses its nearest config's maps, even when a parent package exports a file beneath another config boundary. `exports: './mod.ts'` is shorthand for `{'.': './mod.ts'}`. Exports are exact: no wildcard patterns, conditions, implicit index files, or private-subpath file fallback. Export targets begin with `./` and must stay inside the canonical package directory, including through symlinks. Config-relative paths use file-URL path semantics; queries, fragments, encoded separators, and NUL bytes are rejected. Relative file imports remain independent of the interface: exports are not a filesystem security sandbox. A dependency's `name` is optional unless it needs self-imports or is listed by path alone. Its exports must be nonempty, but a root `'.'` export is optional. Application configs need not have exports. Version and description are optional metadata; local versions do not select directories or constrain aliases. Two bindings may point to different versions/directories with identical declared names, or to the same directory. Canonical file identity determines whether they share a module instance. When a package's config loads, the configs of dependencies listed by path alone are read for their names; the root package's load happens at startup, before any guest code runs. These name reads are host configuration discovery: they ignore execution grants but keep the config trust checks above, and they grant no access to the dependency, whose modules and full config are only loaded, under normal checks, when a binding is selected. A missing or unnamed dependency config, or a name colliding with another binding, the package's own name, or a mapping, fails that package's load. Only declared dependency directories are inspected. A dependency must contain its own config; it cannot inherit an ancestor's interface. Header loading does not recursively build dependency maps, so cyclic package dependencies and cyclic source graphs are supported. Failed required-header reads or parses can be retried, provided ordinary ancestor discovery has not already snapshotted that directory's config as absent. Restart the loader to discover a new config in an already-snapshotted directory. No sibling scan, global workspace registry, or transitive flattening is performed. `jsr:` packages in `deps` bind and stay private in the same way; see [JSR packages](jsr.md). `npm:` packages do too; see [Npm packages](npm.md). Bare local bindings do not implicitly override `jsr:` requests, which remain registry-backed. `avril add` inserts `jsr:` or `npm:` packages into `deps`, or subpath aliases into `imports`, preserving metadata, comments, dependencies, scopes, and unrelated entries. A dependency entry already holding the same binding, local, `jsr:`, or `npm:`, is replaced. It rejects other collisions, such as with the package's own name or mappings, without replacing the config; it does not read dependency configs, so collisions with names declared by path-only dependencies are reported when the package loads. Declare local directory bindings in `deps` by hand. `info` and editor `graph.json` annotate local modules with their owning config, name, version, description, exports, and direct binding-to-directory or binding-to-`jsr:`-package metadata.