anhedral 0.1.6 → 0.1.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,74 +1,117 @@
1
- # anhedral
1
+ # Anhedral
2
2
 
3
- Opinionated init CLI for product teams shipping one stable stack: Expo + React Native Reusables, Fastify, WXT, Drizzle, Neon, Clerk, RevenueCat + Stripe, Cloudflare R2/CDN, and Vercel.
3
+ [![npm version](https://img.shields.io/npm/v/anhedral.svg)](https://www.npmjs.com/package/anhedral)
4
+ [![license](https://img.shields.io/npm/l/anhedral.svg)](./LICENSE)
5
+ [![node](https://img.shields.io/node/v/anhedral.svg)](https://www.npmjs.com/package/anhedral)
4
6
 
5
- ## Requirements
7
+ One command to start a production-shaped Expo, Fastify, and Chrome extension application.
6
8
 
7
- - Node.js 20+
8
- - `pnpm` available on your machine
9
+ Anhedral is an opinionated init CLI for teams that want one stable full-stack architecture instead of a menu of half-finished choices. It generates a single pnpm monorepo with an Expo app for web/iOS/Android, a Fastify API, a WXT Chrome extension, shared packages, and deployment-ready structure for Vercel, EAS, and the Chrome Web Store.
9
10
 
10
- ## Usage
11
+ ![Anhedral init CLI](docs/anhedral-cli-init.png)
11
12
 
12
- Run the latest published CLI directly without installing it globally:
13
+ ## Quick Start
13
14
 
14
15
  ```sh
15
16
  pnpm dlx anhedral@latest init
16
17
  ```
17
18
 
19
+ Or with npm:
20
+
18
21
  ```sh
19
22
  npx anhedral@latest init
20
23
  ```
21
24
 
22
- Use `--skip-install` when you want deterministic file generation without running dependency installation during init:
25
+ Use `--skip-install` when you want deterministic file generation before installing dependencies:
23
26
 
24
27
  ```sh
25
28
  pnpm dlx anhedral@latest init --skip-install
26
29
  pnpm install
27
30
  ```
28
31
 
29
- Global install also works:
32
+ ## What It Generates
30
33
 
31
- ```sh
32
- pnpm add -g anhedral@latest
33
- anhedral init
34
+ ```txt
35
+ .
36
+ ├─ Frontend/ Expo + React Native Reusables app
37
+ ├─ Backend/ Fastify API
38
+ ├─ Extension/ WXT Chrome extension
39
+ ├─ packages/
40
+ │ ├─ api-client/ shared typed API client
41
+ │ ├─ config/ shared config helpers
42
+ │ ├─ contracts/ shared Zod request/response contracts
43
+ │ ├─ db/ Drizzle schema, Neon client, migrations
44
+ │ └─ types/ shared TypeScript types
45
+ ├─ PRODUCTION.md deployment checklist
46
+ ├─ turbo.json workspace task graph
47
+ └─ package.json root scripts
34
48
  ```
35
49
 
36
- ```sh
37
- npm install -g anhedral@latest
38
- anhedral init
39
- ```
50
+ The generated app is intentionally one repository. Deploy the same Git repo as two Vercel projects:
51
+
52
+ - `Frontend`: Expo web export, built with `pnpm build:web`, output to `dist`
53
+ - `Backend`: Fastify API, built with `pnpm build`, entrypoint at `src/index.ts`
54
+
55
+ The same `Frontend` source is used for native iOS and Android builds through EAS. The `Extension` source builds a WXT Chrome extension ZIP for the Chrome Web Store.
40
56
 
41
57
  ## Stack
42
58
 
43
- `init` generates the only supported stack:
59
+ Anhedral supports one carefully maintained stack:
44
60
 
45
61
  - Expo + React Native Reusables frontend
46
62
  - Fastify backend
47
- - WXT extension
63
+ - WXT Chrome extension
48
64
  - Neon + Drizzle
49
65
  - Cloudflare R2/CDN
50
66
  - Clerk auth
51
67
  - RevenueCat + Stripe
52
- - Vercel deploy
68
+ - Vercel deployment
69
+ - pnpm workspaces + Turborepo
70
+
71
+ The goal is stability. The generated project avoids framework sprawl, duplicate schemas, and separate frontend/backend/extension repositories.
72
+
73
+ ## Why This Stack
74
+
75
+ Anhedral is built around one idea: a startup should be able to launch every major client from one repository without committing to infrastructure that becomes expensive, fragmented, or hard to change later.
53
76
 
54
- The scaffold is a pnpm workspace with top-level `Frontend`, `Backend`, `Extension`, and `packages/*` folders. Shared code such as the Drizzle schema lives under `packages/db` so apps do not need separate database schemas.
77
+ The stack is intentionally narrow:
55
78
 
56
- Each scaffold writes a `stack.json` file with the selected architecture, generated outputs, and the verified dependency manifest used for that run.
79
+ | Choice | Why Anhedral uses it |
80
+ | --- | --- |
81
+ | Expo | One React Native codebase targets web browsers, iOS, and Android. Compared with separate web and native apps, Expo keeps product iteration faster and avoids rebuilding shared screens, auth flows, and client logic three times. |
82
+ | React Native Reusables | It brings shadcn-style primitives to React Native and Expo without locking the app into a heavy design system. Compared with bespoke component scaffolds, it gives teams accessible primitives they can replace or extend as the product becomes specific. |
83
+ | Fastify | Fastify is small, fast, TypeScript-friendly, and works well as a central API layer on Vercel. Compared with pushing logic into many frontend routes, serverless functions, or client SDK calls, a Fastify backend centralizes auth, billing, storage, database access, webhooks, and internal APIs in one place. |
84
+ | TypeScript | The whole stack shares types, contracts, and API clients. Compared with untyped template code, this catches frontend/backend drift before deploy and makes the generated app safer to evolve. |
85
+ | Zod contracts | Request and response schemas live in shared packages. Compared with duplicating interfaces across clients, Zod lets the backend validate inputs while the frontend parses responses from the same source of truth. |
86
+ | Neon + Drizzle | Neon gives serverless Postgres that can start free and scale with usage; Drizzle keeps schema and queries close to TypeScript. Compared with proprietary document databases or opaque ORMs, this keeps the data layer portable, SQL-native, and easy to inspect. |
87
+ | Cloudflare R2/CDN | R2 provides S3-compatible object storage without S3-style egress fees. Compared with storing files in the database or coupling uploads to one app client, signed storage routes give every client the same upload/download primitive. |
88
+ | Clerk | Clerk handles modern auth across web, native, and extension clients. Compared with hand-rolled auth, it removes a high-risk surface area while still letting the backend own authorization decisions. |
89
+ | RevenueCat + Stripe | RevenueCat coordinates native subscriptions and Stripe web billing behind one entitlement model. Compared with separate payment implementations per platform, the backend can ask one question: what is this user allowed to access? |
90
+ | WXT | WXT gives the Chrome extension a modern TypeScript/Vite workflow and supports the Side Panel API. Compared with hand-maintained manifest scaffolds, it reduces extension build and packaging mistakes. |
91
+ | Vercel | Vercel deploys the Expo web app and Fastify API from the same Git repository with separate project roots. Compared with manually wiring CI/CD early, teams get preview deployments and production deploys from normal commits. |
57
92
 
58
- ## Vercel Deployment
93
+ Every part of the stack can be started on free tiers and scales automatically as traffic grows. That matters because the first production architecture should not force a team to choose between moving quickly and being able to handle success.
59
94
 
60
- The generated workspace is one Git repository with two Vercel projects:
95
+ The bigger advantage is architectural: Anhedral creates all target clients plus one backend that can serve internal and external requests. Product logic, auth decisions, subscription entitlements, storage access, database writes, and webhooks have a central home. That helps startups avoid the common failure mode where every client invents its own rules, and the team later cannot respond quickly when the product needs to shift.
61
96
 
62
- - `Frontend`: Expo web build. Build command: `pnpm build:web`. Output directory: `dist`.
63
- - `Backend`: Fastify API. Build command: `pnpm build`. Vercel detects `src/index.ts` as the Fastify entrypoint.
97
+ ## Local Development
64
98
 
65
- The `Frontend` source is also the EAS source for iOS and Android builds; Vercel only deploys its web export.
99
+ From the generated project root:
66
100
 
67
- Import the same repository twice in Vercel and set each project Root Directory to the app path above. Enable source access outside the app root so `packages/*` workspace dependencies are available during builds.
101
+ ```sh
102
+ pnpm install
103
+ pnpm dev
104
+ ```
68
105
 
69
- Vercel deployments are Git-driven. After both projects are connected, pushes and pull requests deploy the Expo web app and Fastify API automatically from GitHub commits.
106
+ Run one surface at a time:
70
107
 
71
- Generated projects also include `PRODUCTION.md` with the provider checklist and these root verification scripts:
108
+ ```sh
109
+ pnpm dev:frontend
110
+ pnpm dev:backend
111
+ pnpm dev:extension
112
+ ```
113
+
114
+ Verify before deployment:
72
115
 
73
116
  ```sh
74
117
  pnpm verify
@@ -77,98 +120,71 @@ pnpm verify:backend
77
120
  pnpm verify:extension
78
121
  ```
79
122
 
80
- ## Generated Provider Setup
123
+ Database workflow:
124
+
125
+ ```sh
126
+ pnpm db:generate
127
+ pnpm db:migrate
128
+ ```
129
+
130
+ ## Provider Setup
131
+
132
+ Generated projects include placeholder env values so the repository can be inspected before accounts are provisioned. Real auth, billing, uploads, native builds, and extension sign-in require provider keys.
81
133
 
82
- New projects ship with placeholder env values so the repository can be inspected before accounts are provisioned. A production UI requires real keys from each provider. The generated `README.md` and `PRODUCTION.md` now include setup links and exact env placement for:
134
+ The generated `README.md` and `PRODUCTION.md` explain where every key belongs:
83
135
 
84
- - Neon database: `DATABASE_URL`
85
- - Clerk auth: `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY`, `CLERK_PUBLISHABLE_KEY`, `CLERK_SECRET_KEY`, `VITE_CLERK_PUBLISHABLE_KEY`
136
+ - Neon: `DATABASE_URL`
137
+ - Clerk: `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY`, `CLERK_PUBLISHABLE_KEY`, `CLERK_SECRET_KEY`, `VITE_CLERK_PUBLISHABLE_KEY`
86
138
  - RevenueCat + Stripe: `EXPO_PUBLIC_RC_*`, `RC_SECRET_API_KEY`, `RC_WEBHOOK_SECRET`
87
139
  - Cloudflare R2/CDN: `R2_ACCOUNT_ID`, `R2_ACCESS_KEY_ID`, `R2_SECRET_ACCESS_KEY`, `R2_BUCKET`
88
- - Vercel: two projects from the same Git repo, rooted at `Frontend` and `Backend`
140
+ - Vercel: two projects from the same Git repository, rooted at `Frontend` and `Backend`
89
141
  - EAS: native iOS and Android builds from `Frontend`
90
142
  - Chrome Web Store: WXT ZIP upload from `Extension/.output`
91
143
 
92
- ## Native App Deployment
93
-
94
- Use `Frontend` as the Expo project root for iOS and Android. Vercel only deploys the web export from this app; native builds go through EAS.
95
-
96
- ```sh
97
- cd Frontend
98
- pnpm dlx eas-cli@latest login
99
- pnpm dlx eas-cli@latest init
100
- ```
144
+ ## Deployment
101
145
 
102
- The scaffold generates `Frontend/eas.json` with `development`, `preview`, and `production` profiles.
146
+ ### Vercel
103
147
 
104
- Build commands:
148
+ Import the same GitHub repository twice:
105
149
 
106
- ```sh
107
- # Android
108
- pnpm dlx eas-cli@latest build --platform android --profile production
150
+ | Project | Root Directory | Build Command | Output |
151
+ | --- | --- | --- | --- |
152
+ | Frontend | `Frontend` | `pnpm build:web` | `dist` |
153
+ | Backend | `Backend` | `pnpm build` | Fastify entrypoint |
109
154
 
110
- # iOS
111
- pnpm dlx eas-cli@latest build --platform ios --profile production
155
+ Enable Vercel access to source files outside each project root so workspace packages under `packages/*` resolve during builds.
112
156
 
113
- # Both platforms
114
- pnpm dlx eas-cli@latest build --platform all --profile production
115
- ```
157
+ ### EAS
116
158
 
117
- Submit latest successful builds to the stores:
159
+ Use `Frontend` as the Expo project root:
118
160
 
119
161
  ```sh
120
- # Google Play
121
- pnpm dlx eas-cli@latest submit --platform android --latest --profile production
122
-
123
- # App Store Connect / TestFlight
124
- pnpm dlx eas-cli@latest submit --platform ios --latest --profile production
125
-
126
- # Both platforms
162
+ cd Frontend
163
+ pnpm dlx eas-cli@latest login
164
+ pnpm dlx eas-cli@latest init
165
+ pnpm dlx eas-cli@latest build --platform all --profile production
127
166
  pnpm dlx eas-cli@latest submit --platform all --latest --profile production
128
167
  ```
129
168
 
130
- One-step build and submit:
131
-
132
- ```sh
133
- pnpm dlx eas-cli@latest build --platform android --profile production --auto-submit
134
- pnpm dlx eas-cli@latest build --platform ios --profile production --auto-submit
135
- pnpm dlx eas-cli@latest build --platform all --profile production --auto-submit
136
- ```
137
-
138
- Useful release checks:
169
+ ### Chrome Extension
139
170
 
140
171
  ```sh
141
- pnpm dlx eas-cli@latest build:list
142
- pnpm dlx eas-cli@latest build:version:get --platform all --profile production
143
- pnpm dlx eas-cli@latest credentials
172
+ pnpm extension:zip
144
173
  ```
145
174
 
146
- ## Extension Release
175
+ Upload `Extension/.output/*-chrome.zip` to the Chrome Web Store Developer Dashboard.
147
176
 
148
- The WXT extension is built from `Extension`. It is not deployed by Vercel.
149
-
150
- ```sh
151
- cd Extension
152
- pnpm build
153
- pnpm zip
154
- ```
177
+ ## Dependency Policy
155
178
 
156
- The Chrome ZIP is generated under `.output/`. Upload that ZIP in the Chrome Web Store Developer Dashboard:
179
+ `pnpm dlx anhedral@latest init` gives users the latest published Anhedral CLI, but generated projects use the dependency manifest verified for that release.
157
180
 
158
- 1. Open the Chrome Web Store Developer Dashboard.
159
- 2. Create the item the first time, or open the existing extension item.
160
- 3. Upload the generated Chrome ZIP.
161
- 4. Complete or update the store listing, screenshots, privacy practices, permissions justification, and distribution settings.
162
- 5. Submit the item for review.
181
+ Runtime dependency versions live in `src/dependencies.ts`. Generated projects also receive a `stack.json` file recording the exact stack and dependency manifest used for that init run.
163
182
 
164
- For automated store submissions later, WXT supports:
183
+ This keeps generated apps reproducible while still allowing Anhedral itself to move forward quickly through verified releases.
165
184
 
166
- ```sh
167
- pnpm wxt submit init
168
- pnpm wxt submit
169
- ```
185
+ ## Development
170
186
 
171
- ## Local Development
187
+ Work on the CLI locally:
172
188
 
173
189
  ```sh
174
190
  pnpm install
@@ -176,80 +192,29 @@ pnpm build
176
192
  pnpm test:all
177
193
  ```
178
194
 
179
- ## Publishing
180
-
181
- This package is published once to the npm registry. `pnpm`, `npm`, `yarn`, and `bun` users all install that same published package.
182
-
183
- Official releases are automatic on merges to `main`. GitHub Actions bumps the patch version, runs the release checks once, creates a release commit and tag, and publishes that version to npm.
184
-
185
- Recommended release flow:
195
+ Refresh the checked-in demo output:
186
196
 
187
197
  ```sh
188
- git push origin main
198
+ pnpm demo:refresh
189
199
  ```
190
200
 
191
- Release publishing is handled by:
192
-
193
- - `.github/workflows/release-on-main.yml`: runs on pushes to `main`, bumps `package.json`, verifies the repo, pushes a `v*.*.*` tag, and publishes to npm.
194
- - `.github/workflows/release.yml`: manual retry workflow for publishing the current checked-out package version.
195
-
196
- The repository is private, so npm provenance publishing is not supported. GitHub Actions publishes with `--provenance=false` and skips npm lifecycle scripts because `pnpm release:check` has already run. Configure an npm automation token as `NPM_TOKEN` in the `npm` GitHub environment or repository secrets.
197
-
198
- Manual local publish is still available as an emergency fallback:
201
+ Validate upstream scaffold drift:
199
202
 
200
203
  ```sh
201
- pnpm release:check
202
- npm publish --provenance=false --ignore-scripts
204
+ pnpm test:e2e:latest
203
205
  ```
204
206
 
205
- ## Maintenance
206
-
207
- This repo is maintained in two lanes:
208
-
209
- - `stable`: the default user-facing toolchain, pinned to known-good upstream CLI and package versions in `src/dependencies.ts`.
210
- - `latest`: an early-warning lane that tracks upstream scaffold tools without pinning, so breakage is detected before it reaches the default path.
211
-
212
- The practical rule is simple: users get the latest verified Anhedral release, not uncontrolled registry drift at init time. Detect drift on `latest`, verify it, then promote the pinned dependency manifest only after the e2e matrix passes.
213
-
214
- ### Dependency policy
215
-
216
- - Runtime dependency versions for generated projects live in `src/dependencies.ts`.
217
- - Generated package manifests and install commands must read from that manifest.
218
- - Avoid raw `@latest` and caret ranges in generated output unless a package manager or platform command explicitly requires it.
219
- - `pnpm dlx anhedral@latest init` means the newest published Anhedral CLI. The generated project should still be reproducible for that exact Anhedral version.
220
- - `stack.json` records the dependency manifest so support and debugging can identify exactly what was generated.
221
-
222
- ### Recommended automation
207
+ ## Release
223
208
 
224
- - Renovate is configured in `renovate.json` to keep this repo's own dependencies and generated dependency manifest current.
225
- - GitHub Actions CI runs on pushes and pull requests in `.github/workflows/ci.yml`.
226
- - Weekly toolchain drift checks run in `.github/workflows/toolchain-drift.yml` for both `stable` and `latest`.
227
- - Automatic releases publish through `.github/workflows/release-on-main.yml`; `.github/workflows/release.yml` is for manual retry only.
228
- - Stable dependency pins in `src/dependencies.ts` are annotated so Renovate can open PRs when upstream packages and scaffold CLIs publish updates.
229
- - `prepublishOnly` stays strict for manual local publishing. GitHub Actions skips npm lifecycle scripts during publish after running `pnpm release:check`.
209
+ Official releases are automatic on merges to `main`. The release workflow bumps the patch version, runs the release checks, creates a release commit and tag, and publishes to npm.
230
210
 
231
- ### Upgrade workflow
232
-
233
- Use this sequence when Renovate opens a dependency or toolchain PR:
234
-
235
- ```sh
236
- pnpm install --frozen-lockfile
237
- pnpm test
238
- pnpm test:e2e
239
- npm pack --dry-run
240
- ```
241
-
242
- If you want to validate upstream scaffold drift manually, use the explicit latest-lane script:
211
+ Manual fallback:
243
212
 
244
213
  ```sh
245
- pnpm test:e2e:latest
214
+ pnpm release:check
215
+ npm publish --provenance=false --ignore-scripts
246
216
  ```
247
217
 
248
- When a dependency pin PR passes and the generated outputs look good, update the `VERIFIED_AT` date in `src/dependencies.ts` and release normally.
249
-
250
- ### Release policy
218
+ ## License
251
219
 
252
- - Publish `patch` releases for scaffold fixes, dependency bumps, and safer defaults.
253
- - Publish `minor` releases for new stacks, new flags, or new generated capabilities.
254
- - Publish `major` releases for breaking CLI changes or incompatible generated-project structure changes.
255
- - Never publish from a dirty worktree.
220
+ MIT
@@ -13,6 +13,7 @@ export declare const TOOLCHAIN_DEPENDENCIES: {
13
13
  export declare const ROOT_DEPENDENCIES: DependencyGroup;
14
14
  export declare const SHARED_DB_DEPENDENCIES: DependencyGroup;
15
15
  export declare const SHARED_PACKAGE_DEPENDENCIES: DependencyGroup;
16
+ export declare const CONTRACTS_DEPENDENCIES: DependencyGroup;
16
17
  export declare const API_CLIENT_DEPENDENCIES: DependencyGroup;
17
18
  export declare const BACKEND_DEPENDENCIES: DependencyGroup;
18
19
  export declare const EXTENSION_DEPENDENCIES: DependencyGroup;
@@ -27,6 +28,7 @@ export declare function dependencyManifest(): {
27
28
  readonly wxt: "0.20.25";
28
29
  };
29
30
  root: DependencyGroup;
31
+ contracts: DependencyGroup;
30
32
  sharedDb: DependencyGroup;
31
33
  sharedPackages: DependencyGroup;
32
34
  backend: DependencyGroup;
@@ -40,15 +40,25 @@ export const SHARED_PACKAGE_DEPENDENCIES = {
40
40
  typescript: '5.9.3',
41
41
  },
42
42
  };
43
+ export const CONTRACTS_DEPENDENCIES = {
44
+ dependencies: {
45
+ // renovate: datasource=npm depName=zod
46
+ zod: '4.2.1',
47
+ },
48
+ ...SHARED_PACKAGE_DEPENDENCIES,
49
+ };
43
50
  export const API_CLIENT_DEPENDENCIES = {
44
51
  dependencies: {
45
52
  '@anhedral/config': 'workspace:*',
53
+ '@anhedral/contracts': 'workspace:*',
46
54
  '@anhedral/types': 'workspace:*',
55
+ zod: CONTRACTS_DEPENDENCIES.dependencies.zod,
47
56
  },
48
57
  ...SHARED_PACKAGE_DEPENDENCIES,
49
58
  };
50
59
  export const BACKEND_DEPENDENCIES = {
51
60
  dependencies: {
61
+ '@anhedral/contracts': 'workspace:*',
52
62
  '@anhedral/db': 'workspace:*',
53
63
  // renovate: datasource=npm depName=fastify
54
64
  fastify: '5.6.2',
@@ -81,6 +91,7 @@ export const BACKEND_DEPENDENCIES = {
81
91
  // renovate: datasource=npm depName=@aws-sdk/s3-request-presigner
82
92
  '@aws-sdk/s3-request-presigner': '3.1047.0',
83
93
  dotenv: SHARED_DB_DEPENDENCIES.dependencies.dotenv,
94
+ zod: CONTRACTS_DEPENDENCIES.dependencies.zod,
84
95
  },
85
96
  devDependencies: {
86
97
  typescript: SHARED_DB_DEPENDENCIES.devDependencies.typescript,
@@ -164,6 +175,7 @@ export function dependencyManifest() {
164
175
  packageManager: PACKAGE_MANAGER,
165
176
  toolchain: TOOLCHAIN_DEPENDENCIES,
166
177
  root: ROOT_DEPENDENCIES,
178
+ contracts: CONTRACTS_DEPENDENCIES,
167
179
  sharedDb: SHARED_DB_DEPENDENCIES,
168
180
  sharedPackages: SHARED_PACKAGE_DEPENDENCIES,
169
181
  backend: BACKEND_DEPENDENCIES,