ext-*
packages; dependency-free core code exposes only the provider-neutral contract
and must not import or auto-load the extension.
Use Extensions when you only need to enable an existing
extension.
Prerequisites
- A Veryfront project that imports
veryfront/extensions. - A concrete capability gap to fill.
denoavailable on your PATH.
Scaffold an extension
ext- directory
prefix. The capability and contract audit tasks only check extension directories
with that prefix. Local downstream extensions do not need it.
Write the factory
Provide a contract
Useprovides when the implementation does not need async setup:
setup(ctx) when the implementation opens resources or registers contracts
after async initialization. Declare every dynamically registered contract in
contracts.provides; setup fails closed if it publishes an undeclared contract.
contracts or the legacy static provides object, never both.
Each contracts.provides or contracts.requires list is a dense array of at
most 256 unique names. Contract names are limited to 256 characters and must be
trimmed, well-formed, single-line Unicode. Veryfront snapshots this metadata
before replacing the active extension generation.
Declare capabilities
Capabilities document runtime needs. Use a recognizedtype and matching scope
field so Veryfront can map the capability to a Deno permission flag and audit it
in CI.
Omitting a supported scope field explicitly requests the corresponding
unscoped Deno permission, except that
system:read always requires a non-empty
apis array and never emits bare --allow-sys. If you provide another scope
field, it must be a non-empty array of trimmed strings. Scope values cannot
contain commas or control
characters, including Unicode C1 controls and line separators, because Deno
uses commas to separate permissions and these characters make command and
audit boundaries ambiguous. Scope strings must contain well-formed Unicode;
the same rule applies to every capability metadata key and string so audit
records remain single-line and unambiguous. Audit output JSON-quotes capability
types and field names. Raw capability text is limited to 32,768 UTF-8 bytes and
UTF-16 code units, and its rendered audit output to 49,152 of each. Veryfront
does not normalize filesystem paths. The combined serialized Deno permission
flags for one extension are limited to 8,192 UTF-8 bytes and 8,192 UTF-16 code
units so an accepted declaration remains launchable across supported operating
systems. For net:listen, host is valid only together with a non-empty
ports array.
Veryfront rejects unknown fields on recognized capability types so a typo such
as path instead of paths cannot silently broaden access.
System API scopes must use a Deno.SysPermissionDescriptor.kind supported by
the pinned Deno 2.7.7 runtime: loadavg, hostname, systemMemoryInfo,
networkInterfaces, osRelease, osUptime, uid, gid, username, cpus,
homedir, statfs, or getPriority. The system:read capability rejects
setPriority because that API changes process scheduling state.
Network scopes accept ASCII DNS names (including a leading *. wildcard),
canonical IPv4 addresses, and bracketed IPv6 addresses, with an optional port
for net:outbound. A sole outbound host of "*" explicitly requests an
unscoped --allow-net flag; it cannot be combined with narrower hosts. In Deno,
*.example.com grants both subdomains and the apex example.com; use explicit
hosts when apex access is not intended. Deno’s single --allow-net permission
covers both outbound connections and listeners, so net:outbound versus
net:listen is auditable intent, not process-level directional isolation.
Capability declarations are metadata, not an in-process sandbox. An extension
loaded into the Veryfront process inherits that process’s permissions.
mapToDenoPermissions() only serializes Deno flags; a subprocess launcher must
apply those flags for Deno to enforce them. Use a separate process plus a
container or operating-system policy when directional or stronger isolation is
required.
For first-party extensions, mirror the same capabilities array in deno.json
under veryfront.capabilities.
Understand load order
Veryfront loads extensions in this order:setup() runs in sorted order. teardown()
runs in reverse order during shutdown or reload.
Use presets to group extensions that load together:
veryfront.config.ts trigger teardown,
rediscovery, and setup. Release resources in teardown() so reloads do not leak
connections, timers, or file handles.
Test the extension
Test the factory first:Package the extension
Package an extension only when it needs reuse across projects.- Export the extension factory as the default export.
- Set
veryfront.extension: trueindeno.json,deno.jsonc, orpackage.json. - Set
veryfront.activationto"auto"or"explicit". - Declare capabilities in package metadata and in the factory.
- Declare contract metadata through
contractsor staticprovides. - Include tests for the factory and contract implementation.
- Publish to npm or JSR.
"auto" only when importing and setting up the package is safe merely
because it is installed. Use "explicit" for credentialed, native, or
side-effecting providers; Veryfront then ignores the installed package until
the project imports its factory and adds the resulting extension to
veryfront.config.ts. Omitting activation retains the legacy "auto"
behavior. Unknown or malformed activation metadata fails closed.
Use semver for releases. Treat contract shape changes as breaking changes.
Verify it worked
- Run
veryfront extension validate extensions/my-cache. - Run
deno test --no-check --allow-all extensions/my-cache/src/. - Add the factory to
veryfront.config.tsand restartveryfront dev. - Confirm the dev log lists the extension under its declared name.
- Resolve the contract from app code and confirm it uses the extension’s implementation.
Next
- Extensions: Enable an extension in a project
Related
- veryfront/extensions: Extension APIs
- veryfront/testing: Testing helpers