← All @molecule/* packages · App templates
@molecule/api-project-archive-external-state-d1Provider bond · project-archive-external-state · API (Node) · v1.0.2 · Apache-2.0
Captures and restores a project's Cloudflare D1 databases via wrangler, so archiving a Workers project does not silently drop its data.
npm install @molecule/api-project-archive-external-state-d1npm · Source on GitHub · Implements @molecule/api-project-archive
@molecule/api-project-archive-external-state-d1 is a provider bond on the API (Node) side: it implements the project-archive-external-state core interface (@molecule/api-project-archive) with a concrete vendor or library behind it.
Your code calls the core; you wire this provider once at startup. Swapping vendors later is one line in that wiring, not a rewrite.
import { setExternalStateProvider } from '@molecule/api-project-archive'
import { createD1ExternalStateProvider } from '@molecule/api-project-archive-external-state-d1'
setExternalStateProvider(
createD1ExternalStateProvider({
// A DECLARATION of what the project owns — never a lookup.
databaseNames: (projectId) => [`mol_${projectId}`],
}),
)Works with: @molecule/api-project-archive
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
@molecule/api-project-archive-external-state-d1 — captures and restores a
project's Cloudflare D1 databases so archiving a Workers project does not
silently drop its data.
@molecule/api-project-archive destroys the original once result.verified
is true. State whose provider was never written is captured by nobody,
verifies clean, and is then permanently deleted — so every state-owning
provider bond needs one of these. This is D1's.
Capture shells out to wrangler d1 export, for the same reason the Postgres
bond shells out to pg_dump: only the engine that owns the data can produce a
consistent snapshot with schema, indexes and constraints intact.
import { setExternalStateProvider } from '@molecule/api-project-archive'
import { createD1ExternalStateProvider } from '@molecule/api-project-archive-external-state-d1'
setExternalStateProvider(
createD1ExternalStateProvider({
// A DECLARATION of what the project owns — never a lookup.
databaseNames: (projectId) => [`mol_${projectId}`],
}),
)
provider
npm install @molecule/api-project-archive-external-state-d1 @molecule/api-project-archive
D1ExternalStateConfigHow this deployment finds a project's D1 databases.
interface D1ExternalStateConfig {
/**
* The D1 database NAMES belonging to `projectId`, as `wrangler` knows them.
*
* **This is a DECLARATION, not a search.** An empty array means the project
* genuinely owns none — and it is the ONLY way to say that. Asking Cloudflare
* "which databases does this project have?" cannot distinguish "none" from
* "this API token cannot see them", and the caller DESTROYS the project on a
* successful capture, so an inferred absence deletes live data. A name that is
* listed but does not exist is an ERROR, never an absence.
*
* @param projectId - The project being archived or restored.
* @returns Its D1 database names; `[]` when it owns none.
*/
databaseNames: (projectId: string) => readonly string[] | Promise<readonly string[]>
/**
* The `wrangler` executable. Defaults to `wrangler`.
*
* Capture needs D1's own tooling for the same reason `pg_dump` cannot dump
* MySQL: the export has to come from the engine that owns the data.
*/
wranglerPath?: string
/**
* Extra arguments appended to every `wrangler` invocation — typically
* `['--config', 'wrangler.toml']` or an account selector.
*
* Credentials are NOT passed here. `wrangler` reads `CLOUDFLARE_API_TOKEN` /
* `CLOUDFLARE_ACCOUNT_ID` from the environment, and a token in argv is visible
* in `ps` to every user on the host.
*/
wranglerArgs?: readonly string[]
/**
* Operate on the deployed (remote) database rather than the local emulator.
* Defaults to `true`.
*
* The default is deliberate: `wrangler d1 export` without `--remote` dumps the
* LOCAL miniflare database, which in production is empty. Defaulting to local
* would produce a clean, successful, zero-row capture — and then the caller
* would destroy the real one.
*/
remote?: boolean
}
createD1ExternalStateProvider(config)Create the provider.
function createD1ExternalStateProvider(config: D1ExternalStateConfig): ProjectExternalStateProvider
config — How to find a project's D1 databases.Returns: A provider ready to bond with setExternalStateProvider.
KINDRecorded on every record this provider produces; routes restores back here.
const KIND: 'd1'
Implements @molecule/api-project-archive interface.
Peer dependencies:
@molecule/api-project-archive ^1.0.1@molecule/api-project-archive
databaseNames declares; it must never search. Asking Cloudflare which
databases a project has cannot distinguish "none" from "this token cannot
see them", and the caller destroys the project on a successful capture. An
empty array is the only way to say "owns nothing"; a listed name that does
not exist is an error.
remote defaults to true, deliberately. wrangler d1 export without
--remote dumps the LOCAL miniflare database, which in production is empty.
Defaulting to local would yield a clean, successful, zero-row capture — and
then the caller would destroy the real database.
A zero-byte export is treated as a failure, not an empty database.
d1 export always emits at least schema statements, so zero bytes means the
export did not happen (wrong name, wrong account, silent auth failure).
Credentials come from the environment, never argv. wrangler reads
CLOUDFLARE_API_TOKEN / CLOUDFLARE_ACCOUNT_ID; a token in argv is visible
in ps to every user on the host. wranglerArgs is for --config and
similar, not secrets.