chore: upgrade Node 22 / Next 16 / Tailwind 4 / Biome 2 / TS 6 / Zod 4 / Better Auth#1
chore: upgrade Node 22 / Next 16 / Tailwind 4 / Biome 2 / TS 6 / Zod 4 / Better Auth#1notsuhas wants to merge 9 commits into
Conversation
…rsions Move every workspace's package.json + the root lockfile to the upgraded baseline (Node 22, pnpm 10.33.2, Turbo 2.9.x, TypeScript 6, Zod 4, Better Auth, Next 16, Tailwind 4, Biome 2, Drizzle, Hono v2, sonner v2, lucide-react v1, faker 10, pino 10, aws-sdk 3.1035, etc.). Source code is migrated in subsequent commits in this PR; this commit is the specifications + lockfile.
…store
Replaces the next-auth v5 beta wiring with Better Auth across the
auth package, the API ensure-auth middleware, the web app's auth
routes/login pages/providers, and the DB schema (account, session,
user, verification). Adds the 0002_better_auth.sql Drizzle migration.
Also drops the Zustand path-store: per-segment templates +
AppStoreProvider/AppStoreFragmentProvider are replaced with a thin
useCodePushRouteParams hook reading from next/navigation, and query
factories in codepush-queries.ts now take explicit { appName,
platform, ... } args instead of calling hooks internally.
AUTH_ALLOWED_DOMAIN enforcement moves from a silent hooks.before on
/callback (where ctx.context.newSession is null and ctx.body.email is
absent for OAuth) to databaseHooks.user.create.before for new sign-ups
and databaseHooks.session.create.before for returning logins.
- Next 16: rename middleware.ts → proxy.ts (Next 16 renamed the public hook), refresh next.config.ts. - Tailwind v4: drop tailwind.config.ts, switch to CSS-first config in globals.css + postcss.config.mjs, regenerate components.json. - Biome 2: bump biome.json to v2 schema, run biome check --write across the workspace (UI components, drizzle metadata snapshots, .changeset/config, .vscode/settings). - Drop the Suspense template wrappers under (main)/codepush/** that the Zustand store-fragment cleanup made unnecessary.
- Bump every workspace tsconfig.json to the new TS 6 base. - Migrate Zod 3.25 → 4.3 across packages/api/src/schemas/** and the consumers (openapi schemas, types.ts, web add-app + collaborators forms). Switch to the new error-map / refinement / inference shapes.
Catches up the source code with the bumped runtime libraries:
- Hono / @hono/node-server 2 + @scalar/hono-api-reference 0.10:
refresh packages/api routes, lib/create/app, openapi config,
middlewares, and the apps/web …/route.ts handler.
- oclif CLI stack: regenerate packages/cli/bin/{dev,run}, retarget
commands and common base classes, and refresh the README index.
- mocha 11 + chai 6: rewrite the hello-world tests, switch
.mocharc.json to the new loader.
- sonner 2 + lucide-react 1: update Toaster wiring + icon imports
across the web UI.
- pino 10, faker 10, aws-sdk 3.1035, @alwatr/parse-duration 9, conf
15 / which 6 / shx 0.4: small touch-ups in db/manager, scripts,
cli services, and shared/api-client.
- Drop the redundant turbo.json globalEnv entries the bump exposed.
… app→platform structure Capture the inserted platform rows and group them under their app instead of re-querying schema.codepush_platform downstream. Avoids re-pulling stale rows from prior seed runs and keeps the unique-constraint contract clean during the deployment-insertion step.
…or TypeScript and TypeScript React files
The hint comment said `http://localhost:3000/api/auth` but the actual callback path under both the previous next-auth setup and Better Auth is `/api/auth/callback/github`. Anyone copying the hint verbatim into their GitHub OAuth app would land on the wrong callback and see an OAuth error after the migration.
- Apply changeset: bump every workspace package from 2.0.0 to 3.0.0 in lockstep (fixed group: @rentlydev/rnota-*). - Sync pnpm-lock.yaml with the new version refs. - README: node badge 18 → 22, 'Auth.js' → 'Better Auth', 'Next.js 15' → 'Next.js 16'.
| console.warn( | ||
| `Blocking sign-in for ${owner.email} — does not match AUTH_ALLOWED_DOMAIN=${env.AUTH_ALLOWED_DOMAIN}`, | ||
| ); | ||
| return false; |
There was a problem hiding this comment.
return false here relies on Better Auth's internal control flow converting a falsy return into a null session → error redirect. This isn't documented in their public API. If Better Auth changes how hook return values are handled in a patch release, blocked users could silently get through. Add an integration test that verifies a non-matching domain user cannot obtain a session.
There was a problem hiding this comment.
This is documented: https://better-auth.com/docs/concepts/database#1-before-hook
I don't think Better Auth is going to make such a change and put it as non-breaking. Even if they did, on upgrade, TS compilation would fail.
| "lib": ["ES2022", "DOM", "DOM.Iterable"], | ||
| "types": ["node"], | ||
| "allowJs": true, | ||
| "ignoreDeprecations": "6.0", |
There was a problem hiding this comment.
Fine for the initial TS 6 migration, but this suppresses deprecation warnings for esModuleInterop (line 4), resolveJsonModule (line 11), and forceConsistentCasingInFileNames (line 19). Consider opening a tracking issue to remove these deprecated options in a follow-up so this doesn't become permanent tech debt.
There was a problem hiding this comment.
The three options you named (esModuleInterop, resolveJsonModule, forceConsistentCasingInFileNames) aren't deprecated in TS 6 — they're stable and have no deprecation notice. The flags actually targeted by ignoreDeprecations: "6.0" are charset, target: "ES3", importsNotUsedAsValues, preserveValueImports, noImplicitUseStrict, noStrictGenericChecks, keyofStringsOnly, suppressExcessPropertyErrors, suppressImplicitAnyIndexErrors, out, and prepend.
Also grepped every tsconfig in the repo (base + internal-package + the 9 consumers) and none of them set any of those.
Summary
Brings
react_native_ota_updaterup to a modern toolchain — Node 22, Next.js 16, Tailwind v4, Biome 2, TypeScript 6, Zod 4, Better Auth — and bumps every workspace dependency. Nine logically scoped commits. Workspace packages are bumped to v3.0.0 (major) in commit 9 via Changesets.Commits in order
7fb6082chore: upgrade Node.js to 22, pnpm 10.33.x, and bump workspace dep versions98a312bfeat: migrate auth from next-auth to better-auth + drop Zustand path-store6adb2aachore: migrate to Next.js 16 + Tailwind v4 + Biome 203827e2chore: migrate to TypeScript 6 + Zod 401f6cffchore: adapt source to upgraded library APIs862817drefactor(seed): use returning() for platform inserts and build nested app→platform structure8e35002chore: set Biome as default formatter for TypeScript / TSX in .vscode/settings.jsone7c805fdocs(env): fix GitHub OAuth callback URL hint in .env.exampled25c494chore: release v3.0.0 + refresh README for upgraded stackTotal: 197 files changed, +11111 / -8296.
What's done
tailwind.config.ts),middleware.ts→proxy.ts(Next 16 rename).next-auth@5.0.0-beta→ Better Auth across the auth package,ensure-authmiddleware, web auth routes/login pages/providers, and the DB schema (account,session,user, newverification); ships migration0002_better_auth.sql.AUTH_ALLOWED_DOMAINenforcement moved fromhooks.before(silently null on OAuth/callback) todatabaseHooks.user.create.before+databaseHooks.session.create.before.AppStoreProvider/AppStoreFragmentProvider+ per-segment templates replaced with a thinuseCodePushRouteParamshook. Query factories incodepush-queries.tsnow take explicit{ appName, platform, … }args instead of calling hooks internally.@hono/node-serverv2 +@scalar/hono-api-reference0.10; oclif refresh; mocha 11 + chai 6; sonner 2; lucide-react 1; pino 10; faker 10; aws-sdk 3.1035;@alwatr/parse-duration9; conf 15 / which 6 / shx 0.4.biome check --writeacross the workspace, Biome v2 schema inbiome.json, regeneratedcomponents.json, refreshed Drizzle metadata snapshots..returning()and group them under their app instead of re-querying.Verification done locally
pnpm install --frozen-lockfilepnpm typecheck— 14/14 turbo tasks greenpnpm dlx @biomejs/biome@2 check— cleanpnpm build:next— 7/7 turbo tasks, all routes compiledWhat's NOT done
0002_better_auth.sqlships in the diff but has not been run against any database. Plan a downtime/maintenance window to apply it (it adds theverificationtable and reshapesaccount/session/user).turbo.jsonglobalEnvcleanup in commit 5 may be too aggressive for environments that read additional vars at build time — diff that file with care.Reviewer instructions — running this branch locally
Pre-requisites
.nvmrcis22;nvm usewill pick it up).packageManagerfrom rootpackage.json; runcorepack enableonce if you haven't).start-services.shfor Docker.Steps
Pull and switch Node
Install
Static checks (must pass before touching the DB)
Back up the database
0002_better_auth.sqlreshapesaccount/session/userand addsverification. Do not skip.Apply the migration
Inspect
internal/db/drizzle/0002_better_auth.sqlfirst if you want to see the exact DDL.Env / OAuth callback check
Better Auth reuses the same env vars as the previous next-auth setup (
AUTH_URL,AUTH_SECRET,AUTH_GITHUB_ID,AUTH_GITHUB_SECRET,AUTH_ALLOWED_DOMAIN) — nothing to add or rotate. The.env.examplehint comment for the GitHub OAuth Authorization callback URL has been corrected (commit 8) tohttp://localhost:3000/api/auth/callback/github; if your existing GitHub OAuth app was set to just…/api/auth, update it on github.com/settings/developers to match.Run dev
Smoke test in this order (auth is the riskiest change — verify it first)
/login→ "Continue with GitHub" → callback → land on/codepush.UserNavshows the user. An email outsideAUTH_ALLOWED_DOMAINproduces a redirect-style failure (not a silent null).databaseHooks.session.create.beforedoesn't block returning users./codepushlists apps; "Add app" creates one (validates the Drizzle.returning()path from commit 6).cd packages/cli && pnpm link:cli && rnota --helpto verify the oclif wiring (commit 5).If something breaks
psql "$DATABASE_URL" < backup-pre-better-auth.sql), open a comment with the error, do NOT hand-patch tables. The schema reshape is interdependent./api/auth/error→ callback URL on the GitHub app doesn't match<AUTH_URL>callback/github. Fix it on github.com, not in code.AUTH_SECRETerrors from Better Auth → set it:openssl rand -base64 32.pnpm install --frozen-lockfile; node_modules can desync after the lockfile bump.Rolling back (code + DB together)
Migration prompt — for porting these changes onto a private/internal fork
Copy-paste prompt:
🤖 Generated with Claude Code