{"_id":"@alexbruf/d1-level","_rev":"2-220a118aeccbf5477f40a42ae9f8e703","name":"@alexbruf/d1-level","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@alexbruf/d1-level","version":"0.1.0","keywords":["abstract-level","leveldb","cloudflare","d1","sqlite","workers","serverless"],"license":"Apache-2.0","_id":"@alexbruf/d1-level@0.1.0","maintainers":[{"name":"alexbruf","email":"alex@brufsky.org"}],"homepage":"https://github.com/alexbruf/d1-level#readme","bugs":{"url":"https://github.com/alexbruf/d1-level/issues"},"dist":{"shasum":"ce7a11f8fd00e2a1cf56ec0faa04de5b722abffb","tarball":"https://registry.npmjs.org/@alexbruf/d1-level/-/d1-level-0.1.0.tgz","fileCount":18,"integrity":"sha512-0aYg8BF63klK0aaN22lewCokePBA5b6qzm9lMSgLisD/5J+q8hbDvsc9HM2ZVqfK7lLltkkrMn2pRbgIf+1rYw==","signatures":[{"sig":"MEUCIQCWAbdrB09W7zwpoStZ6uUe0wldxxvjaeaaws0CQJer7gIgQkm3SMilT1oQkeOm20nF1xr3iVwS1lSECkcy+bafdC8=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexbruf%2fd1-level@0.1.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":42242},"type":"module","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"bd3720dd52bc61b13e89db347210017d18d3847f","scripts":{"test":"vitest run","build":"tsc","test:watch":"vitest","prepublishOnly":"npm run build"},"_npmUser":{"name":"alexbruf","email":"alex@brufsky.org"},"repository":{"url":"git+https://github.com/alexbruf/d1-level.git","type":"git"},"_npmVersion":"10.8.2","description":"An abstract-level database backed by Cloudflare D1","directories":{},"_nodeVersion":"20.20.1","dependencies":{"abstract-level":"^1.0.4"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"vitest":"3.2.4","typescript":"^5.4.0","better-sqlite3":"^11.0.0","@types/better-sqlite3":"^7.6.0","@cloudflare/workers-types":"^4.0.0","@cloudflare/vitest-pool-workers":"^0.12.0"},"_npmOperationalInternal":{"tmp":"tmp/d1-level_0.1.0_1774546266668_0.1605801568220937","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"name":"@alexbruf/d1-level","version":"0.2.0","description":"An abstract-level database backed by Cloudflare D1","type":"module","exports":{".":{"import":"./dist/index.js","types":"./dist/index.d.ts"}},"scripts":{"build":"tsc","test":"vitest run","test:watch":"vitest","prepublishOnly":"npm run build"},"dependencies":{"abstract-level":"^1.0.4"},"devDependencies":{"@cloudflare/vitest-pool-workers":"^0.12.0","@cloudflare/workers-types":"^4.0.0","@types/better-sqlite3":"^7.6.0","better-sqlite3":"^11.0.0","typescript":"^5.4.0","vitest":"3.2.4"},"publishConfig":{"access":"public"},"license":"Apache-2.0","repository":{"type":"git","url":"git+https://github.com/alexbruf/d1-level.git"},"homepage":"https://github.com/alexbruf/d1-level#readme","bugs":{"url":"https://github.com/alexbruf/d1-level/issues"},"keywords":["abstract-level","leveldb","cloudflare","d1","sqlite","workers","serverless"],"_id":"@alexbruf/d1-level@0.2.0","gitHead":"e6b644819c4a4a01c93c41950101bc1a42ba2f9c","_nodeVersion":"20.20.1","_npmVersion":"10.8.2","dist":{"integrity":"sha512-hL+h7EL5aqFaP26fNpVacS6WkVaA4JqGHQYvLDLLj1XuAb2D2WVcCsoPf9OtNW1ojdMgEiDskcv8CoE4czzQCw==","shasum":"6d51030dd50547d51c345b523e5f7f870814dc01","tarball":"https://registry.npmjs.org/@alexbruf/d1-level/-/d1-level-0.2.0.tgz","fileCount":18,"unpackedSize":43525,"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@alexbruf%2fd1-level@0.2.0","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHvY2MS1RKyZeTH2YKqlAuud2SNBKE/1ZRgg2MZJNuIOAiEA9c9BCz0hOICz7gcbhtdS8sVEtXhIxAmFTCxj1iBB1zI="}]},"_npmUser":{"name":"alexbruf","email":"alex@brufsky.org"},"directories":{},"maintainers":[{"name":"alexbruf","email":"alex@brufsky.org"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/d1-level_0.2.0_1774559649462_0.5285077296407776"},"_hasShrinkwrap":false}},"time":{"created":"2026-03-26T17:31:06.531Z","modified":"2026-03-26T21:14:09.954Z","0.1.0":"2026-03-26T17:31:06.863Z","0.2.0":"2026-03-26T21:14:09.663Z"},"bugs":{"url":"https://github.com/alexbruf/d1-level/issues"},"license":"Apache-2.0","homepage":"https://github.com/alexbruf/d1-level#readme","keywords":["abstract-level","leveldb","cloudflare","d1","sqlite","workers","serverless"],"repository":{"type":"git","url":"git+https://github.com/alexbruf/d1-level.git"},"description":"An abstract-level database backed by Cloudflare D1","maintainers":[{"name":"alexbruf","email":"alex@brufsky.org"}],"readme":"# d1-level\n\nAn [`abstract-level`](https://github.com/Level/abstract-level) database backed by [Cloudflare D1](https://developers.cloudflare.com/d1/).\n\nUse any library from the [`level`](https://github.com/Level/community) ecosystem — or anything that accepts an `abstract-level` database — on Cloudflare Workers with no external database dependencies.\n\n> 📌 New to `abstract-level`? Head over to the [Level FAQ](https://github.com/Level/community#faq).\n\n[![Tests](https://img.shields.io/badge/tests-887%20passing-brightgreen)](#tests)\n[![abstract-level](https://img.shields.io/badge/abstract--level-compliant-blue)](https://github.com/Level/abstract-level)\n[![License](https://img.shields.io/badge/license-Apache--2.0-blue)](LICENSE)\n\n## Install\n\n```sh\nnpm install d1-level\n```\n\n## Usage\n\n```typescript\nimport { D1Level } from 'd1-level'\n\nexport default {\n  async fetch(request: Request, env: { DB: D1Database }) {\n    const db = new D1Level({ d1: env.DB })\n\n    await db.put('hello', 'world')\n    const value = await db.get('hello') // 'world'\n\n    await db.batch([\n      { type: 'put', key: 'a', value: '1' },\n      { type: 'put', key: 'b', value: '2' },\n    ])\n\n    for await (const [key, value] of db.iterator({ gte: 'a', lte: 'b' })) {\n      console.log(key, value)\n    }\n\n    return new Response('ok')\n  }\n}\n```\n\n### With TinaCMS\n\n```typescript\n// tina/database.ts\nimport { D1Level } from 'd1-level'\nimport { createDatabase } from '@tinacms/datalayer'\nimport { GitHubProvider } from 'tinacms-gitprovider-github'\n\nexport function createTinaDatabase(env: { DB: D1Database }) {\n  return createDatabase({\n    level: new D1Level({ d1: env.DB }),\n    gitProvider: new GitHubProvider({\n      owner: process.env.GITHUB_OWNER,\n      repo: process.env.GITHUB_REPO,\n      token: process.env.GITHUB_PERSONAL_ACCESS_TOKEN,\n      branch: process.env.GITHUB_BRANCH,\n    }),\n  })\n}\n```\n\n## Setup\n\n### Wrangler config\n\nAdd the D1 binding to your `wrangler.toml`:\n\n```toml\n[[d1_databases]]\nbinding = \"DB\"\ndatabase_name = \"my-db\"\ndatabase_id = \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"\n```\n\n### Table creation\n\nThe default `createTable: true` runs `CREATE TABLE IF NOT EXISTS` on open — no migrations needed for development.\n\nFor production, create the table explicitly:\n\n```sh\nwrangler d1 execute MY_DB --remote --command \\\n  \"CREATE TABLE IF NOT EXISTS kv (key TEXT PRIMARY KEY, value TEXT NOT NULL) WITHOUT ROWID;\"\n```\n\nOr add a migration file:\n\n```sql\n-- migrations/0001_create_kv.sql\nCREATE TABLE IF NOT EXISTS kv (\n  key   TEXT PRIMARY KEY,\n  value TEXT NOT NULL\n) WITHOUT ROWID;\n```\n\n```sh\nwrangler d1 migrations apply MY_DB --remote\n```\n\nThen pass `createTable: false`:\n\n```typescript\nconst db = new D1Level({ d1: env.DB, createTable: false })\n```\n\n### Namespace (shared databases)\n\nUse `namespace` to isolate this adapter's table when sharing a D1 database:\n\n```typescript\nconst db = new D1Level({ d1: env.DB, namespace: 'tina' })\n// → uses table \"tina_kv\" instead of \"kv\"\n```\n\n## API\n\n### `new D1Level(options)`\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `d1` | `D1Database` | **required** | Cloudflare D1 binding from Worker `env` |\n| `namespace` | `string` | `''` | Table name prefix. `''` → table `kv`; `'tina'` → table `tina_kv` |\n| `createTable` | `boolean` | `true` | Run `CREATE TABLE IF NOT EXISTS` on open |\n\nAll other options are forwarded to [`abstract-level`](https://github.com/Level/abstract-level#db--new-abstractlevelmanifest-options).\n\n`D1Level` inherits the full `abstract-level` API: `put`, `get`, `del`, `getMany`, `batch`, `iterator`, `keys`, `values`, `clear`, `sublevel`, and more.\n\n## How it works\n\nD1 is SQLite under the hood. Entries are stored in a two-column table:\n\n```sql\nCREATE TABLE kv (\n  key   TEXT PRIMARY KEY,\n  value TEXT NOT NULL\n) WITHOUT ROWID;\n```\n\n`WITHOUT ROWID` is a SQLite optimization for tables where the primary key is the data — it avoids the internal rowid indirection and keeps the B-tree compact.\n\n**Iteration** uses cursor-based pagination. Since D1 is accessed over HTTP, there's no persistent server-side cursor. Instead, the iterator fetches rows in pages of 100, using `WHERE key > lastKey` to advance between pages. This is transparent to callers.\n\n**Batches** use D1's native `batch()` which executes all statements as a single atomic transaction.\n\n**Sublevels** are handled entirely by `abstract-level` via key prefixing — no extra SQL machinery needed.\n\n### Limitations\n\n- **No snapshot isolation** — iterators read live data. If you write to the database while iterating, the iterator may see the changes. This is declared via `supports.snapshots = false` in the manifest.\n- **No `seek()`** — repositioning an open iterator is not implemented.\n- **UTF-8 keys and values only** — binary encodings are not supported (D1 TEXT columns only). Use base64 encoding for binary data.\n\n## Tests\n\n887 tests pass across three suites:\n\n| Suite | Count | Environment |\n|-------|-------|-------------|\n| Unit tests | 32 | Node.js (better-sqlite3 mock) |\n| abstract-level compliance | 844 | Node.js (better-sqlite3 mock) |\n| Integration tests | 11 | Miniflare (real D1 via `vitest-pool-workers`) |\n\nThe compliance suite is the [official `abstract-level` test suite](https://github.com/Level/abstract-level/tree/main/test) that all level implementations run against. All applicable tests pass (snapshot and seek tests are skipped via manifest flags, consistent with how other implementations handle unsupported features).\n\n```sh\nbun test\n```\n\n## License\n\n[Apache-2.0](LICENSE)\n","readmeFilename":"README.md"}