Skip to content

Commit 964e27d

Browse files
committed
chore: upgrade Better Auth 1.7, unify deploys, guard db:push
Better Auth 1.7 keys an external identity on `(issuer, accountId)` instead of `(providerId, accountId)`, and `issuer` is required. `identity` gains the column and swaps its composite unique; the old constraint is now implied, since issuer is a function of providerId. `db/migrations/0000_init.sql` is regenerated in place per the squashed-init convention - run `bun db:push` after pulling. `getAuthTables()` also started reporting the indexes, defaults and cascades a plugin declares. `generate-auth-schema.ts` emitted none of them, and the validation command told reviewers to ignore exactly the metadata that changed, so both now carry it. Three rules the docs stated become controls the code enforces: - `bun deploy:{staging,production}` builds and deploys api, app and web in one script that `deploy.yml` also calls, so a release from a laptop and one from Actions cannot drift in order or environment selection. It owns the production-to-empty-`--env` mapping and rejects any other name. - `db:push` refuses a non-local database. Reshaping in place is a migration nobody reviewed, and it drops columns to make the shapes agree. `ALLOW_REMOTE_DB_PUSH=1` is the deliberate way past it. - `grant-app-role.sql` provisions the least-privilege role Hyperdrive should use. It asserts the runner owns the database and schema first, because Postgres answers an unauthorised REVOKE with a warning and exit 0. `no-unused-vars` gains `ignoreRestSiblings`, so `const { password, ...rest }` stops being a lint error in a kit that ships a password column.
1 parent aceeb4f commit 964e27d

36 files changed

Lines changed: 1078 additions & 468 deletions

