@molecule/api-database-d1
v1.0.3
Published
Database provider for Cloudflare D1 — SQLite on Workers, reusing the SQLite dialect with a D1-backed pool instead of a native driver.
Readme
@molecule/api-database-d1
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-database-d1 — a @molecule/api-database provider for
Cloudflare D1, so a molecule API can run on Workers with no Postgres.
D1 is SQLite, so this bond reuses @molecule/api-database-sqlite's dialect
(query building, placeholder conversion, id generation) verbatim and replaces
only the pool: better-sqlite3 is a synchronous native binding, D1 is an
async platform binding. The native driver is never imported, which is what
lets this run in a Workers isolate at all.
Quick Start
import { setStore } from '@molecule/api-database'
import { createProvider, type D1DatabaseLike } from '@molecule/api-database-d1'
// Worker bindings arrive per-invocation on `env`; they are not in module
// scope and not in process.env, so setupBonds() takes `env` on Workers.
// (Here `env` stands in for the real `scheduled(event, env, ctx)` argument.)
const env = { DB: {} as D1DatabaseLike }
setStore(createProvider({ database: env.DB }))
// wrangler.toml:
// [[d1_databases]]
// binding = "DB"
// database_name = "my-app"
// database_id = "<id>"Type
provider
Installation
npm install @molecule/api-database-d1 @molecule/api-database @molecule/api-database-sqliteAPI
Interfaces
D1Config
Configuration for the D1 provider.
interface D1Config {
/**
* The D1 binding from the Worker's `env` (for example `env.DB`).
*
* REQUIRED and passed in explicitly: a Worker's bindings arrive per-invocation
* on `env` and are not readable from the module scope or from `process.env`,
* so there is nothing for this bond to discover. Being told is the only
* correct option, and a discovery mechanism here could only ever guess wrong.
*/
database: D1DatabaseLike
}D1DatabaseLike
The subset of Cloudflare's D1Database binding this bond uses.
interface D1DatabaseLike {
/** Prepares a SQL statement. */
prepare(query: string): D1PreparedStatementLike
/** Runs a set of prepared statements as one batch. */
batch?<T = Record<string, unknown>>(
statements: D1PreparedStatementLike[],
): Promise<{ results: T[] }[]>
}D1PreparedStatementLike
The subset of Cloudflare's D1PreparedStatement this bond uses.
Declared structurally rather than imported from @cloudflare/workers-types
so the package carries no dependency on the Workers type package — a consumer
that already has those types passes its real binding and it type-checks, and
a consumer that does not can still build.
interface D1PreparedStatementLike {
/** Binds ordinal parameters, returning a bound statement. */
bind(...values: unknown[]): D1PreparedStatementLike
/** Runs the statement and returns all result rows plus metadata. */
all<T = Record<string, unknown>>(): Promise<{
results: T[]
meta?: { changes?: number; last_row_id?: number | string }
}>
/** Runs the statement for its side effects. */
run(): Promise<{
results?: unknown[]
meta?: { changes?: number; last_row_id?: number | string }
}>
}Functions
createDatabasePool(config)
Creates the D1 pool on its own, for callers that want raw SQL access alongside the DataStore.
function createDatabasePool(config: D1Config): DatabasePoolconfig— The D1 binding from the Worker'senv.
Returns: A DatabasePool backed by D1.
createPool(config)
Creates a DatabasePool over a Cloudflare D1 binding.
function createPool(config: D1Config): DatabasePoolconfig— The D1 binding to use.
Returns: A pool the shared SQLite store can run against.
createProvider(config)
Creates a D1-backed DataStore.
The store is @molecule/api-database-sqlite's, unchanged: D1 speaks SQLite,
so the dialect is shared and only the pool differs. That is why this bond is
small — the sqlite store was already written against the abstract
DatabasePool rather than against its native driver.
function createProvider(config: D1Config): DataStoreconfig— The D1 binding from the Worker'senv.
Returns: A DataStore backed by D1.
Core Interface
Implements @molecule/api-database interface.
Injection Notes
Requirements
Peer dependencies:
@molecule/api-database^1.0.1
Runtime Dependencies
@molecule/api-database@molecule/api-database-sqliteThe binding must be PASSED IN; it cannot be discovered. A Worker's bindings arrive per-invocation on
env— they are not in the module scope and not inprocess.env. SosetupBonds()takesenvon Workers, and the provider is constructed per invocation rather than once at import time.There are no interactive transactions, and this bond does not fake one.
pool.transactionisundefinedrather than a no-op that reports success for a rollback which never happened. D1 offersbatch()— one atomic set of statements decided up front — which is a different shape, not a drop-in. Checktypeof pool.transaction === 'function'before relying on it.Migrations do not run through this bond.
@molecule/api-database-sqlite's migrator reads the filesystem and opens the native driver, neither of which exists on Workers. Apply schema withwrangler d1 migrations applyfrom CI or a local shell, the same way you would run any other out-of-band migration.D1 rows come back as plain JSON values. There is no per-column type metadata the way
better-sqlite3exposes it, so a column's declared type cannot be used to re-hydrate values; store dates as ISO strings and booleans as 0/1, which is what the shared SQLite dialect already writes.
