Changelog
Every published CapsuleDB release, newest first, with its breaking changes and the Effect and SQL driver versions it requires.
capsuledb@0.6.0
Effect 4.1.2 and Alchemy beta.85
Breaking: CapsuleDB now requires Effect >=4.1.2 <5; Effect 4.0 is no longer supported.
Checksums use Digest from effect/crypto, with WebCrypto when the caller does not provide a Digest service. Existing canonical bytes and SHA-256 checksums are unchanged. Development and provider tests now use Effect SQL 4.1.2 and Alchemy 2.0.0-beta.85. Optional SQL and Alchemy peer ranges remain unchanged.
capsuledb@0.5.1
Dependency refresh
CapsuleDB 0.5.1 is verified against Effect 4.0.2 and the Effect SQL 4.0.2 drivers, Alchemy 2.0.0-beta.81, @libsql/client 0.18, and current Cloudflare D1 tooling. There are no API changes, and peer dependency ranges are unchanged.
capsuledb@0.5.0
Stable Effect 4
Breaking: CapsuleDB now requires stable Effect 4 (>=4.0.0 <5) and stable Effect SQL
drivers with the same version range. Update your application’s Effect and SQL
driver dependencies together before upgrading; Effect 4 release candidates are
no longer supported. SQL imports use effect/sql/* and CLI imports use
effect/cli.
The optional capsuledb/alchemy integration now requires Alchemy
>=2.0.0-beta.80 <3 and @effect/sql-pg >=4.0.0 <5. Alchemy beta80 supports
stable Effect module paths, so deploy-time PostgreSQL registry preparation works
with the stable dependencies. CapsuleDB’s public entrypoints remain available.
capsuledb@0.4.0
A current registry answers in one round trip
Registry.prepare, Registry.assert, and Registry.status read readiness metadata and the whole
ledger in one statement. When the recorded fingerprint matches and the ledger is complete,
prepare returns Ready from that read alone: no transaction, no PostgreSQL advisory lock, and no
CREATE TABLE IF NOT EXISTS. Anything else — missing tables, a new migration, a ledger that still
needs re-keying — takes the locked preparation path unchanged. Inside a caller’s transaction the
read runs under a savepoint, so an empty PostgreSQL database cannot abort that transaction.
Check readiness on first use
Registry.layer({ ..., readiness: "first-use" }) builds without a single statement. Capsules
receive the host SqlClient wrapped so their first connection, reservation, or transaction runs the
mode check (prepare or assert) once; concurrent first uses share it, a success is kept for the
Layer’s lifetime, and a failure reaches the capsule’s query as a SqlError whose cause is the
registry error and runs again on the next use. Driver-specific members such as D1’s batch stay on
the wrapped client and are gated the same way. Composition errors still fail the build. The default,
readiness: "boot", checks while the Layer is built, as before.
Prepare from a manifest
Registry.prepare, Registry.assert, and Registry.status also take
{ provider, manifest, prefix?, allowDestructive?, allowLegacyLedgerUpgrade? }, so a deploy tool
can prepare a database from the serialized output of Registry.manifest without loading capsule
code. The manifest’s structure, body checksums, and fingerprint are verified before the database is
touched, and its SQL bodies for the provider’s dialect are what gets applied. A migration with an
Effect step fails with InvalidDefinition, as emit does. The ledger and metadata are written
exactly as capsule preparation writes them, so either path reads the other’s database as Ready.
capsuledb/alchemy: prepare the registry at deploy time
The new capsuledb/alchemy subpath exports a CapsuleDB.Registry Alchemy resource and its
providers() collection. Given a PostgreSQL connection url, provider: "Postgres", and the
registry manifest, reconcile prepares the database from the manifest and outputs its
fingerprint, ledger provider, capsule count, and prefix. Diff updates only when the URL,
provider, prefix, authorizations, or manifest fingerprint change; an unchanged or already-prepared
database reconciles with a single read, and delete keeps every table. alchemy (>=2.0.0-beta.79 <3) and @effect/sql-pg (>=4.0.0-rc.117 <5) are optional peer dependencies used only by this
subpath; the package root never imports them.
capsuledb@0.3.0
Effect 4.0.0-rc.117
CapsuleDB builds against Effect 4.0.0-rc.117, and the effect, @effect/sql-libsql, and
@effect/sql-sqlite-bun peer ranges are now >=4.0.0-rc.117 <5. Effect renamed the CLI flag
constructors to Flag.Boolean and Flag.String, and 0.2.0’s capsuledb bin calls the old
lowercase names at import, so every subcommand crashes under Effect rc.113 or newer. A host on a
newer Effect needs this release, and a host on an older one upgrades Effect with it.
capsuledb@0.2.0
Deterministic manifests, optional D1 artifacts, and provider-stamped readiness
The manifest is deterministic, the static D1 artifact tooling is optional, and capsule authors and host operators each get their own documentation. Registry readiness fails closed when an active migration ledger row was stamped by a different provider.
Declare tables once and render the DDL per dialect
Schema.table plus the column constructors describe a capsule’s tables, and
Migration.createTable, addColumn, createIndex, and dropTable render them
deterministically for PostgreSQL and SQLite — the dialect that covers Bun SQLite,
libSQL, and Cloudflare D1. Migration.sql stays the escape hatch for
engine-specific statements and Migration.effect for work that needs the host
client; one migration may mix all three. capsule.tables exposes the
declaration, and Schema.Row infers the row type from it.
Breaking: a migration takes steps, not a providers map keyed by provider or
dialect tag, and bodies are keyed by dialect (postgres / sqlite) only.
Provider and Dialect are string unions rather than tagged unions, and
ProviderProfile.execution is gone because capabilities._tag already names the
execution model. The manifest records per-dialect bodies in place of
providers. The built-in D1 profile now allows 16 statements per atomic batch
instead of 2; Cloudflare publishes no batch statement-count limit, and one
declared table with indexes needs more than one slot.
Make capsule definitions pure values and boot every capsule from one Layer
Capsule.make and Migration.make now return the value and throw
CapsuleDefinitionError on an invalid definition, so a capsule is a module
constant instead of an Effect a host has to run first. Registry.layer(options)
prepares pending migrations and then provides every registered capsule’s
service with its merged service, failure, and requirement types.
Breaking: the root export is namespace-only (Capsule, Migration, Registry,
…); makeCapsule, makeMigration, sqlMigrationBody, effectMigrationBody,
makeRegistry, describe, migrationsOf, and assertRegistryReady are gone.
RegistryPlanState, Readiness, and ReadinessReceipt collapse into one
Readiness union of Ready, Pending, and Drift.
Emit capsule SQL into a host’s migration folder and assert readiness at boot
capsuledb emit --module --export --dialect postgres|sqlite --out <dir> writes
the ledger DDL, one file per migration with its ledger row, and the readiness
metadata row. capsuledb check verifies that folder still matches the installed
library. Registry.layer({ mode: "assert" }) then applies nothing and fails with
NotReady unless the database already matches the registered history.
Files are numbered by CapsuleDB’s own migration order rather than by wall clock,
so the projection is byte-for-byte reproducible and check can compare it
directly. --provider stamps a non-default SQLite provider identity and
--prefix matches a prefixed registry.
Checksum only the dialect body the host applies
Manifest v2 gives every dialect body its own checksum, and the ledger records
which dialect a row’s checksum is keyed to. Adding a SQLite body to a capsule
already deployed on PostgreSQL, or fixing another engine’s SQL, no longer
invalidates a deployed host’s ledger. MigrationChecksumDrift and
LedgerConflict name the dialect that drifted.
A ledger written by CapsuleDB 0.1 is upgraded in place on the first v2
preparation: the runtime adds the dialect column and re-keys each row to the
body this host applies. It still fails closed when a row’s capsule, migration ID,
or name no longer matches the registered history.
Prune the export surface and ship a conformance kit
capsuledb/Testing exports the provider-neutral conformance suite this
repository runs against every provider, plus a withSqlite helper that opens a
throwaway in-memory database, so a capsule author gets a first signal without
testcontainers. Registry.layer and friends accept a prefix so two
independent registries can share one database.
Breaking: TokenNotFound, TokenAlreadyConsumed, and InvalidToken were
example-only errors and now live in the reference example rather than the
library’s CapsuleError union.
bun run docs:check now verifies that every capsuledb subpath and symbol a
documentation snippet names still exists, and tests/artifact asserts the packed
root surface is exactly one namespace per exported subpath.
capsuledb@0.1.0
The first capsule
The first public release of CapsuleDB, providing Effect-native database capsules, append-only migrations, and transactional PostgreSQL, Bun SQLite, and libSQL provider support.