.claude/commands/validate-auth-schema.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ Check that the Drizzle schema in `db/schema/` still satisfies what Better Auth e
66
bun run db/scripts/generate-auth-schema.ts
77
```
88

9-
The script builds a real auth instance from `apps/api/lib/auth.ts` with fixed placeholder credentials, every optional integration switched on, so the output is the full set of tables rather than the subset your environment happens to enable. Per field it carries the `type`, the `required` and `unique` flags, and the reference target — nothing else.
9+
The script builds a real auth instance from `apps/api/lib/auth.ts` with fixed placeholder credentials, every optional integration switched on, so the output is the full set of tables rather than the subset your environment happens to enable. Per field it carries the `type`, the `required`, `unique` and `index` flags, any literal `defaultValue`, and the reference target with its `onDelete`. Per table it carries `indexes`: the composite indexes a plugin declares, which is how the account identity key `(issuer, accountId)` arrives.
1010

1111
Compare that output against `db/schema/` and report:
1212

1313
- Tables Better Auth expects that are missing, and tables no plugin in `auth.ts` needs any more.
1414
- Field-level drift: missing or extra columns, mismatched types, and `required` or `unique` flags that disagree.
1515
- Foreign keys pointing at the wrong table or column.
16-
- Defaults, `onDelete`, and indexes are **not** in the generated output — they are this project's decisions. Check those against the conventions in `db/AGENTS.md` instead, and do not report them as Better Auth drift.
16+
- A `true` `index` flag, a table-level entry in `indexes`, a literal `defaultValue`, or an `onDelete` in the output is Better Auth asking for it: report a schema that lacks one. Indexes, defaults and cascades the project adds beyond that list are its own decisions — check those against the conventions in `db/AGENTS.md` and do not report them as drift.
1717
- Local naming that must stay mapped, not renamed away: Better Auth's `account` is our `identity` table.
1818
- Project-specific columns, indexes, and constraints are expected and fine on their own. Flag any that constrain a write Better Auth performs: a `NOT NULL` column with no database default breaks every insert into that table, and an extra unique or check constraint can reject a row Better Auth considers valid. Fields that must participate in its models belong in `additionalFields` rather than added to the table behind its back.
1919

.github/CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Before starting work on a significant change, open an issue to discuss your prop
1616

1717
### Prerequisites
1818

19-
- [Bun](https://bun.sh) >= 1.3.0
19+
- [Bun](https://bun.sh) >= 1.4.0
2020
- [Node.js](https://nodejs.org) >= 20 (for some tooling)
2121
- [Git](https://git-scm.com)
2222

.github/workflows/deploy.yml

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ jobs:
6464
# `apps/email/dist` is not deployed directly – the API worker imports
6565
# `@repo/email`, whose exports point there, so `worker.ts` fails to bundle
6666
# without it.
67+
#
68+
# `scripts/deploy.ts` checks the same three, and this stays anyway: that
69+
# check runs after the migration, and a restore that silently dropped a
70+
# `dist` should fail before the point of no return, not after it.
6771
- name: Verify build artifacts
6872
run: |
6973
test -d apps/email/dist
@@ -168,14 +172,10 @@ jobs:
168172
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
169173
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
170174
DEPLOY_ENV: ${{ inputs.environment }}
171-
run: |
172-
# Recomputed rather than carried from the preflight: an empty `--env`
173-
# selects production, so a value that went missing would deploy it.
174-
if [[ "$DEPLOY_ENV" == "production" ]]; then
175-
env_args=(--env "")
176-
else
177-
env_args=(--env "$DEPLOY_ENV")
178-
fi
179-
bun wrangler deploy --config apps/api/wrangler.jsonc "${env_args[@]}"
180-
bun wrangler deploy --config apps/app/wrangler.jsonc "${env_args[@]}"
181-
bun wrangler deploy --config apps/web/wrangler.jsonc "${env_args[@]}"
175+
# `bun deploy:{staging,production}` runs the same script locally, so a
176+
# release from a laptop and one from CI cannot drift in order or in
177+
# environment selection. It maps production to Wrangler's empty `--env`
178+
# itself and rejects any other environment name outright, so a value
179+
# lost in transit fails the run rather than deploying production.
180+
# `--skip-build` because the restored artifact is the verified build.
181+
run: bun scripts/deploy.ts "$DEPLOY_ENV" --skip-build

AGENTS.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
## Tech Stack
1414

15-
- **Toolchain:** Bun >=1.3.0 (package manager, scripts, local API server), TypeScript 6.0, ESM (`"type": "module"`)
15+
- **Toolchain:** Bun >=1.4.0 (package manager, scripts, local API server), TypeScript 6.0, ESM (`"type": "module"`)
1616
- **Production runtime:** Cloudflare Workers (workerd) – not Bun. Code that ships must run on Workers APIs.
1717
- **Frontend:** React 19, TanStack Router, TanStack Query, Jotai, shadcn/ui (new-york), Tailwind CSS v4
1818
- **Backend:** Hono, tRPC 11, Better Auth (email OTP, passkey, Google OAuth, organizations)
@@ -31,11 +31,12 @@ bun lint # ESLint with cache
3131
bun typecheck # tsc --build (builds apps/email for its types)
3232
bun infra:check # Terraform fmt + validate, no credentials or state
3333
bun ui:add <component> # Add shadcn/ui component to packages/ui
34+
bun deploy:{staging,production} # Build and deploy api → app → web; no migrations
3435

3536
# Per-app: bun {web,app,api}:{dev,build,deploy}; test for app/api, check for web
3637
# Database: bun db:{push,generate,migrate,studio,seed,export}
3738
# :staging / :production on migrate, studio, export; seed stops at :staging;
38-
# push and generate are local-only
39+
# generate is local-only, and push refuses a non-local database
3940
```
4041

4142
## Verification

