Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
d3b12f6
Initial plan
Copilot Jan 2, 2026
6a5eb48
Implement Universal ID-based sharding system with shard cache
Copilot Jan 2, 2026
eb6dbe6
Add comprehensive tests for ID generator and shard cache
Copilot Jan 2, 2026
c943cb0
Add comprehensive documentation for Universal ID-based sharding
Copilot Jan 2, 2026
253e243
Address code review feedback: improve error handling and security
Copilot Jan 2, 2026
6dad897
Add fallback for databaseName in cache operations
Copilot Jan 2, 2026
71f9c14
Add plugin support and schema relationship handling
Copilot Mar 4, 2026
4116749
Merge pull request #1 from ataylorme/copilot/improve-d1-multi-tenancy
ataylorme Mar 4, 2026
a79706c
Initial plan
Copilot Mar 4, 2026
de233bb
Update examples and documentation for PR #1 Universal ID sharding cha…
Copilot Mar 4, 2026
fea83e6
Merge pull request #2 from ataylorme/copilot/update-examples-and-docu…
ataylorme Mar 4, 2026
63a1558
Initial plan
Copilot Mar 4, 2026
bd4150c
test: add full test coverage for PR #1 features with Drizzle mocking
Copilot Mar 4, 2026
626dea1
Merge pull request #3 from ataylorme/copilot/ensure-full-test-coverage
ataylorme Mar 4, 2026
07c73fa
Initial plan
Copilot Mar 4, 2026
7138691
Improve shard cache performance using Cloudflare KV as persistent L2 …
Copilot Mar 4, 2026
75c6852
Update documentation to reflect KV-backed shard cache changes
Copilot Mar 4, 2026
56e9ae4
Merge pull request #4 from ataylorme/copilot/improve-cache-with-kv
ataylorme Mar 4, 2026
3475238
Add comprehensive test suite with Vitest, nock, faker and CI workflow
claude Mar 16, 2026
ca4ec2e
Replace D1 mocks with real local D1 via wrangler local persistence
claude Mar 16, 2026
7f4ecac
Add PR description markdown file for copy/paste
claude Mar 16, 2026
9a0c916
Revert "Add PR description markdown file for copy/paste"
claude Mar 16, 2026
bb10aff
Update test workflow to include multi-tenancy branch
ataylorme Mar 16, 2026
b72044c
Remove RUNNER_TEMP env variable from workflow
ataylorme Mar 16, 2026
abe7fa0
Add @vitest/coverage-v8 dev dependency for test coverage
claude Mar 16, 2026
7bbc7c1
Add coverage directory to .gitignore
claude Mar 16, 2026
39c1ebb
Add local test scripts and concurrency cancellation to all workflows
claude Mar 16, 2026
6897785
Add test:all script to package.json
claude Mar 16, 2026
b158622
Wrangler persisted test suite
ataylorme Mar 16, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build-hono-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ on:
- ".github/workflows/build-hono-example.yml" # This file
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/build-opennextjs-example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ on:
- ".github/workflows/build-example.yml" # This file
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ on:
- ".github/workflows/build-opennextjs-org-d1-multi-tenancy-example.yml" # This file
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
branches: [main]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/cli-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
pull_request:
paths: ["cli/**"]

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
build:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/cli-test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ on:
pull_request:
paths: ["cli/**"]

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
test:
runs-on: ubuntu-latest
Expand Down
4 changes: 4 additions & 0 deletions .github/workflows/continuous-releases.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ on:
branches: [main]
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

permissions: {}

jobs:
Expand Down
140 changes: 140 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
name: Test Suite

on:
push:
branches:
- main
- "feat/d1-multi-tenancy"
pull_request:
branches:
- main
- "feat/d1-multi-tenancy"
workflow_dispatch:

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
unit-tests:
name: Unit & Integration Tests (Node ${{ matrix.node-version }})
runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
node-version: ["20", "22", "24"]

steps:
- uses: actions/checkout@v4

- name: Setup Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.10.0
run_install: false

- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Cache pnpm dependencies
uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-

- name: Install dependencies
run: pnpm install

- name: Run tests
run: pnpm test

- name: Run tests with coverage
run: pnpm test:coverage
if: matrix.node-version == '22'

