@forgezero/vault
v0.1.22
Published
ForgeZero vault client. Credential discovery and versioned secrets through one stable API origin.
Maintainers
Readme
Vault SDK
One scoped contract over platform-direct, managed-agent and external API-key trust paths.
Package overview
The scoped vault facade. A tenant application uses its local agent or an API key; trusted platform code injects a direct realm backend instead of calling itself. The one package that ends up in somebody else's production dependency tree, which is why it stays alone and stays small. Supported runtimes: bun, node, workers, deno. Package root: @forgezero/vault. Consumer documentation is curated with each module's explicit public flag; the complete internal/export inventory remains in the typed SSOT and declaration files.
bun add @forgezero/vaultForgeZero package family
The five packages are installation boundaries. Choose a package by who installs it; choose a subpath by the capability used in that file.
| package | short description | runtimes | documentation | |---|---|---|---| | @forgezero/vault | Scoped secret access with Agent, API-key and systemd-credential sources. | bun, node, workers, deno | Open | | @forgezero/access | Typed route, principal, factor, RBAC and request-pipeline contracts. | bun, node, workers, deno | Open | | @forgezero/providers | Typed external providers with priority, health and classified fallback. | bun, node, workers, deno | Open | | @forgezero/runtime | Portable runtime primitives for queries, jobs, events, schemas and finance. | bun, node | Open | | @forgezero/agent | Operator CLI and managed-node agent for bootstrap, deploy and lifecycle. | bun, node | Open |
@forgezero/vault supported imports and commands
These are supported consumer entry points, not every internal module shipped for ForgeZero managed installation. Each row links to its task-oriented usage.
| public entry | short description | runtime | details |
|---|---|---|---|
| @forgezero/vault | One scoped contract over an explicitly injected platform backend, a managed tenant socket or an automatically derived external API-key signer. | portable | Reference + usage |
| @forgezero/vault/schema | Where an entry’s shape comes from: pulled from the platform when ForgeZero has to render it, declared locally when only the tenant needs it. | portable | Reference + usage |
| @forgezero/vault/config | Read .fz/config.json — which project, which environment, which secrets, and what to call them. | portable | Reference + usage |
| @forgezero/vault/env | Envless: fill process.env from the vault at boot, refusing to run during a build. | portable | Reference + usage |
| @forgezero/vault/frameworks | SvelteKit and Next.js wiring, attached at the one place that runs once, on the server, before any request. | portable | Reference + usage |
| @forgezero/vault/providers | Adapters that make Vault a provider-configuration and credential source without coupling the providers package to ForgeZero. | portable | Reference + usage |
Commands
bun add @forgezero/vault — Install the scoped Vault client and its public subpaths.
bun add @forgezero/vault@forgezero/vault
One scoped contract over an explicitly injected platform backend, a managed tenant socket or an automatically derived external API-key signer. This is a supported entry point. Import only the named values used by the adjacent task example; the declaration file remains the complete API reference.
import {
DEFAULT_API_URL,
} from '@forgezero/vault';@forgezero/vault — Read a scoped secret
The same client discovers the managed Agent socket or uses an external API-key signer. Project and environment remain explicit.
import {
createVault,
} from '@forgezero/vault';
const vault = createVault({ project: 'payments', environment: 'production' });
const token = await vault.get('STRIPE_KEY');@forgezero/vault/schema
Where an entry’s shape comes from: pulled from the platform when ForgeZero has to render it, declared locally when only the tenant needs it. This is a supported entry point. Import only the named values used by the adjacent task example; the declaration file remains the complete API reference.
import {
localSchemas,
} from '@forgezero/vault/schema';@forgezero/vault/schema — Managed schema with a local fallback
Managed schemas let ForgeZero render and validate a provider form. Local schemas keep tenant-owned extensions independent. Managed wins when both define the same name; the version travels with the shape and no credential value is stored in the schema.
import {
managedSchemas,
localSchemas,
preferManaged,
} from '@forgezero/vault/schema';
import {
createVault,
} from '@forgezero/vault';
const vault = createVault({ project: 'payments', environment: 'production' });
const schemas = preferManaged(
managedSchemas(vault),
localSchemas({
postmark: { version: 1, schema: {
type: 'object', additionalProperties: false,
properties: { apiKey: { type: 'string', title: 'API key', writeOnly: true } },
required: ['apiKey']
} }
})
);
const { schema, version } = await schemas.get('postmark');@forgezero/vault/config
Read .fz/config.json — which project, which environment, which secrets, and what to call them. This is a supported entry point. Import only the named values used by the adjacent task example; the declaration file remains the complete API reference.
import {
CONFIG_PATHS,
} from '@forgezero/vault/config';@forgezero/vault/config — Use this entry point
This minimal executable use imports one concrete value from this exact entry point without a wildcard or package-root detour. Keep the value or values the application actually needs; the full named inventory remains directly above it.
import {
CONFIG_PATHS,
} from '@forgezero/vault/config';
export const selectedCapability = CONFIG_PATHS;@forgezero/vault/env
Envless: fill process.env from the vault at boot, refusing to run during a build. This is a supported entry point. Import only the named values used by the adjacent task example; the declaration file remains the complete API reference.
import {
EnvError,
} from '@forgezero/vault/env';@forgezero/vault/env — Use this entry point
This minimal executable use imports one concrete value from this exact entry point without a wildcard or package-root detour. Keep the value or values the application actually needs; the full named inventory remains directly above it.
import {
EnvError,
} from '@forgezero/vault/env';
export const selectedCapability = EnvError;@forgezero/vault/frameworks
SvelteKit and Next.js wiring, attached at the one place that runs once, on the server, before any request. This is a supported entry point. Import only the named values used by the adjacent task example; the declaration file remains the complete API reference.
import {
bootstrapEnv,
} from '@forgezero/vault/frameworks';@forgezero/vault/frameworks — Use this entry point
This minimal executable use imports one concrete value from this exact entry point without a wildcard or package-root detour. Keep the value or values the application actually needs; the full named inventory remains directly above it.
import {
bootstrapEnv,
} from '@forgezero/vault/frameworks';
export const selectedCapability = bootstrapEnv;@forgezero/vault/providers
Adapters that make Vault a provider-configuration and credential source without coupling the providers package to ForgeZero. This is a supported entry point. Import only the named values used by the adjacent task example; the declaration file remains the complete API reference.
import {
vaultConfig,
} from '@forgezero/vault/providers';@forgezero/vault/providers — Attach a versioned Git forge to Git Connect
One GitHub App provider is projected into separate OAuth Server and Git Connect method sets. Its shared credential source remains Vault-scoped and installation tokens are minted only when needed.
import {
createService,
} from '@forgezero/providers';
import {
defineGitHubProvider,
gitConnectService,
} from '@forgezero/providers/git';
import {
createVault,
} from '@forgezero/vault';
import {
vaultCredentials,
} from '@forgezero/vault/providers';
declare const githubAdapter: Parameters<typeof defineGitHubProvider>[0]['adapter'];
const vault = createVault({ project: 'control-plane', environment: 'production' });
const credentials = vaultCredentials(vault, 'github');
const github = defineGitHubProvider({ version: 'github-app:2026-03-10', adapter: githubAdapter });
const git = createService(gitConnectService, {
beginInstallation: [],
completeInstallation: [],
listInstallations: [],
listRepositories: [{ provider: github, method: 'listRepositories', version: 'github-app:2026-03-10', credentials, priority: 1 }],
listBranches: [],
mintCloneCredential: [],
verifyWebhook: [],
disconnectInstallation: []
});
const repositories = await git.call('listRepositories', { installationId: '42' });
if (!repositories.ok) throw repositories.error;Three paths, and why they stay explicit
Platform API logic already holds the requested realm master seed, so it opens the scoped envelope directly through an injected internal backend — no HTTP call, API key or local replica. A tenant on managed compute uses the local agent and its memory-only project scope. A tenant elsewhere signs HTTPS with an API-key seed. These share vault semantics and never silently fall through from a stronger posture to a weaker one.
PLATFORM API resident realm seed -> direct scoped envelope
MANAGED TENANT local unix socket -> agent RAM scope
EXTERNAL TENANT scoped API-key seed -> signed HTTPSCurrent implementation boundary
All three trust paths now have code: the platform opens its resident realm seed directly, an enrolled tenant agent derives its project binding and keeps every environment in that project in RAM, and createVault automatically uses either the local socket or a hybrid signer derived from an API-key seed. Live SEV-SNP report acquisition and an end-to-end production deployment are still gates; installation alone is not presented as proof.
1. Install
One ForgeZero identity dependency plus its required audited Noble crypto peers. The HTTPS path works anywhere fetch and Web Crypto exist; managed socket discovery requires a Bun or Node server runtime.
bun add @forgezero/vault2. Read a secret
The project and environment are explicit application scope. Managed compute uses the local Agent socket; external runtimes use the stable API origin and their scoped key.
import {
ForgeZero,
} from '@forgezero/vault';
const fz = new ForgeZero({ project: 'payments-api', environment: 'production' });
const value = await fz.get('PAYMENT_PROVIDER');
const names = await fz.list(); // names; HTTPS reads also carry metadata3. Ship it unchanged — target discovery
On managed tenant compute the Agent holds the node identity and the complete project RAM replica; the application holds no reusable remote credential and selects its environment in each client instance. The client finds the group-scoped socket instead of the environment variable. Outside managed compute it automatically derives the exact hybrid request signer from FORGEZERO_API_KEY.
new ForgeZero()
|- /run/forgezero/vault.sock exists -> MANAGED, app holds nothing
|- FORGEZERO_API_KEY present -> EXTERNAL, derive and sign locally
`- neither -> throws, naming BOTH remediesWhen both are present, the socket wins
On managed compute an API key in the environment is a leftover. Honouring it would silently downgrade a machine that holds nothing into one holding a signing seed, so discovery always prefers the stronger posture.
Rotation is human-authorised and application-observed
Writes stay on the authenticated platform surface with a human session, step-up proof and named audit actor. The application credential is read-only. External API-key reads may request a historical version; the managed RAM replica intentionally serves only the current value.
// after an authorised rotation in the platform UI
for await (const change of fz.watch()) {
console.log(change.name, change.version);
}getAll is managed-only, deliberately
One compromised API key should not hand over an entire environment in a single call, so a key holder gets list() plus reads by name. On managed compute there is no key to compromise, which is why the bulk read is allowed there and only there.
One stable API origin
The client always calls api.forgezero.net. Cloudflare owns routing and node health behind that name; the SDK never receives a node hostname, polls an assignment endpoint or replays a state-changing request against a different process.
410 421 502 503 504 530 -> ask for a different node, retry once
401 403 -> an answer, not a routing problemErrors you will actually hit
Each names what to do next.
NO_CREDENTIAL neither the socket nor FORGEZERO_API_KEY was found
VAULT_LOCKED the realm has no seed in memory; a custodian must unlock
MANAGED_ONLY getAll needs the agent socket
NO_NODE no vault node is currently availableAPI keys — the key is a seed, not a password
The SDK derives an Ed25519 + ML-DSA-65 keypair from it and signs every request, including a one-use hybrid ML-KEM-768 + X25519 response key. The API AES-256-GCM seals the result to that request before it crosses the edge. The seed itself is never transmitted, and ForgeZero stores only public halves.
fz.live.<keyId>.<seed> fz.test.<keyId>.<seed>Scope every key to one project and only the environments it needs
An API key is fixed to one project, optionally narrowed to named environments, and issued with exact route grants or project-owned API-key roles. Single-entry read, metadata listing and change following are the least-privilege default; bulk environment read and exact pipeline release are separate opt-ins.
project: payments
environments: production, staging
routes: read one, list metadata, follow changes
bulk read: explicit opt-in
pipeline release: explicit live-key roleControls, and what each is actually worth
Project, environment, exact route grants and revocation are real: status is read fresh on every call, so a revoked key stops working on the next request. API keys do not currently expire automatically; rotate or revoke them deliberately. An origin header is not treated as server authentication because any server-side caller can set it.
Vault read-only; release intent is the narrow machine write
The external Vault SDK has no secret write endpoint. A live API key may separately receive pipeline:release:create: it queues one full Git commit on an existing enabled pipeline, requires a stable idempotency key, and cannot edit a pipeline, target, secret or compute. Sandbox and legacy keys never inherit it, and the bound Agent still claims execution.
Full rendered documentation: https://www.forgezero.net/docs/vault-package
