# Bun-SQLite & D1 Store adapters

inseam's two first-party `StoreAdapter` implementations: `@inseam/adapter-store-bun-sqlite` (embedded SQLite via `bun:sqlite`, Bun-runtime-only) and `@inseam/adapter-store-d1` (Cloudflare D1, async-only, Worker-supplied binding). Pick whichever matches the host. They share a parameterized conformance harness shipped from `@inseam/store-contract/testing`.

**See also:** [design](../design/bun-d1-sqlite-adapters.md) · [spec](../spec/bun-d1-sqlite-adapters.md)

## What it does

Each adapter wraps one driver as a `StoreAdapter` (the [Store port](./store.md)'s adapter surface). Both:

- Throw only `AdapterError` (with `cause` and `adapterKind`); higher-level error types are core's concern.
- Implement `batch` as a real atomic unit — a SQLite transaction for bun-sqlite, `db.batch(...)` for D1.
- Resolve `batch([])` to `[]` without touching the driver and `health()` to `false` (never throws) on a broken connection.

Adapter-specific:

- **`bunSqliteAdapter(path)`** opens or creates a SQLite database at `path` (or `":memory:"`). Applies WAL, `foreign_keys=ON`, and a fixed `busy_timeout` at construction. Sync driver wrapped to async. `kind: "bun-sqlite"`.
- **`d1Adapter(db)`** captures a Worker-injected `D1Database` binding and performs no driver work at construction. Normalizes D1's `success: false` envelopes into thrown `AdapterError`s; on batch failure, attaches `batchIndex` (from D1 when available, else `0`) to the wrapped error. `kind: "d1"`.

## How to use it

A Bun-compiled host:

```ts
import { openStore } from "@inseam/core";
import { bunSqliteAdapter } from "@inseam/adapter-store-bun-sqlite";

const store = await openStore(bunSqliteAdapter("./inseam.sqlite"));
```

A Cloudflare Worker:

```ts
import { openStore } from "@inseam/core";
import { d1Adapter } from "@inseam/adapter-store-d1";

export default {
  async fetch(_req: Request, env: { DB: D1Database }) {
    const store = await openStore(d1Adapter(env.DB));
    // ...
  },
};
```

Full factory and method contracts: [spec — Public API](../spec/bun-d1-sqlite-adapters.md#public-api).

## How to extend it

A new backend is a sibling package depending only on `@inseam/store-contract` and its driver — never on `@inseam/core` or another adapter. First-party adapters live at `pkgs/adapter-store-<backend>/`; third-party adapters publish as `inseam-adapter-store-<backend>`.

The minimum:

1. Implement `StoreAdapter` (see the [Store doc](./store.md#how-to-extend-it) for the contract).
2. Wrap every native driver error in `AdapterError` with the original on `cause`.
3. Run the conformance harness against your adapter:

```ts
import { runStoreAdapterTests } from "@inseam/store-contract/testing";
import { myAdapter } from "../src/index.ts";

runStoreAdapterTests(async () => {
  const adapter = myAdapter(/* ... */);
  return {
    adapter,
    cleanup: () => adapter.close(),
    breakHealth: () => adapter.close(), // or whatever drives health() → false
  };
});
```

Use bun-sqlite as the worked example for "sync driver, wrapped to async" and d1 as the worked example for "async driver, near-passthrough." Both are short enough to read in one sitting.

## Where the code lives

- bun-sqlite adapter: `pkgs/adapter-store-bun-sqlite/src/index.ts`
- D1 adapter: `pkgs/adapter-store-d1/src/index.ts`
- Conformance harness: `pkgs/store-contract/src/testing/run-store-adapter-tests.ts` (exported as `@inseam/store-contract/testing`)
- Per-adapter tests (envelope normalization, factory, package shape): `pkgs/adapter-store-{bun-sqlite,d1}/test/`

## Related

- [Store](./store.md) — the port these adapters implement
- [Spec — bun-d1-sqlite-adapters](../spec/bun-d1-sqlite-adapters.md) — per-method behavior, error wrapping, acceptance criteria
- [Design — bun-d1-sqlite-adapters](../design/bun-d1-sqlite-adapters.md) — why these two, why `bun:sqlite` for the local case
- [Monorepo package model](./monorepo-package-model.md) — adapter naming, dependency direction, source-shape rules