typecheck:
name: Typecheck
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.10.0
run_install: false

- name: Install dependencies
run: pnpm install

- name: Typecheck
run: pnpm typecheck

sharding-scenarios:
name: Sharding Scenarios
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
scenario:
- name: "Multi-DB Sharding"
test-filter: "sharding-multi-db"
- name: "Integration Sharding"
test-filter: "integration-sharding"
- name: "Shard Cache"
test-filter: "shard-cache"
- name: "ID Generator & Routing"
test-filter: "id-generator"
- name: "Schema Detection"
test-filter: "schema-detection"
- name: "D1 Utils"
test-filter: "d1-utils"
- name: "Plugin Index"
test-filter: "__tests__/index"

steps:
- uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "24"

- name: Setup pnpm
uses: pnpm/action-setup@v4
with:
version: 10.10.0
run_install: false

- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Cache pnpm dependencies
uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-

- name: Install dependencies
run: pnpm install

- name: "Run: ${{ matrix.scenario.name }}"
run: npx vitest run --reporter=verbose ${{ matrix.scenario.test-filter }}
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,6 @@ node_modules
dist
pnpm-lock.yaml
bun.lock
*.log
*.log
.wrangler
coverage
14 changes: 13 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Demo implementations are available in the [`examples/`](./examples/) directory f
- 🚀 **Hyperdrive Support**: Connect to Postgres and MySQL databases through Cloudflare Hyperdrive.
- 🔌 **KV Storage Integration**: Optionally use Cloudflare KV for secondary storage (e.g., session caching).
- 📁 **R2 File Storage**: Upload, download, and manage user files with Cloudflare R2 object storage and database tracking.
- 🏢 **D1 Multi-Tenancy**: Automatic tenant database creation with Universal ID-based sharding for optimal performance.
- 📍 **Automatic Geolocation Tracking**: Enrich user sessions with location data derived from Cloudflare.
- 🌐 **Cloudflare IP Detection**: Utilize Cloudflare's IP detection headers out-of-the-box.
- 🔍 **Rich Client-Side Context**: Access timezone, city, country, region, and more via the client plugin.
Expand All @@ -34,7 +35,7 @@ Demo implementations are available in the [`examples/`](./examples/) directory f
- [x] R2
- [ ] Cloudflare Images
- [ ] Durable Objects
- [ ] D1 Multi-Tenancy
- [x] D1 Multi-Tenancy with Universal ID-based Sharding

**CLI:**

Expand Down Expand Up @@ -67,6 +68,8 @@ Demo implementations are available in the [`examples/`](./examples/) directory f
- [7. Initialize the Client](#7-initialize-the-client)
- [Usage Examples](#usage-examples)
- [Accessing Geolocation Data](#accessing-geolocation-data)
- [D1 Multi-Tenancy with Universal ID Sharding](./docs/d1-multi-tenancy-universal-ids.md)
- [D1 Multi-Tenancy Plugin Integration Guide](./docs/d1-multi-tenancy-plugins.md)
- [R2 File Storage Guide](./docs/r2.md)
- [License](#license)
- [Contributing](#contributing)
Expand Down Expand Up @@ -339,6 +342,15 @@ For integrating the generated `auth.schema.ts` with your existing Drizzle schema

If you provide a KV namespace in the `withCloudflare` configuration (as shown in `src/auth/index.ts`), it will be used as [Secondary Storage](https://www.better-auth.com/docs/concepts/database#secondary-storage) by Better Auth. This is typically used for caching or storing session data that doesn't need to reside in your primary database.

When D1 multi-tenancy is configured, the same KV namespace (or a dedicated one passed as `multiTenancy.kv`) is also used as a **persistent L2 backing store for the shard cache**. This means the `shardHash → databaseId` mapping survives Worker cold starts and is shared across all Worker instances, eliminating the tenant-table re-hydration query on startup.

```typescript
multiTenancy: {
// ... other options
kv: env.KV, // uses this KV for the shard cache; falls back to top-level kv if omitted
},
```

Ensure your KV namespace (e.g., `USER_SESSIONS`) is correctly bound in your `wrangler.toml` file.

### 6. Set Up API Routes
Expand Down
Loading