README.md

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ Each app deploys independently to Cloudflare Workers. The web worker routes `/ap
5454

5555
## Prerequisites
5656

57-
- [Bun](https://bun.sh/) v1.3+ (replaces Node.js and npm)
57+
- [Bun](https://bun.sh/) v1.4+ (replaces Node.js and npm)
5858
- [VS Code](https://code.visualstudio.com/) with our [recommended extensions](.vscode/extensions.json)
5959
- [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) browser extension (recommended)
6060
- [Cloudflare account](https://dash.cloudflare.com/sign-up) for deployment
@@ -172,15 +172,13 @@ bun db:migrate:production # reads .env.production.local, and only that file
172172
### 4. Build and Deploy
173173

174174
```bash
175-
# Build every deployable workspace; Bun orders workspace dependencies
176-
bun run build # Build all deployable workspaces
177-
178-
# Deploy service-binding targets before the web router
179-
bun api:deploy --env=""
180-
bun app:deploy --env=""
181-
bun web:deploy --env=""
175+
# Builds, then deploys api -> app -> web (service-binding targets first)
176+
bun deploy:staging
177+
bun deploy:production
182178
```
183179

180+
CI runs the same script, so a release from your machine and one from GitHub Actions cannot drift.
181+
184182
## Backers
185183

186184
<a href="https://reactstarter.com/b/1"><img src="https://reactstarter.com/b/1.png" height="60" /></a>&nbsp;&nbsp;<a href="https://reactstarter.com/b/2"><img src="https://reactstarter.com/b/2.png" height="60" /></a>&nbsp;&nbsp;<a href="https://reactstarter.com/b/3"><img src="https://reactstarter.com/b/3.png" height="60" /></a>&nbsp;&nbsp;<a href="https://reactstarter.com/b/4"><img src="https://reactstarter.com/b/4.png" height="60" /></a>&nbsp;&nbsp;<a href="https://reactstarter.com/b/5"><img src="https://reactstarter.com/b/5.png" height="60" /></a>&nbsp;&nbsp;<a href="https://reactstarter.com/b/6"><img src="https://reactstarter.com/b/6.png" height="60" /></a>&nbsp;&nbsp;<a href="https://reactstarter.com/b/7"><img src="https://reactstarter.com/b/7.png" height="60" /></a>&nbsp;&nbsp;<a href="https://reactstarter.com/b/8"><img src="https://reactstarter.com/b/8.png" height="60" /></a>

apps/api/package.json

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,30 +18,30 @@
1818
"logs": "wrangler tail --env-file ../../.env --env-file ../../.env.local"
1919
},
2020
"dependencies": {
21-
"@better-auth/passkey": "^1.6.29",
22-
"@better-auth/stripe": "^1.6.29",
21+
"@better-auth/passkey": "^1.7.1",
22+
"@better-auth/stripe": "^1.7.1",
2323
"@repo/core": "workspace:*",
2424
"@repo/db": "workspace:*",
2525
"@repo/email": "workspace:*",
2626
"@trpc/server": "^11.18.0",
27-
"better-auth": "^1.6.29",
27+
"better-auth": "^1.7.1",
2828
"drizzle-orm": "^0.45.2",
2929
"postgres": "^3.4.9",
30-
"resend": "^6.20.0",
30+
"resend": "^6.22.0",
3131
"stripe": "^22.5.0"
3232
},
3333
"peerDependencies": {
34-
"hono": "^4.13.2",
34+
"hono": "^4.13.3",
3535
"zod": "^4.4.3"
3636
},
3737
"devDependencies": {
38-
"@cloudflare/workers-types": "^5.20260816.1",
38+
"@cloudflare/workers-types": "^5.20260823.1",
3939
"@repo/typescript-config": "workspace:*",
40-
"@types/bun": "^1.3.14",
41-
"hono": "^4.13.2",
40+
"@types/bun": "^1.4.0",
41+
"hono": "^4.13.3",
4242
"typescript": "~6.0.3",
43-
"vitest": "~4.1.10",
44-
"wrangler": "^4.123.0",
43+
"vitest": "~4.1.11",
44+
"wrangler": "^4.125.0",
4545
"zod": "^4.4.3"
4646
}
4747
}

apps/app/package.json

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,15 @@
1414
"logs": "wrangler tail --env-file ../../.env --env-file ../../.env.local"
1515
},
1616
"dependencies": {
17-
"@better-auth/passkey": "^1.6.29",
18-
"@better-auth/stripe": "^1.6.29",
17+
"@better-auth/passkey": "^1.7.1",
18+
"@better-auth/stripe": "^1.7.1",
1919
"@repo/ui": "workspace:*",
20-
"@tanstack/react-query": "^5.101.4",
21-
"@tanstack/react-router": "^1.170.29",
20+
"@tanstack/react-query": "^5.102.2",
21+
"@tanstack/react-router": "^1.170.32",
2222
"@trpc/client": "^11.18.0",
23-
"better-auth": "^1.6.29",
23+
"better-auth": "^1.7.1",
2424
"jotai": "^2.20.2",
25-
"lucide-react": "^1.31.0",
25+
"lucide-react": "^1.33.0",
2626
"react": "^19.2.8",
2727
"react-dom": "^19.2.8",
2828
"react-error-boundary": "^6.1.3",
@@ -32,24 +32,24 @@
3232
"@repo/api": "workspace:*",
3333
"@repo/typescript-config": "workspace:*",
3434
"@tailwindcss/vite": "^4.3.3",
35-
"@tanstack/react-devtools": "^0.10.10",
36-
"@tanstack/react-query-devtools": "^5.101.4",
35+
"@tanstack/react-devtools": "^0.10.12",
36+
"@tanstack/react-query-devtools": "^5.102.2",
3737
"@tanstack/react-router-devtools": "^1.167.1",
38-
"@tanstack/router-plugin": "^1.168.32",
38+
"@tanstack/router-plugin": "^1.168.35",
3939
"@testing-library/jest-dom": "^7.0.1",
4040
"@testing-library/react": "^16.3.2",
41-
"@testing-library/user-event": "^14.6.4",
42-
"@types/bun": "^1.3.14",
41+
"@testing-library/user-event": "^14.6.6",
42+
"@types/bun": "^1.4.0",
4343
"@types/node": "^26.2.0",
4444
"@types/react": "^19.2.18",
4545
"@types/react-dom": "^19.2.4",
46-
"@vitejs/plugin-react": "^6.0.5",
47-
"happy-dom": "^20.11.2",
46+
"@vitejs/plugin-react": "^6.1.0",
47+
"happy-dom": "^20.11.6",
4848
"tailwindcss": "^4.3.3",
4949
"tw-animate-css": "^1.4.0",
5050
"typescript": "~6.0.3",
51-
"vite": "~8.2.1",
52-
"vitest": "~4.1.10",
53-
"wrangler": "^4.123.0"
51+
"vite": "~8.2.2",
52+
"vitest": "~4.1.11",
53+
"wrangler": "^4.125.0"
5454
}
5555
}

apps/web/package.json

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,22 +13,22 @@
1313
"logs": "wrangler tail --env-file ../../.env --env-file ../../.env.local"
1414
},
1515
"dependencies": {
16-
"@astrojs/react": "^6.0.2",
16+
"@astrojs/react": "^6.0.4",
1717
"@repo/ui": "workspace:*",
18-
"astro": "^7.2.2",
19-
"hono": "^4.13.2",
18+
"astro": "^7.2.4",
19+
"hono": "^4.13.3",
2020
"react": "^19.2.8",
2121
"react-dom": "^19.2.8"
2222
},
2323
"devDependencies": {
2424
"@astrojs/check": "^0.9.10",
25-
"@cloudflare/workers-types": "^5.20260816.1",
25+
"@cloudflare/workers-types": "^5.20260823.1",
2626
"@repo/typescript-config": "workspace:*",
2727
"@tailwindcss/vite": "^4.3.3",
2828
"@types/react": "^19.2.18",
2929
"@types/react-dom": "^19.2.4",
3030
"tailwindcss": "^4.3.3",
3131
"typescript": "~6.0.3",
32-
"wrangler": "^4.123.0"
32+
"wrangler": "^4.125.0"
3333
}
3434
}

0 commit comments

Comments
 (0)