EXTENSION DEPENDENCIES
swamp extension push accepts dependencies written the way Deno and Node
projects usually write them, and ships every one of them in a single form: each
npm: and jsr: import pinned to the exact version the bundle holds. The
registry audits that form as written, and consumers run the bundle built from
it. swamp extension quality resolves dependencies exactly as push does.
Supported inputs
The categories below are supported. If a future Swamp release changes how it resolves dependencies, a category it can no longer support gets a dated deprecation, announced in advance. Archives already published keep working, because their source names every dependency exactly.
Accepted
| Input | Ships as | Dependency trust |
|---|---|---|
Exact npm: or jsr: import, such as npm:ms@2.1.3 |
as written | audited |
| Range or npm dist-tag, with a lock | the locked version, exact | audited |
| Range or npm dist-tag, no lock | the version resolved at push, exact | audited; push warns, and it costs 1 of 2 points (lock rule) |
Unpinned npm: or jsr: import, where the project's deno.json excludes the no-unversioned-import lint rule |
as a range, above | as a range, above |
Bare import through deno.json or deno.jsonc imports, an importMap file, or scopes |
the target Deno resolves for each importing module, exact | as its target |
| Workspace member | exact, bundled against the workspace root's lock | as its target |
package.json with npm registry dependencies installed in node_modules |
npm:<name>@<installed version>, one per installed copy |
audited per copy; lock rule |
deno.json beside package.json |
the installed version, exact; deno.json decides |
lock rule; only deno.lock counts |
package.json file:, link:, workspace: or git dependency |
the bare name, as written; the bundle holds the code | not audited: 0 of 2 points |
URL import, such as https://deno.land/std@0.224.0/fmt/colors.ts |
as written; the bundle holds the code | not audited: 0 of 2 points |
| Relative import inside the repository or extensions root | relative; a module more than one level above its kind directory moves under _shared/ |
— |
node: builtin |
as written | — |
npm:zod, any version |
as written; a bare zod 4 import ships as npm:zod@4 |
provided by Swamp, never audited, no cost |
Refused
| Input | Why | Fix |
|---|---|---|
@=1.2.3 or @v1.2.3 |
Deno cannot bundle these spellings | write @1.2.3 |
Unpinned npm: or jsr: import, such as npm:ms |
the no-unversioned-import lint rule fails it |
name a version or a range |
JSR dist-tag, such as jsr:@std/assert@latest |
JSR has no dist-tags | name a version or a range |
A deno.json, package.json or node_modules above the repository that an import needs |
it would shape the push from outside the repository | add a deno.json or package.json inside the repository, or write the specifier in full |
| A workspace root above the repository | its imports and lock would apply from outside the repository | move the workspace root inside the repository, or push from its own repository |
| Relative import outside the repository and extensions root | push cannot include the module in the archive | move the module inside the repository |
Dynamic import() |
the bundler cannot follow it | use a static top-level import |
| Anything Deno cannot resolve | Deno's error names the import | fix the import Deno names |
The shipped form
An archive push writes satisfies all of these:
- Every
npm:andjsr:import isnpm:<name>@<x.y.z>[/subpath]orjsr:@<scope>/<name>@<x.y.z>[/subpath], where the version is the one the bundle holds. Plain semver only: no^,~,=,v, dist-tag or missing version.npm:zodis the one exception; see zod. - Every other import is relative to a file inside the archive,
node:, or code from outside npm and JSR, which ships as written. extension/dependency-audit.jsonis arecordVersion: 2record listing each shippednpm:andjsr:package version, the code from outside npm and JSR, and a SHA-256 of each bundle. See Publishing Commands § Dependency audit record.- The archive carries no project configuration: no
deno.json,deno.jsonc,deno.lock,package.json,package-lock.json,.npmrcornode_modules, unless a module imports one of them as data.
A written range with a lock at 2.1.3 ships as the exact version:
// dep.ts, as written
import ms from "npm:ms@^2";
// dep.ts, as shipped
import ms from "npm:ms@2.1.3";A config, lock or package file listed in additionalFiles or reached through
include is left out of the archive, with the archive-project-file warning:
deno.json is a Deno config, lock or package file, so push leaves it out of the archive: the archive's source ships every dependency pinned instead.A kind directory ships only the modules its entry points import, so a config file there that no module imports is never packaged.
The lock rule
Pin exact versions or commit a lock. A non-exact specifier (a range, an npm dist-tag, or no version where the lint rule allows it) costs one of the two dependency-trust points only when no valid lock resolved it. Exact pins and a lock score the same; a lock is the stronger choice, because it also fixes the transitive versions the bundle holds.
| Lock | Counts when |
|---|---|
deno.lock of the project's deno.json |
always; push bundles with --frozen, so a stale lock fails the push |
deno.lock of a workspace |
the workspace root's; a member's own lock is ignored, with a workspace-member-lock warning |
deno.lock in a package.json project |
always, as above |
package-lock.json |
only with no deno.json, and only when node_modules matches it, transitive packages included; otherwise push warns with package-lock-mismatch and treats it as no lock |
A project with neither a deno.json nor a package.json bundles with
--no-lock, so no lock applies. Push never writes a lock.
A non-exact specifier no lock resolved is warned about at push, and the warning names the version that ships:
"ms": "no lock: ^2 resolved to 2.1.3 today; commit a lock or pin exact versions (costs 1 point)"The record keeps the spelling the author wrote (writtenAs) and whether a lock
fixed it (locked), so the registry scores the same rule. See
Scorecard Rubric § At push
for which lockfile a project reads.
Code from outside npm and JSR
A URL import, and a package.json dependency on a git repository or a local
path (file:, link:, workspace:, portal: or a path), is bundled and
ships, but no registry audit covers it. Push lists it under unaudited in the
record with its origin and a SHA-256 of each module the bundle holds, warns, and
the dependency-trust factor scores 0 of 2:
"https://deno.land/std@0.224.0/fmt/colors.ts": "not audited: https://deno.land/std@0.224.0/fmt/colors.ts is a URL import, from outside npm and JSR, so no registry audit covers it"To earn the points back, import the code as an npm: or jsr: package, or move
it into the repository and import it relatively.
zod
Swamp provides zod to every extension and decides its version, so a zod import
is never pinned, listed in the record or audited, and costs nothing. A zod 4
import is left to the host: a bare zod that the project maps to zod 4 ships as
npm:zod@4. A zod 3 import is bundled into the extension.
Nothing from above the repository
Push resolves dependencies from inside the repository only, and passes
--no-config so Deno does not read a config above it. When that config would
have resolved an import, push refuses and names it:
Push found /home/me/deno.json above /home/me/work/repo. Deno would use it to resolve "ms", but it is outside the repository, so push ignores it (--no-config). Add a deno.json inside the repository that maps the import, or write the specifier in full.A package.json above the repository is refused the same way. A workspace root
above the repository is refused because its imports and lock would apply, and a
package found in a node_modules above the repository is refused because no
file in the repository declares it. A config above the repository that resolves
nothing is ignored.
What consumers run
swamp extension pull, swamp extension update, auto-resolve on first use, and
swamp extension install keep the bundle the publisher built. Before
installing, pull checks each bundle against the SHA-256 the record lists; a
mismatch aborts the install:
Extension bundles do not match the archive's dependency audit record. Install aborted.A consumer rebuilds from the archive's source, with --no-config, only when the
archive holds no bundle for a source, its bundleFormat is one the running
Swamp does not run, or a kept bundle fails to load. The rebuild fetches the
exact versions the source names, the ones the registry audited. Workers build
their own bundle from the same source, with zod included.