Publishing
flog publish uses a prepare-then-execute model. It completes the full plan
before the first registry upload, so a manifest, lifecycle, packing, git, or
registry-state failure in any selected package leaves every package
unpublished.
Selection and order#
Without --recursive or --workspace, flog publishes the package containing
the selected directory. Private packages are rejected. --workspace selects by
exact package name, workspace directory, owned file, or workspace path glob;
--recursive separately selects every workspace. Exact and glob selectors
cannot be mixed, and duplicate aliases or overlapping globs are errors. Private
workspace packages matched by broad path globs or a plain recursive selection
are omitted with explicit package name, importer path, and private reason in
human and JSON plans and summaries. An exact workspace selector is a direct
request and remains an error. A broad selection containing only private
workspaces is also an error.
Selected packages are ordered dependency-first using the workspace graph. Versions already present in the registry are skipped only when their published integrity or shasum matches the newly prepared artifact. A mismatch is a hard error and flog never attempts to replace the version.
Preflight and lifecycle#
For every selected package, flog:
- validates every project dependency declaration against
flog.lock, then validates package identity, version, requested tag and access, git state, and workspace selection; - reads registry baselines, rejects an incoherent workspace release set, and reports newer compatible direct dependency versions as advisory warnings;
- runs
prepublishOnly; - packs the package, which runs
prepack,prepare, andpostpack, rewritesworkspace:ranges, and stages the exact tarball to upload; - validates the exact packed dependency declarations against the reviewed lock
after lifecycle changes and
workspace:rewriting; - revalidates the release set against post-lifecycle manifests; and
- displays the complete ordered plan.
Only after the complete plan succeeds and is confirmed does flog upload staged
artifacts sequentially. A successful upload runs publish and postpublish.
Artifacts are never rebuilt between the plan and upload.
A source or packed manifest/lock mismatch is always fatal, including dry-run,
and no force or acknowledgement option bypasses it. Lifecycle scripts therefore
cannot make an unreviewed dependency change eligible for upload. A newer
registry version that still satisfies a selected package's declared range is
different: the reviewed lock remains
authoritative, publication continues, and the deterministic warning reports the
locked and available versions with flog upgrade guidance. Exact declarations
and ranges with no newer compatible version produce no warning.
Workspace release sets#
Publication preflight computes a release closure from public workspace
dependencies. If a selected package crosses a compatibility line and a
published dependent's range excludes the proposed version, that dependent must
be included with its own compatibility-line bump. The check propagates through
transitive dependents. For SemVer, compatibility lines are a major version, a
minor version within 0.x, or an individual 0.0.x version.
Flog also rejects packed workspace dependencies whose ranges are not satisfied
by an existing registry version or an earlier package in the publication plan.
It never selects packages or edits versions automatically. Use
--allow-incomplete-release-set only to accept a reviewed exception; the
override and every affected edge remain in plans and summaries. --yes and git
overrides do not bypass release-set validation. Development-only workspace
edges are reported but do not require publication.
See workspace release sets for compatibility-line rules, dependency-chain examples, availability checks, and override behavior.
Immediately before every upload, flog reads that package's registry metadata
again. It aborts if the prepared version appeared, if latest changed, or if a
registry-reported access value changed after preflight. Registry baselines used
by release-set analysis are also checked before the first mutation and between
uploads. When an OTP challenge
occurs, the same check is repeated after the OTP is obtained and before the
authenticated retry. A mutating request that starts web authentication is not
automatically replayed; after authentication, flog rechecks metadata and
explicitly retries it. These checks narrow the stale-plan window, but
npm-compatible publication endpoints do not provide a portable conditional
update that atomically compares the old dist-tag or access while publishing a
version. A registry change in the final interval between this read and its
upload can therefore still race; flog does not claim race-free latest or
access safety.
Lifecycle scripts and packages run sequentially. Cancellation during a prompt, web login, OTP request, lifecycle script, or upload prevents subsequent uploads.
Tags and confirmation#
Stable versions default to latest. A prerelease requires an explicit
non-latest tag, for example:
flog publish --recursive --tag next
--tag latest is rejected for every prerelease. For stable versions, flog also
rejects a latest update whose SemVer precedence is lower than or equal to the
registry's current latest version. An equal version is accepted only as a
verified already-published resume.
Interactive publication asks for confirmation after displaying the plan.
Automation must deliberately pass --yes; redirected or otherwise
noninteractive input is never treated as confirmation.
Package access#
For a first publication, flog follows npm defaults: unscoped packages are
public, while scoped packages are restricted. Use an explicit access level
when the default is not the intended registry visibility:
flog publish --recursive --access public --tag next
One --access value applies to every selected package. public is valid for
mixed scoped and unscoped workspaces; restricted is rejected for any unscoped
package during initial validation, before lifecycle scripts or registry
requests. For an existing scoped package with no option, flog preserves a known
registry-reported public or restricted value. If the registry does not
report existing visibility, the plan says preserve and flog omits the access
field rather than risk requesting a downgrade to the scoped default.
The npm-compatible upload document carries the requested top-level access
field except for that preserve case. Requested access is included in every
plan entry, confirmation display, JSON summary, and summary file.
A successful upload response proves that a publication mutation was accepted;
it does not prove the registry applied the access field. After every accepted
upload, flog verifies the exact artifact through authenticated metadata and
checks whether that version is anonymously readable. It reports published
only when the observed public/restricted visibility matches the access intent.
An accepted upload with different visibility is
published-access-mismatch; unavailable verification or an unknown prior value
under preserve is published-access-unverified. Both outcomes return an
error, stop later workspace uploads, record access intent and observed access
separately, and warn that the accepted publication may be irreversible.
publish and postpublish still run because the registry accepted the package.
If a registry rejects the field, flog reports the ordinary failed upload. If it accepts but ignores the field, flog never silently substitutes visibility or reports confirmed success. Dry runs show the access intent but remain anonymous and never mutate package visibility.
Dry runs, git checks, and summaries#
--dry-run performs lifecycle, packing, registry-state, and safety checks but
does not upload or authenticate. Metadata requests omit configured and session
credentials and cannot start web authentication.
By default the worktree must be clean and the current branch must be main or
master. --allow-dirty and --allow-branch override those checks
individually. --no-git-checks disables both. Every active override is shown as
a warning in the plan.
--json writes a machine-readable package summary to stdout. The plan is
written to stderr first so it remains visible before mutation. Use
--summary <file> to atomically record the same summary in a JSON file,
including failed, published-access-mismatch,
published-access-unverified, and not-attempted package statuses after a
partial or unverifiable publication. A rerun rebuilds and revalidates
already-present versions before continuing.
If a registry requests a one-time password, interactive use prompts for one.
Automation may provide NPM_CONFIG_OTP in its environment.