# UPDATES.SPEC.md

## `create-w3-app` - Full Dependency Update Specification

---

## Table of Contents

1. [Current State](#current-state)
2. [Phase 1: CLI Self-Dependencies (Low Risk)](#phase-1-cli-self-dependencies-low-risk)
3. [Phase 2: Template Version Map (Mixed Risk)](#phase-2-template-version-map-mixed-risk)
4. [Phase 3: Base Template (Medium Risk)](#phase-3-base-template-medium-risk)
5. [Phase 4: Template File Changes (High Risk)](#phase-4-template-file-changes-high-risk)
6. [Phase 5: CI/CD Workflow](#phase-5-cicd-workflow)
7. [How to Run Locally](#how-to-run-locally)
8. [How to Test](#how-to-test)
9. [How to Release](#how-to-release)
10. [Release Channels](#release-channels)

---

## Current State

The project manages dependencies in **three separate places**:

| Location | Purpose |
|----------|---------|
| `package.json` (root) | Dependencies for the CLI tool itself |
| `src/installers/dependencyVersionMap.ts` | Versions injected into users' scaffolded projects |
| `template/base/package.json` | Base Next.js app starting point for scaffolded projects |

**Current versions (as of v0.7.0):**

| Package | CLI (package.json) | Version Map | Base Template |
|---------|-------------------|-------------|---------------|
| next | `^15.5.4` (devDep) | — | `^15.5.2` |
| react | `^19.2.0` (devDep) | — | `^19.2.0` |
| react-dom | `^19.2.0` (devDep) | — | `^19.0.0` |
| typescript | `^5.9.3` (devDep) | — | `^5.9.3` |
| tailwindcss | `^4.1.14` (devDep) | `^4.0.15` | — |
| @tailwindcss/postcss | `^4.1.14` (devDep) | `^4.0.15` | — |
| postcss | — | `^8.5.3` | — |
| @privy-io/react-auth | `^3.3.0` (devDep) | `^2.4.14` | — |
| @privy-io/wagmi | — | `^1.0.5` | — |
| @rainbow-me/rainbowkit | `^2.2.8` (devDep) | `^2.2.6` | — |
| wagmi | `^2.18.0` (devDep) | `^2.15.6` | — |
| viem | `^2.38.0` (devDep) | `^2.31.0` | — |
| @tanstack/react-query | `^5.90.2` (devDep) | `^5.69.0` | — |
| lucide-react | `^0.545.0` (devDep) | `^0.515.0` | — |
| class-variance-authority | `^0.7.1` (devDep) | `^0.7.1` | — |
| clsx | `^2.1.1` (devDep) | `^2.1.1` | — |
| tailwind-merge | `^3.3.1` (devDep) | `^3.3.1` | — |
| tw-animate-css | `^1.4.0` (devDep) | `^1.3.4` | — |
| prettier | `^3.6.2` (devDep) | `^3.5.3` | — |
| prettier-plugin-tailwindcss | `^0.6.14` (devDep) | `^0.6.11` | — |
| eslint | — | `^9.23.0` | — |
| eslint-config-next | — | `^15.2.3` | — |
| typescript-eslint | `^8.46.0` | `^8.27.0` | — |
| @biomejs/biome | — | `^1.9.4` | — |
| @eslint/eslintrc | — | `^3.3.1` | — |
| eslint-plugin-drizzle | — | `^0.2.3` | — |
| @clack/prompts | `^0.11.0` | — | — |
| @clack/core | `^0.5.0` | — | — |
| zod | `^4.1.12` | — | — |
| superjson | `^2.2.2` | — | — |
| next-auth | `^4.24.11` | — | — |

---

## Phase 1: CLI Self-Dependencies (Low Risk)

These dependencies only affect the CLI tool itself — they do **not** affect scaffolded user projects.

### 1.1 Production Dependencies (`package.json` dependencies)

| Package | Current | Latest | Action | Breaking? |
|---------|---------|--------|--------|-----------|
| `@clack/core` | `^0.5.0` | `1.4.2` | **UPDATE** | YES — v1 API differs |
| `@clack/prompts` | `^0.11.0` | `1.6.0` | **UPDATE** | YES — v1 API differs |
| `@ianvs/prettier-plugin-sort-imports` | `^4.7.0` | check latest | KEEP/UPDATE | Check latest |
| `chalk` | `5.6.2` | latest | KEEP (pinned) | None |
| `commander` | `^14.0.1` | check latest | KEEP/UPDATE | Check latest |
| `eslint-plugin-import-x` | `^4.16.1` | check latest | KEEP/UPDATE | Check latest |
| `execa` | `^9.6.0` | check latest | KEEP/UPDATE | Check latest |
| `fs-extra` | `^11.3.2` | latest | KEEP/UPDATE | None |
| `gradient-string` | `^3.0.0` | latest | KEEP/UPDATE | None |
| `ora` | `9.0.0` | latest | KEEP (pinned) | None |
| `sort-package-json` | `^3.4.0` | latest | KEEP/UPDATE | None |
| `typescript-eslint` | `^8.46.0` | check latest | KEEP/UPDATE | Check latest |

### 1.2 Dev Dependencies (`package.json` devDependencies)

| Package | Current | Latest | Action | Breaking? |
|---------|---------|--------|--------|-----------|
| `@changesets/cli` | `^2.29.7` | check latest | KEEP/UPDATE | Check latest |
| `@types/fs-extra` | `^11.0.4` | latest | KEEP/UPDATE | None |
| `@types/gradient-string` | `^1.1.6` | latest | KEEP/UPDATE | None |
| `@types/node` | `^24.7.1` | check latest | UPDATE | None |
| `prettier` | `^3.6.2` | check latest | KEEP/UPDATE | None |
| `tsup` | `^8.5.0` | check latest | KEEP/UPDATE | None |
| `type-fest` | `^5.0.1` | check latest | KEEP/UPDATE | None |
| `typescript` | `^5.9.3` | `6.0.3` | **HOLD** | Next.js may not support TS 6 |
| `zod` | `^4.1.12` | `4.4.3` | UPDATE | Low risk (minor) |
| `superjson` | `^2.2.2` | check latest | KEEP/UPDATE | None |
| `next-auth` | `^4.24.11` | check latest | KEEP/UPDATE | None |

### 1.3 @clack/prompts Migration Notes

The `@clack/prompts` v0 → v1 migration is the highest-risk item in Phase 1. The CLI uses it in `src/cli/index.ts` for interactive prompts:

- **Affected file:** `src/cli/index.ts`
- **Key usage:** `text()`, `confirm()`, `select()`, `multiselect()`, `isCancel()`, `intro()`, `outro()`, `note()`, `spinner()`
- **What to check:**
  - Import paths may have changed
  - Function signatures may differ
  - Return types may be different
  - `isCancel` behavior may have changed
  - `spinner` API may differ

---

## Phase 2: Template Version Map (Mixed Risk)

File: `src/installers/dependencyVersionMap.ts`

These are the versions that get injected into users' `package.json` when scaffolding a project.

### 2.1 Safe Updates (No Breaking Changes)

| Package | Current | Target | Category |
|---------|---------|--------|----------|
| `tailwindcss` | `^4.0.15` | `^4.3.1` | Tailwind |
| `postcss` | `^8.5.3` | `^8.5.15` | Tailwind |
| `@tailwindcss/postcss` | `^4.0.15` | `^4.3.1` | Tailwind |
| `class-variance-authority` | `^0.7.1` | `^0.7.1` | shadcn (no change) |
| `clsx` | `^2.1.1` | `^2.1.1` | shadcn (no change) |
| `tailwind-merge` | `^3.3.1` | `^3.3.1` | shadcn (no change) |
| `tw-animate-css` | `^1.3.4` | `^1.4.0` | shadcn |
| `prettier` | `^3.5.3` | latest | ESLint |
| `@eslint/eslintrc` | `^3.3.1` | latest | ESLint |
| `prettier-plugin-tailwindcss` | `^0.6.11` | `^0.6.14` | ESLint |
| `eslint` | `^9.23.0` | latest | ESLint |
| `eslint-plugin-drizzle` | `^0.2.3` | latest | ESLint |
| `@biomejs/biome` | `^1.9.4` | latest | Biome |
| `@tanstack/react-query` | `^5.69.0` | `^5.101.1` | Web3 |
| `viem` | `^2.31.0` | `^2.53.1` | Web3 |
| `@rainbow-me/rainbowkit` | `^2.2.6` | `^2.2.11` | Web3 |

### 2.2 Breaking Updates (Template Files Need Rewriting)

| Package | Current | Target | Breaking Change |
|---------|---------|--------|-----------------|
| `eslint-config-next` | `^15.2.3` | `^16.x` | Must match Next.js 16. ESLint flat config changes |
| `typescript-eslint` | `^8.27.0` | latest | Low risk, but types may change |
| `@privy-io/react-auth` | `^2.4.14` | `^3.32.2` | Major v2→v3. `PrivyClientConfig`, `PrivyProvider` API |
| `@privy-io/wagmi` | `^1.0.5` | `^4.0.13` | Major v1→v4. Requires privy v3. `createConfig`/`WagmiProvider` from `@privy-io/wagmi` |
| `wagmi` | `^2.15.6` | `^3.6.18` | Major v2→v3. Hook renames, connector deps now optional |
| `lucide-react` | `^0.515.0` | `^1.21.0` | Major v0→v1. Icon import API completely changed |

### 2.3 wagmi v2 → v3 Breaking Changes

From wagmi migration guide:

1. **Connector dependencies now optional** — `injected` no longer requires any extra package. For our templates using only `injected()`, no change needed.
2. **Hook renames:**
   - `useAccount` → `useConnection`
   - `useAccountEffect` → `useConnectionEffect`
   - `useSwitchAccount` → `useSwitchConnection`
3. **Mutate function renames:** Custom names (e.g. `connect()`) → `mutate()`/`mutateAsync()`
4. **Removed:** `useConnect().connectors` → use `useConnectors()`
5. **Removed:** `useSwitchChain().chains` → use `useChains()`
6. **Removed:** `useDisconnect().connectors` and `useSwitchConnection().connectors` → use `useConnections()`
7. **Minimum TypeScript:** Now `5.9.3`

> **Note:** Our template config files (`wagmi.ts`, `wagmi-privy.ts`, `wagmi-rainbow.ts`) only use `createConfig`, `http`, `injected`, and `WagmiProvider` — these core APIs are **unchanged** in v3. The provider components in `template/extras/src/provider/` may need updates if they use any renamed hooks.

### 2.4 @privy-io/react-auth v2 → v3 Breaking Changes

- `PrivyClientConfig` type may have new required fields or renamed options
- `PrivyProvider` props may have changed
- `embeddedWallets` configuration shape may have changed
- `loginMethods` values may differ

**Affected template files:**
- `template/extras/config/privy.ts`
- `template/extras/src/provider/privy-provider.tsx`
- `template/extras/src/provider/privy-wagmi-provider.tsx`

### 2.5 @privy-io/wagmi v1 → v4 Breaking Changes

Peer dependencies from npm registry for v4.0.13:
- `@privy-io/react-auth: "^3"` (matches our privy v3 update)
- `wagmi: ">=2"` (works with both v2 and v3)
- `viem: "2.52.0"` (pin specific version)
- `react: ">=18"`

The `createConfig` and `WagmiProvider` API from `@privy-io/wagmi` need verification.

**Affected template files:**
- `template/extras/config/wagmi-privy.ts`
- `template/extras/src/provider/privy-wagmi-provider.tsx`

### 2.6 lucide-react v0 → v1 Breaking Changes

- Icon imports changed from named exports to default exports or different paths
- v0: `import { Activity } from "lucide-react"`
- v1: `import Activity from "lucide-react/dist/esm/icons/activity"` or tree-shakeable individual imports
- Dynamic icon imports API changed

**Affected template files:**
- Any component importing lucide icons (check `template/extras/src/app/components/connect.tsx` and `template/extras/src/pages/components/connect.tsx` variants)

---

## Phase 3: Base Template (Medium Risk)

File: `template/base/package.json`

### 3.1 Version Updates

| Package | Current | Target | Notes |
|---------|---------|--------|-------|
| `next` | `^15.5.2` | `^16.2.9` | Requires Node >=20.9.0 |
| `react` | `^19.2.0` | `^19.2.7` | Patch bump |
| `react-dom` | `^19.0.0` | `^19.2.7` | Match react version |
| `@types/react` | `^19.0.0` | `^19.2.7` | Match react version |
| `@types/react-dom` | `^19.2.0` | `^19.2.7` | Match react-dom version |
| `typescript` | `^5.9.3` | `^5.9.3` | Hold — TS 6.0.3 not needed yet |
| `@types/node` | `^24.7.1` | latest | Check latest |

### 3.2 Script Changes (Next.js 16)

Next.js 16 makes Turbopack the default. Remove `--turbopack` flags:

```diff
- "dev": "next dev --turbopack",
- "build": "next build --turbopack",
+ "dev": "next dev",
+ "build": "next build",
```

### 3.3 Next.js 16 Breaking Changes Summary

1. **Turbopack is default** — No need for `--turbopack` flag. If template uses custom webpack config, add `--webpack` flag.
2. **`next lint` removed** — Must use ESLint CLI directly. The `lint` script in the template should use `eslint .` instead of `next lint`.
3. **`middleware` → `proxy`** — Rename middleware file and functions in template if any exist.
4. **Async Request APIs** — `cookies()`, `headers()`, `params`, `searchParams` are now Promises. Template page/layout files need `await`.
5. **React 19.2** — Required by Next.js 16.
6. **`eslint-config-next`** — Must match Next.js 16 (`^16.x`). ESLint flat config is default.
7. **Minimum Node.js** — `20.9.0` (was 18.17.0).

---

## Phase 4: Template File Changes (High Risk)

### 4.1 Files Requiring Changes

| File | Change Needed | Reason |
|------|--------------|--------|
| `template/base/package.json` | Update versions, remove `--turbopack` | Next 16 + version bumps |
| `template/base/next.config.js` | Remove deprecated options if any | Next 16 |
| `template/extras/config/privy.ts` | `PrivyClientConfig` type update | Privy v3 |
| `template/extras/config/wagmi-privy.ts` | `createConfig` from `@privy-io/wagmi` v4 API | @privy-io/wagmi v4 |
| `template/extras/src/provider/privy-provider.tsx` | `PrivyProvider` API update | Privy v3 |
| `template/extras/src/provider/privy-wagmi-provider.tsx` | `PrivyProvider`/`WagmiProvider` from new packages | Privy v3 + @privy-io/wagmi v4 |
| `template/extras/src/app/layout/*.tsx` | `params` → `await params` | Next 16 async params |
| `template/extras/src/app/page/*.tsx` | `searchParams` → `await searchParams` | Next 16 async params |
| `template/extras/src/pages/_app/*.tsx` | No change (Pages Router not affected) | — |
| `template/extras/src/app/components/connect.tsx` | lucide-react v1 imports | lucide-react v1 |
| `template/extras/src/pages/components/connect.tsx` | lucide-react v1 imports | lucide-react v1 |
| `template/extras/config/_eslint.base.js` | Flat config updates, remove `next lint` | Next 16 + ESLint flat config |
| `template/extras/config/postcss.config.js` | Check for Tailwind v4 compatibility | Tailwind v4.3 |
| `template/extras/config/components.json` | Check for shadcn compatibility | May need update |
| `template/extras/src/styles/globals.css` | Check Tailwind v4.3 directives | Tailwind v4.3 |
| `template/extras/src/styles/shadcn-globals.css` | Check Tailwind v4.3 + shadcn | Tailwind v4.3 |
| `src/installers/eslint.ts` | `eslint-config-next` version, remove `next lint` scripts | Next 16 |
| `src/installers/privy.ts` | Package dependencies list, file copy logic | Privy v3 + @privy-io/wagmi v4 |
| `src/installers/wagmi.ts` | Package dependencies, config file paths | wagmi v3 |
| `src/installers/rainbow.ts` | Package dependencies | RainbowKit update |
| `src/installers/tailwind.ts` | Package dependencies | Tailwind v4.3 |
| `src/installers/shadcn.ts` | Package dependencies | shadcn/lucide updates |

### 4.2 Template Layout/Page Files — Async Params Migration

App Router layout and page files need `params` and `searchParams` to be awaited:

```tsx
// Before (Next 15):
export default function Layout({ children, params }: { children: React.ReactNode; params: { slug: string } }) {
  const { slug } = params
  // ...
}

// After (Next 16):
export default async function Layout({ children, params }: { children: React.ReactNode; params: Promise<{ slug: string }> }) {
  const { slug } = await params
  // ...
}
```

Multiple variants exist in:
- `template/extras/src/app/layout/` — 7 layout variants
- `template/extras/src/app/page/` — 7 page variants

Each variant must be checked and updated as needed.

### 4.3 eslint-config-next Update

Since Next.js 16 removed the `next lint` command, the template's `lint` script must change:

```diff
- "lint": "next lint",
- "lint:fix": "next lint --fix",
+ "lint": "eslint .",
+ "lint:fix": "eslint . --fix",
```

This is handled in `src/installers/eslint.ts`.

---

## Phase 5: CI/CD Workflow

File: `.github/workflows/release.yml`

### 5.1 Changes

| Setting | Current | Target | Reason |
|---------|---------|--------|--------|
| `node-version` | `20` | `22` | Next 16 requires Node >=20.9. LTS 22 is current |
| `pnpm/action-setup` version | `v2` | `v4` | Latest version |
| `actions/checkout` | `v4` | `v4` | Already latest |
| `actions/setup-node` | `v4` | `v4` | Already latest |
| pnpm version | `9` | `9` | Staying on pnpm 9 |

### 5.2 Required GitHub Secrets

| Secret | Purpose |
|--------|---------|
| `NPM_TOKEN` | Publish to npm registry |
| `GH_PAT` | Create GitHub Release |

---

## How to Run Locally

```bash
# 1. Install dependencies
pnpm install

# 2. Type-check the CLI source
pnpm typecheck

# 3. Lint the CLI source
pnpm lint

# 4. Build the CLI
pnpm build

# 5. Run the CLI and create a test project
# This will scaffold a full app in ../my-test-app
pnpm start ../my-test-app

# 6. Navigate to the test project
cd ../my-test-app

# 7. Install the generated project's dependencies
pnpm install

# 8. Run the generated dev server
pnpm dev
# Expected: Next.js dev server starts on http://localhost:3000

# 9. Type-check the generated project
pnpm typecheck
# Expected: No type errors

# 10. Build the generated project
pnpm build
# Expected: Successful production build
```

**Quick dev loop (CLI changes only):**

```bash
# Watch mode: rebuilds CLI on every change and auto-runs
pnpm dev
```

---

## How to Test

### Test Matrix

Since the CLI supports many combinations of options, test each major path:

| Test Case | Flags/Options | What to Verify |
|-----------|--------------|----------------|
| **Default** | `--default` | Tailwind + Privy installs, app builds |
| **Tailwind only** | Select Tailwind: yes, Shadcn: no, Auth: none, Wagmi: no | Tailwind works, no web3 packages |
| **Tailwind + Shadcn** | Tailwind: yes, Shadcn: yes, Auth: none | shadcn components work, lucide icons render |
| **Privy + Wagmi** | Auth: Privy, Wagmi: yes | Providers wrap correctly, env vars exist |
| **Rainbow Kit** | Auth: Rainbow Kit | RainbowKit+wagmi+viem installed, provider renders |
| **ESLint** | ESLint: yes | Config files created, scripts added, lint runs |
| **Biome** | Biome: yes | biome.jsonc created, scripts added |
| **App Router** | Router: App Router | layout.tsx exists (not _app.tsx) |
| **Pages Router** | Router: Pages Router | _app.tsx exists (not layout.tsx) |
| **No Git** | `--noGit` | No .git directory created |
| **No Install** | `--noInstall` | No node_modules, manual `pnpm install` works after |

### Automated Check

After scaffolding each test case:

```bash
cd <test-project>
pnpm typecheck   # Must pass
pnpm build       # Must pass
```

---

## How to Release

### 1. Create a Changeset

```bash
pnpm changeset
```

This interactively asks:
- Which packages changed (select `create-w3-app`)
- Type of bump: `major` | `minor` | `patch`
- Summary message

### 2. Version Bump

```bash
pnpm release
```

This runs `changeset version` which:
- Bumps the version in `package.json`
- Updates `CHANGELOG.md`
- Deletes consumed changeset files

### 3. Build and Publish

```bash
# Build the CLI
pnpm build

# Publish to npm (latest tag)
pnpm pub:release

# Or publish with tags:
pnpm pub:beta    # --tag beta
pnpm pub:next    # --tag next
```

### 4. GitHub Release

The GitHub release is created **automatically** on push to `main` via `.github/workflows/release.yml`:

1. Push to `main` triggers the workflow
2. Workflow checks if the version already exists on npm
3. If new: publishes to npm + creates GitHub Release from `CHANGELOG.md`

**Manual trigger:** Use `workflow_dispatch` in GitHub Actions UI.

### 5. Post-Release Checklist

- [ ] Verify package appears on [npmjs.com/package/create-w3-app](https://www.npmjs.com/package/create-w3-app)
- [ ] Verify GitHub Release created at [github.com/gopiinho/create-w3-app/releases](https://github.com/gopiinho/create-w3-app/releases)
- [ ] Test fresh install: `npx create-w3-app@latest test-project`
- [ ] Verify `npx create-w3-app@latest` resolves correctly
- [ ] Test scaffolded app: `cd test-project && pnpm install && pnpm build`

---

## Release Channels

| Channel | Command | npm Tag | Use Case |
|---------|---------|---------|----------|
| `latest` | `pnpm pub:release` | `latest` | Stable releases |
| `beta` | `pnpm pub:beta` | `beta` | Pre-release testing |
| `next` | `pnpm pub:next` | `next` | Canary/experimental |

Users install specific channels:
```bash
npx create-w3-app@latest    # stable
npx create-w3-app@beta      # beta
npx create-w3-app@next      # canary
```

---

## Risk Summary

| Phase | Risk Level | Breaking Changes | Rollback Safe? |
|-------|-----------|-----------------|----------------|
| Phase 1: CLI deps | Low | @clack/prompts v1 API | Yes — `pnpm install` revert |
| Phase 2: Version map | Mixed | wagmi v3, privy v3, lucide v1 | Partially — versions can be reverted in map |
| Phase 3: Base template | Medium | Next.js 16 async params | Yes — template file revert |
| Phase 4: Template files | **High** | All breaking changes combined | Complex — multiple files intertwined |
| Phase 5: CI/CD | Low | None | Yes — workflow file revert |

### Recommended Execution Order

1. **Phase 1 first** — Update CLI deps, rebuild, verify CLI still works
2. **Phase 2 (safe subset)** — Update non-breaking version map entries
3. **Phase 3** — Update base template versions and scripts
4. **Phase 4** — Update template files for each breaking change, one at a time:
   - a. Tailwind v4.3 (lowest risk)
   - b. Next.js 16 (async params, scripts, eslint config)
   - c. lucide-react v1 (icon imports in connect components)
   - d. wagmi v3 (config files, provider components)
   - e. privy v3 + @privy-io/wagmi v4 (config, provider, integration)
5. **Phase 5** — CI/CD updates

### After All Phases

1. Run `pnpm typecheck` — must pass
2. Run `pnpm lint` — must pass
3. Run `pnpm build` — must build successfully
4. Scaffold a test project with `pnpm start ../test-app`
5. In the test project: `pnpm install && pnpm typecheck && pnpm build` — all must pass
6. Create a changeset and release
