anhedral 0.1.4 → 0.1.6

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
@@ -51,7 +51,7 @@ anhedral init
51
51
  - RevenueCat + Stripe
52
52
  - Vercel deploy
53
53
 
54
- The scaffold is a pnpm workspace with `apps/*` and `packages/*`. Shared code such as the Drizzle schema lives under `packages/db` so apps do not need separate database schemas.
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.
55
55
 
56
56
  Each scaffold writes a `stack.json` file with the selected architecture, generated outputs, and the verified dependency manifest used for that run.
57
57
 
@@ -59,26 +59,48 @@ Each scaffold writes a `stack.json` file with the selected architecture, generat
59
59
 
60
60
  The generated workspace is one Git repository with two Vercel projects:
61
61
 
62
- - `apps/frontend`: Expo web build. Build command: `pnpm build:web`. Output directory: `dist`.
63
- - `apps/api`: Fastify API. Build command: `pnpm build`. Requests rewrite to `api/index.ts`.
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.
64
64
 
65
- The `apps/frontend` source is also the EAS source for iOS and Android builds; Vercel only deploys its web export.
65
+ The `Frontend` source is also the EAS source for iOS and Android builds; Vercel only deploys its web export.
66
66
 
67
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.
68
68
 
69
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.
70
70
 
71
+ Generated projects also include `PRODUCTION.md` with the provider checklist and these root verification scripts:
72
+
73
+ ```sh
74
+ pnpm verify
75
+ pnpm verify:frontend
76
+ pnpm verify:backend
77
+ pnpm verify:extension
78
+ ```
79
+
80
+ ## Generated Provider Setup
81
+
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:
83
+
84
+ - Neon database: `DATABASE_URL`
85
+ - Clerk auth: `EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY`, `CLERK_PUBLISHABLE_KEY`, `CLERK_SECRET_KEY`, `VITE_CLERK_PUBLISHABLE_KEY`
86
+ - RevenueCat + Stripe: `EXPO_PUBLIC_RC_*`, `RC_SECRET_API_KEY`, `RC_WEBHOOK_SECRET`
87
+ - 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`
89
+ - EAS: native iOS and Android builds from `Frontend`
90
+ - Chrome Web Store: WXT ZIP upload from `Extension/.output`
91
+
71
92
  ## Native App Deployment
72
93
 
73
- Use `apps/frontend` as the Expo project root for iOS and Android. Vercel only deploys the web export from this app; native builds go through EAS.
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.
74
95
 
75
96
  ```sh
76
- cd apps/frontend
97
+ cd Frontend
77
98
  pnpm dlx eas-cli@latest login
78
99
  pnpm dlx eas-cli@latest init
79
- pnpm dlx eas-cli@latest build:configure
80
100
  ```
81
101
 
102
+ The scaffold generates `Frontend/eas.json` with `development`, `preview`, and `production` profiles.
103
+
82
104
  Build commands:
83
105
 
84
106
  ```sh
@@ -123,10 +145,10 @@ pnpm dlx eas-cli@latest credentials
123
145
 
124
146
  ## Extension Release
125
147
 
126
- The WXT extension is built from `apps/extension`. It is not deployed by Vercel.
148
+ The WXT extension is built from `Extension`. It is not deployed by Vercel.
127
149
 
128
150
  ```sh
129
- cd apps/extension
151
+ cd Extension
130
152
  pnpm build
131
153
  pnpm zip
132
154
  ```
@@ -91,8 +91,6 @@ export const BACKEND_DEPENDENCIES = {
91
91
  vitest: '4.0.16',
92
92
  // renovate: datasource=npm depName=@vitest/coverage-v8
93
93
  '@vitest/coverage-v8': '4.0.16',
94
- // renovate: datasource=npm depName=@vercel/node
95
- '@vercel/node': '5.5.13',
96
94
  // renovate: datasource=npm depName=eslint
97
95
  eslint: '9.39.2',
98
96
  // renovate: datasource=npm depName=@eslint/js
@@ -144,8 +142,8 @@ export const EXTENSION_DEPENDENCIES = {
144
142
  };
145
143
  export const FRONTEND_ADDON_DEPENDENCIES = {
146
144
  '@anhedral/api-client': 'workspace:*',
147
- // renovate: datasource=npm depName=@clerk/clerk-expo
148
- '@clerk/clerk-expo': '2.19.31',
145
+ // renovate: datasource=npm depName=@clerk/expo
146
+ '@clerk/expo': '3.2.11',
149
147
  // renovate: datasource=npm depName=react-native-purchases
150
148
  'react-native-purchases': '10.1.1',
151
149
  // renovate: datasource=npm depName=react-native-purchases-ui
package/dist/scaffold.js CHANGED
@@ -147,25 +147,71 @@ ${generatedPaths}
147
147
  \`\`\`bash
148
148
  pnpm install
149
149
  cp .env.example .env
150
- # apps/frontend/.env is generated for local Expo development
151
- cp apps/extension/.env.example apps/extension/.env
150
+ # Frontend/.env is generated for local Expo development
151
+ cp Extension/.env.example Extension/.env
152
152
  pnpm db:generate
153
153
  pnpm db:migrate
154
- pnpm dev:api
154
+ pnpm verify
155
+ pnpm dev:backend
155
156
  pnpm dev:frontend
156
157
  pnpm dev:extension
157
158
  \`\`\`
158
159
 
159
- For a provider-free smoke test, keep \`ANHEDRAL_DEMO=true\` in \`apps/api/.env\`. Demo mode returns a signed-in sample user and active subscription responses without Clerk, RevenueCat, or Stripe credentials. It is for local development only.
160
+ The generated env files intentionally contain placeholder provider values. That is enough to inspect the project structure and run backend smoke tests, but the full UI needs real provider keys before auth, billing, uploads, and extension sign-in behave like production.
161
+
162
+ For a provider-free backend smoke test, keep \`ANHEDRAL_DEMO=true\` in \`Backend/.env\`. Demo mode returns a signed-in sample user and active subscription responses without Clerk, RevenueCat, or Stripe credentials. It is for local development only.
160
163
 
161
164
  ## Provider Setup
162
165
 
163
- - Neon: create a Postgres database and set \`DATABASE_URL\` in the root and API env files.
164
- - Clerk: create an application, configure allowed origins, and set \`CLERK_PUBLISHABLE_KEY\`, \`CLERK_SECRET_KEY\`, plus the Expo and extension publishable keys.
165
- - RevenueCat + Stripe: create an entitlement named \`pro\`, configure Stripe as a RevenueCat web billing source, configure app keys, then set \`RC_SECRET_API_KEY\`, \`RC_WEBHOOK_SECRET\`, and the \`EXPO_PUBLIC_RC_*\` values.
166
- - Cloudflare R2: create a bucket and API token, then set \`R2_ACCOUNT_ID\`, \`R2_ACCESS_KEY_ID\`, \`R2_SECRET_ACCESS_KEY\`, and \`R2_BUCKET\`.
167
- - Vercel: import this same Git repository twice. Use \`apps/frontend\` as the root directory for the Expo web project, and \`apps/api\` as the root directory for the Fastify API project. Enable access to source files outside each root directory so workspace packages under \`packages/*\` are available during builds.
168
- - EAS: use \`apps/frontend\` as the Expo project root for iOS and Android builds. Vercel deploys the web export from the same source.
166
+ Use this order so each service has the domains and callback URLs it needs:
167
+
168
+ 1. Neon database
169
+ - Create a Neon project and database: https://neon.com/docs/get-started-with-neon/connect-neon
170
+ - Put the pooled connection string in \`DATABASE_URL\` in \`.env\`, \`Backend/.env\`, and the Backend Vercel project.
171
+ - Run \`pnpm db:generate\` and \`pnpm db:migrate\` after \`DATABASE_URL\` is real.
172
+
173
+ 2. Clerk auth
174
+ - Expo setup: https://docs.expo.dev/guides/using-clerk/
175
+ - Clerk Expo quickstart: https://clerk.com/docs/quickstarts/get-started-with-expo
176
+ - Set \`EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY\` in \`Frontend/.env\`, Vercel Frontend, and EAS.
177
+ - Set \`CLERK_PUBLISHABLE_KEY\` and \`CLERK_SECRET_KEY\` in \`Backend/.env\` and Vercel Backend.
178
+ - Set \`VITE_CLERK_PUBLISHABLE_KEY\` in \`Extension/.env\`.
179
+ - Add allowed origins for \`http://localhost:8081\`, the Frontend Vercel domain, and the extension origin after Chrome assigns an extension id.
180
+
181
+ 3. RevenueCat + Stripe
182
+ - RevenueCat Web overview: https://www.revenuecat.com/docs/web/overview
183
+ - RevenueCat Stripe Billing integration: https://www.revenuecat.com/docs/web/integrations/stripe
184
+ - Stripe API keys: https://docs.stripe.com/keys
185
+ - Create an entitlement named \`pro\`.
186
+ - Create iOS, Android, and Web apps in RevenueCat and copy their public SDK keys into \`EXPO_PUBLIC_RC_API_KEY_IOS\`, \`EXPO_PUBLIC_RC_API_KEY_ANDROID\`, and \`EXPO_PUBLIC_RC_WEB_API_KEY\`.
187
+ - Set \`EXPO_PUBLIC_RC_ENTITLEMENT_ID=pro\`.
188
+ - Set \`RC_SECRET_API_KEY\` and \`RC_WEBHOOK_SECRET\` only in Backend envs.
189
+ - Point the RevenueCat webhook to \`https://<backend-domain>/webhooks/revenuecat\`.
190
+
191
+ 4. Cloudflare R2/CDN
192
+ - R2 S3-compatible setup: https://developers.cloudflare.com/r2/get-started/s3/
193
+ - R2 API tokens: https://developers.cloudflare.com/r2/api/tokens/
194
+ - Create a bucket and least-privilege API token.
195
+ - Set \`R2_ACCOUNT_ID\`, \`R2_ACCESS_KEY_ID\`, \`R2_SECRET_ACCESS_KEY\`, and \`R2_BUCKET\` only in Backend envs.
196
+ - If you use a public CDN/custom domain for uploaded files, add that URL to your own app config before exposing uploads broadly.
197
+
198
+ 5. Vercel web/API deploys
199
+ - Monorepo docs: https://vercel.com/docs/monorepos
200
+ - Monorepo FAQ for source outside root: https://vercel.com/docs/monorepos/monorepo-faq
201
+ - Import this same Git repository twice. Use \`Frontend\` as the root directory for the Expo web project and \`Backend\` as the root directory for the Fastify API project.
202
+ - Enable access to source files outside each project root so workspace packages under \`packages/*\` are available during builds.
203
+ - Frontend build command: \`pnpm build:web\`; output directory: \`dist\`.
204
+ - Backend build command: \`pnpm build\`; Vercel detects \`Backend/src/index.ts\` as the Fastify entrypoint.
205
+
206
+ 6. EAS native app builds
207
+ - EAS docs: https://docs.expo.dev/eas/
208
+ - Store submission docs: https://docs.expo.dev/deploy/submit-to-app-stores/
209
+ - Use \`Frontend\` as the Expo project root for iOS and Android builds. Vercel deploys the web export from the same source.
210
+
211
+ 7. Chrome Web Store
212
+ - WXT publishing: https://wxt.dev/guide/essentials/publishing.html
213
+ - Chrome publishing: https://developer.chrome.com/docs/webstore/publish
214
+ - Build with \`pnpm extension:zip\`, then upload \`Extension/.output/*-chrome.zip\` in the Chrome Web Store Developer Dashboard.
169
215
 
170
216
  ## Setup Notes
171
217
 
@@ -173,14 +219,24 @@ For a provider-free smoke test, keep \`ANHEDRAL_DEMO=true\` in \`apps/api/.env\`
173
219
  2. Review \`install-skills.sh\` and run the listed skill commands manually so you can choose scope and agent targets.
174
220
  3. Add the real provider configuration for Clerk, RevenueCat, Stripe web billing, Neon, and R2 where the scaffolded helper files indicate.
175
221
  4. Use \`stack.json\` when debugging generated projects; it records the verified dependency manifest used by this init run.
176
- 5. Run database generation and migrations from the shared DB package:
222
+ 5. Review \`PRODUCTION.md\` before connecting live provider projects.
223
+ 6. Run database generation and migrations from the shared DB package:
177
224
 
178
225
  \`\`\`bash
179
226
  pnpm db:generate
180
227
  pnpm db:migrate
181
228
  \`\`\`
182
229
 
183
- 6. Build or run the extension separately. It is not deployed by Vercel:
230
+ Run deployment readiness checks before pushing:
231
+
232
+ \`\`\`bash
233
+ pnpm verify
234
+ pnpm verify:frontend
235
+ pnpm verify:backend
236
+ pnpm verify:extension
237
+ \`\`\`
238
+
239
+ 7. Build or run the extension separately. It is not deployed by Vercel:
184
240
 
185
241
  \`\`\`bash
186
242
  pnpm dev:extension
@@ -188,6 +244,248 @@ pnpm extension:zip
188
244
  \`\`\`
189
245
  `);
190
246
  }
247
+ function writeProductionGuide(root, options) {
248
+ writeFile(path.join(root, 'PRODUCTION.md'), `# ${options.displayName} Production Guide
249
+
250
+ ## Project Structure
251
+
252
+ The generated app is one pnpm monorepo:
253
+
254
+ \`\`\`txt
255
+ .
256
+ ├─ Frontend/ Expo + React Native Reusables app
257
+ ├─ Backend/ Fastify API
258
+ ├─ Extension/ WXT Chrome extension
259
+ ├─ packages/
260
+ │ ├─ api-client/ shared typed API client
261
+ │ ├─ config/ shared config constants/helpers
262
+ │ ├─ db/ Drizzle schema, Neon client, migrations
263
+ │ └─ types/ shared TypeScript types
264
+ ├─ PRODUCTION.md development and deployment guide
265
+ ├─ turbo.json workspace build graph
266
+ └─ package.json root scripts
267
+ \`\`\`
268
+
269
+ ## Frontend
270
+
271
+ \`Frontend\` is the single Expo source for:
272
+
273
+ - Web on Vercel
274
+ - iOS through EAS
275
+ - Android through EAS
276
+
277
+ Important files:
278
+
279
+ - \`Frontend/package.json\`: Expo scripts
280
+ - \`Frontend/vercel.json\`: Vercel web export config
281
+ - \`Frontend/eas.json\`: native build profiles
282
+ - \`Frontend/app\`: Expo Router screens
283
+
284
+ Build output goes to \`Frontend/dist\`.
285
+
286
+ ## Backend
287
+
288
+ \`Backend\` is the Fastify API.
289
+
290
+ Important files:
291
+
292
+ - \`Backend/src/index.ts\`: Vercel Fastify entrypoint
293
+ - \`Backend/src/app.ts\`: Fastify app construction
294
+ - \`Backend/vercel.json\`: minimal Vercel config
295
+ - \`Backend/src/routes\`: health/auth/subscription routes
296
+
297
+ ## Extension
298
+
299
+ \`Extension\` is the WXT Chrome extension using the Side Panel API.
300
+
301
+ Important files:
302
+
303
+ - \`Extension/wxt.config.ts\`: manifest, side panel, permissions
304
+ - \`Extension/src/entrypoints/sidepanel\`: side panel UI
305
+ - \`Extension/src/entrypoints/background.ts\`: side panel behavior
306
+
307
+ ZIP output goes to \`Extension/.output\`.
308
+
309
+ ## Develop
310
+
311
+ From the repository root:
312
+
313
+ \`\`\`sh
314
+ pnpm install
315
+ pnpm dev
316
+ \`\`\`
317
+
318
+ Or run one surface at a time:
319
+
320
+ \`\`\`sh
321
+ pnpm dev:frontend
322
+ pnpm dev:backend
323
+ pnpm dev:extension
324
+ \`\`\`
325
+
326
+ Use these before deploy:
327
+
328
+ \`\`\`sh
329
+ pnpm verify
330
+ pnpm verify:frontend
331
+ pnpm verify:backend
332
+ pnpm verify:extension
333
+ \`\`\`
334
+
335
+ Database workflow:
336
+
337
+ \`\`\`sh
338
+ pnpm db:generate
339
+ pnpm db:migrate
340
+ \`\`\`
341
+
342
+ Local demo mode is enabled through generated \`.env\` files. Real provider behavior needs Clerk, RevenueCat/Stripe, Neon, and R2 credentials.
343
+
344
+ The generated placeholder values are intentionally non-production. They let you inspect files and run backend demo checks, but browser auth, paid subscriptions, uploads, and extension sign-in require the setup below.
345
+
346
+ ## Environment Variables
347
+
348
+ - Root/local: \`DATABASE_URL\` for shared Drizzle commands.
349
+ - Frontend/Vercel Frontend: only \`EXPO_PUBLIC_*\` values.
350
+ - Backend/Vercel Backend: server secrets such as \`DATABASE_URL\`, \`CLERK_SECRET_KEY\`, \`RC_SECRET_API_KEY\`, \`RC_WEBHOOK_SECRET\`, and R2 credentials.
351
+ - Extension: \`VITE_API_URL\`, \`VITE_CLERK_PUBLISHABLE_KEY\`, and optionally \`VITE_CRX_PUBLIC_KEY\`.
352
+ - EAS: add native app public keys with \`eas secret:create\` or the EAS dashboard.
353
+
354
+ ## Provider Setup
355
+
356
+ ### Neon + Drizzle
357
+
358
+ Docs:
359
+
360
+ - https://neon.com/docs/get-started-with-neon/connect-neon
361
+ - https://orm.drizzle.team/docs/tutorials/drizzle-with-neon
362
+
363
+ Steps:
364
+
365
+ 1. Create a Neon project and Postgres database.
366
+ 2. Copy the pooled connection string.
367
+ 3. Set \`DATABASE_URL\` in the root \`.env\`, \`Backend/.env\`, and the Backend Vercel project.
368
+ 4. Run:
369
+
370
+ \`\`\`sh
371
+ pnpm db:generate
372
+ pnpm db:migrate
373
+ \`\`\`
374
+
375
+ ### Clerk
376
+
377
+ Docs:
378
+
379
+ - https://docs.expo.dev/guides/using-clerk/
380
+ - https://clerk.com/docs/quickstarts/get-started-with-expo
381
+
382
+ Steps:
383
+
384
+ 1. Create a Clerk application.
385
+ 2. Set \`EXPO_PUBLIC_CLERK_PUBLISHABLE_KEY\` in \`Frontend/.env\`, the Frontend Vercel project, and EAS.
386
+ 3. Set \`CLERK_PUBLISHABLE_KEY\` and \`CLERK_SECRET_KEY\` in \`Backend/.env\` and the Backend Vercel project.
387
+ 4. Set \`VITE_CLERK_PUBLISHABLE_KEY\` in \`Extension/.env\`.
388
+ 5. Add allowed origins for local Expo web, the deployed Frontend Vercel domain, and the Chrome extension origin after the extension id is stable.
389
+ 6. Configure native redirect/deep-link settings for the Expo scheme in \`Frontend/app.json\`.
390
+
391
+ ### RevenueCat + Stripe
392
+
393
+ Docs:
394
+
395
+ - https://www.revenuecat.com/docs/web/overview
396
+ - https://www.revenuecat.com/docs/web/integrations/stripe
397
+ - https://docs.stripe.com/keys
398
+
399
+ Steps:
400
+
401
+ 1. Create the RevenueCat project.
402
+ 2. Create an entitlement named \`pro\`.
403
+ 3. Create iOS, Android, and Web apps in RevenueCat.
404
+ 4. Copy the public SDK keys into \`EXPO_PUBLIC_RC_API_KEY_IOS\`, \`EXPO_PUBLIC_RC_API_KEY_ANDROID\`, and \`EXPO_PUBLIC_RC_WEB_API_KEY\`.
405
+ 5. Set \`EXPO_PUBLIC_RC_ENTITLEMENT_ID=pro\`.
406
+ 6. Connect Stripe as the RevenueCat web billing source.
407
+ 7. Set \`RC_SECRET_API_KEY\` and \`RC_WEBHOOK_SECRET\` only in Backend envs.
408
+ 8. Configure the RevenueCat webhook URL as \`https://<backend-domain>/webhooks/revenuecat\`.
409
+
410
+ ### Cloudflare R2/CDN
411
+
412
+ Docs:
413
+
414
+ - https://developers.cloudflare.com/r2/get-started/s3/
415
+ - https://developers.cloudflare.com/r2/api/tokens/
416
+
417
+ Steps:
418
+
419
+ 1. Create an R2 bucket.
420
+ 2. Create a least-privilege API token for that bucket.
421
+ 3. Set \`R2_ACCOUNT_ID\`, \`R2_ACCESS_KEY_ID\`, \`R2_SECRET_ACCESS_KEY\`, and \`R2_BUCKET\` only in Backend envs.
422
+ 4. Configure a public bucket URL or custom domain if uploaded assets need public CDN delivery.
423
+
424
+ ## Deploy
425
+
426
+ Vercel deployment is two Vercel projects from the same Git repo:
427
+
428
+ 1. Frontend Vercel project
429
+ - Root Directory: \`Frontend\`
430
+ - Build command: \`pnpm build:web\`
431
+ - Output directory: \`dist\`
432
+
433
+ 2. Backend Vercel project
434
+ - Root Directory: \`Backend\`
435
+ - Build command: \`pnpm build\`
436
+ - Fastify entrypoint: \`src/index.ts\`
437
+
438
+ Enable Vercel access to source files outside each project root so \`packages/*\` workspace packages resolve.
439
+
440
+ Native app deployment:
441
+
442
+ \`\`\`sh
443
+ cd Frontend
444
+ pnpm dlx eas-cli@latest login
445
+ pnpm dlx eas-cli@latest init
446
+ pnpm dlx eas-cli@latest build --platform all --profile production
447
+ pnpm dlx eas-cli@latest submit --platform all --latest --profile production
448
+ \`\`\`
449
+
450
+ Chrome extension deployment:
451
+
452
+ \`\`\`sh
453
+ pnpm extension:zip
454
+ \`\`\`
455
+
456
+ Upload \`Extension/.output/*-chrome.zip\` to the Chrome Web Store Developer Dashboard.
457
+
458
+ ## Production Checklist
459
+
460
+ - Replace every \`*_placeholder\` value before production deploy.
461
+ - Keep server secrets out of Frontend, Extension, and EAS public envs.
462
+ - Confirm Clerk works on local web, Vercel web, iOS, Android, and the Chrome extension.
463
+ - Confirm RevenueCat returns the \`pro\` entitlement after Stripe web purchase and native store purchase.
464
+ - Confirm \`pnpm db:migrate\` has run against the production Neon database.
465
+ - Confirm R2 upload and signed avatar URL retrieval work from the deployed Backend domain.
466
+ - Confirm both Vercel projects can resolve \`packages/*\` workspace packages.
467
+ - Confirm the Chrome extension ZIP is tested locally with \`chrome://extensions\` before Chrome Web Store upload.
468
+
469
+ ## Relevant Docs
470
+
471
+ - [Vercel monorepos](https://vercel.com/docs/monorepos)
472
+ - [Vercel monorepo FAQ](https://vercel.com/docs/monorepos/monorepo-faq)
473
+ - [Expo web publishing](https://docs.expo.dev/guides/publishing-websites/)
474
+ - [Expo EAS](https://docs.expo.dev/eas/)
475
+ - [Expo store submissions](https://docs.expo.dev/deploy/submit-to-app-stores/)
476
+ - [Clerk with Expo](https://docs.expo.dev/guides/using-clerk/)
477
+ - [Clerk Expo quickstart](https://clerk.com/docs/quickstarts/get-started-with-expo)
478
+ - [Neon connection strings](https://neon.com/docs/get-started-with-neon/connect-neon)
479
+ - [Drizzle with Neon](https://orm.drizzle.team/docs/tutorials/drizzle-with-neon)
480
+ - [RevenueCat Web](https://www.revenuecat.com/docs/web/overview)
481
+ - [RevenueCat Stripe Billing](https://www.revenuecat.com/docs/web/integrations/stripe)
482
+ - [Stripe API keys](https://docs.stripe.com/keys)
483
+ - [Cloudflare R2 S3 API](https://developers.cloudflare.com/r2/get-started/s3/)
484
+ - [Cloudflare R2 API tokens](https://developers.cloudflare.com/r2/api/tokens/)
485
+ - [WXT publishing](https://wxt.dev/guide/essentials/publishing.html)
486
+ - [Chrome Web Store publishing](https://developer.chrome.com/docs/webstore/publish)
487
+ `);
488
+ }
191
489
  function writeStackFile(root, stack) {
192
490
  writeFile(path.join(root, 'stack.json'), JSON.stringify(stack, null, 2) + '\n');
193
491
  }
@@ -755,9 +1053,9 @@ R2_BUCKET=
755
1053
  ${paymentsEnv}`);
756
1054
  }
757
1055
  function writeRootVercelFiles(root) {
758
- writeFile(path.join(root, '.vercelignore'), `apps/extension/.output
759
- apps/extension/.wxt
760
- apps/extension/dist
1056
+ writeFile(path.join(root, '.vercelignore'), `Extension/.output
1057
+ Extension/.wxt
1058
+ Extension/dist
761
1059
  `);
762
1060
  }
763
1061
  function writeGeneratedCiWorkflow(root) {
@@ -799,22 +1097,22 @@ jobs:
799
1097
  run: pnpm install --frozen-lockfile
800
1098
 
801
1099
  - name: Check Expo dependency alignment
802
- run: pnpm --filter ./apps/frontend exec expo install --check
1100
+ run: pnpm --filter ./Frontend exec expo install --check
803
1101
 
804
1102
  - name: Build Expo web
805
- run: pnpm --filter ./apps/frontend build:web
1103
+ run: pnpm --filter ./Frontend build:web
806
1104
 
807
1105
  - name: Test API
808
- run: pnpm --filter ./apps/api test
1106
+ run: pnpm --filter ./Backend test
809
1107
 
810
1108
  - name: Build API
811
- run: pnpm --filter ./apps/api build
1109
+ run: pnpm --filter ./Backend build
812
1110
 
813
1111
  - name: Build extension
814
- run: pnpm --filter ./apps/extension build
1112
+ run: pnpm --filter ./Extension build
815
1113
 
816
1114
  - name: Zip extension
817
- run: pnpm --filter ./apps/extension zip
1115
+ run: pnpm --filter ./Extension zip
818
1116
 
819
1117
  - name: Build workspace
820
1118
  run: pnpm build
@@ -822,32 +1120,36 @@ jobs:
822
1120
  }
823
1121
  function writeFullstackRootFiles(root, options) {
824
1122
  const appFilters = [
825
- './apps/frontend',
826
- './apps/api',
827
- './apps/extension',
1123
+ './Frontend',
1124
+ './Backend',
1125
+ './Extension',
828
1126
  ];
829
1127
  const parallelFilters = appFilters.map((entry) => `--filter=${entry}`).join(' ');
830
1128
  const scripts = {
831
1129
  dev: `turbo dev --parallel ${parallelFilters}`,
832
- 'dev:api': 'pnpm --filter ./apps/api dev',
1130
+ 'dev:backend': 'pnpm --filter ./Backend dev',
833
1131
  build: 'turbo build',
834
1132
  typecheck: 'turbo typecheck',
1133
+ verify: 'pnpm verify:frontend && pnpm verify:backend && pnpm verify:extension',
1134
+ 'verify:frontend': 'pnpm --filter ./Frontend exec expo install --check && pnpm --filter ./Frontend build:web',
1135
+ 'verify:backend': 'pnpm --filter ./Backend test && pnpm --filter ./Backend build',
1136
+ 'verify:extension': 'pnpm --filter ./Extension typecheck && pnpm --filter ./Extension zip',
835
1137
  'db:generate': 'pnpm --filter @anhedral/db db:generate',
836
1138
  'db:migrate': 'pnpm --filter @anhedral/db db:migrate',
837
1139
  };
838
- scripts['dev:frontend'] = 'pnpm --filter ./apps/frontend dev';
839
- scripts['dev:extension'] = 'pnpm --filter ./apps/extension dev';
840
- scripts['extension:zip'] = 'pnpm --filter ./apps/extension zip';
841
- writeRootPackageJson(root, options.projectName, scripts, ['apps/*', 'packages/*'], {
1140
+ scripts['dev:frontend'] = 'pnpm --filter ./Frontend dev';
1141
+ scripts['dev:extension'] = 'pnpm --filter ./Extension dev';
1142
+ scripts['extension:zip'] = 'pnpm --filter ./Extension zip';
1143
+ writeRootPackageJson(root, options.projectName, scripts, ['Frontend', 'Backend', 'Extension', 'packages/*'], {
842
1144
  devDependencies: ROOT_DEPENDENCIES.devDependencies,
843
1145
  });
844
- writePnpmWorkspace(root, ['apps/*', 'packages/*']);
1146
+ writePnpmWorkspace(root, ['Frontend', 'Backend', 'Extension', 'packages/*']);
845
1147
  writeFile(path.join(root, 'turbo.json'), JSON.stringify({
846
1148
  $schema: 'https://turborepo.dev/schema.json',
847
1149
  tasks: {
848
1150
  build: {
849
1151
  dependsOn: ['^build'],
850
- outputs: ['dist/**', '.output/**'],
1152
+ outputs: [],
851
1153
  },
852
1154
  typecheck: {
853
1155
  dependsOn: ['^build'],
@@ -861,7 +1163,9 @@ function writeFullstackRootFiles(root, options) {
861
1163
  appendGitignore(root, [
862
1164
  'node_modules',
863
1165
  '.turbo',
864
- 'apps/*/node_modules',
1166
+ 'Frontend/node_modules',
1167
+ 'Backend/node_modules',
1168
+ 'Extension/node_modules',
865
1169
  'packages/*/node_modules',
866
1170
  ...SHARED_ENV_GITIGNORE_LINES,
867
1171
  ...SHARED_TYPESCRIPT_GITIGNORE_LINES,
@@ -903,9 +1207,10 @@ async function scaffoldFullstack(root, options) {
903
1207
  });
904
1208
  return [
905
1209
  '.github/workflows/ci.yml',
906
- 'apps/frontend',
907
- 'apps/api',
908
- 'apps/extension',
1210
+ 'PRODUCTION.md',
1211
+ 'Frontend',
1212
+ 'Backend',
1213
+ 'Extension',
909
1214
  'packages/db',
910
1215
  'packages/types',
911
1216
  'packages/config',
@@ -927,6 +1232,7 @@ export async function scaffoldProject(options) {
927
1232
  writeSkillsGuide(root, skillCommands);
928
1233
  const stack = normalizeStack(options, generatedPaths);
929
1234
  writeRootDocs(root, options, stack);
1235
+ writeProductionGuide(root, options);
930
1236
  writeStackFile(root, stack);
931
1237
  anhedralPrint.done('Project metadata written');
932
1238
  console.log('');
@@ -938,9 +1244,10 @@ export async function scaffoldProject(options) {
938
1244
  anhedralPrint.info('Next commands:');
939
1245
  console.log(' pnpm install');
940
1246
  console.log(' cp .env.example .env');
941
- console.log(' cp apps/extension/.env.example apps/extension/.env');
1247
+ console.log(' cp Extension/.env.example Extension/.env');
942
1248
  console.log(' pnpm db:generate && pnpm db:migrate');
943
- console.log(' pnpm dev:api');
1249
+ console.log(' pnpm verify');
1250
+ console.log(' pnpm dev:backend');
944
1251
  console.log(' pnpm dev:frontend');
945
1252
  console.log(' pnpm dev:extension');
946
1253
  console.log('');
@@ -4,7 +4,7 @@ import { anhedralPrint } from '../print.js';
4
4
  import { getBackendInstallCommands } from '../commands.js';
5
5
  import { BACKEND_DEPENDENCIES } from '../dependencies.js';
6
6
  export async function scaffoldBackend(root, { projectName, displayName, frontendUrl, skipInstall }) {
7
- const dir = path.join(root, 'apps/api');
7
+ const dir = path.join(root, 'Backend');
8
8
  anhedralPrint.section('Backend (Fastify)');
9
9
  anhedralPrint.step('Writing backend source files');
10
10
  writePackageJson(dir, projectName);
@@ -24,7 +24,6 @@ export async function scaffoldBackend(root, { projectName, displayName, frontend
24
24
  writeRepositories(dir);
25
25
  writeRoutes(dir, displayName);
26
26
  writeAppAndIndex(dir, displayName);
27
- writeVercelEntry(dir);
28
27
  writeVercelConfig(dir);
29
28
  writeTestFiles(dir);
30
29
  anhedralPrint.done('Backend source files written');
@@ -2174,55 +2173,11 @@ main().catch((err) => {
2174
2173
  });
2175
2174
  `);
2176
2175
  }
2177
- function writeVercelEntry(dir) {
2178
- writeFile(path.join(dir, 'api/index.ts'), `import type { VercelRequest, VercelResponse } from '@vercel/node';
2179
- import type { FastifyInstance } from 'fastify';
2180
- import { buildApp } from '../src/app.js';
2181
-
2182
- let appReadyPromise: Promise<FastifyInstance> | undefined;
2183
-
2184
- async function getApp(): Promise<FastifyInstance> {
2185
- if (!appReadyPromise) {
2186
- appReadyPromise = (async () => {
2187
- const app = await buildApp();
2188
- await app.ready();
2189
- return app;
2190
- })().catch((err) => {
2191
- appReadyPromise = undefined;
2192
- throw err;
2193
- });
2194
- }
2195
- return appReadyPromise;
2196
- }
2197
-
2198
- export default async function handler(req: VercelRequest, res: VercelResponse) {
2199
- const app = await getApp();
2200
- if (req.url === '/api' || req.url === '/backend') {
2201
- req.url = '/';
2202
- } else if (req.url?.startsWith('/api/')) {
2203
- req.url = req.url.slice('/api'.length);
2204
- } else if (req.url?.startsWith('/backend/')) {
2205
- req.url = req.url.slice('/backend'.length);
2206
- }
2207
- app.server.emit('request', req, res);
2208
- }
2209
- `);
2210
- }
2211
2176
  function writeVercelConfig(dir) {
2212
2177
  writeFile(path.join(dir, 'vercel.json'), JSON.stringify({
2213
- version: 2,
2214
- builds: [
2215
- {
2216
- src: 'api/index.ts',
2217
- use: '@vercel/node',
2218
- },
2219
- ],
2220
- routes: [
2221
- {
2222
- src: '/(.*)',
2223
- dest: 'api/index.ts',
2224
- },
2225
- ],
2178
+ $schema: 'https://openapi.vercel.sh/vercel.json',
2179
+ buildCommand: 'pnpm build',
2180
+ devCommand: 'vercel dev',
2226
2181
  }, null, 2) + '\n');
2227
2182
  }
2228
2183
  // ═══════════════════════════════════════════════════════════════════════════
@@ -5,13 +5,11 @@ import { anhedralPrint } from '../print.js';
5
5
  import { EXTENSION_DEPENDENCIES } from '../dependencies.js';
6
6
  import { resolveToolchainChannel, resolveToolchain, toolPackageRef } from '../toolchain.js';
7
7
  export async function scaffoldExtension(root, { projectName, displayName, skipInstall }) {
8
- const appsRoot = path.join(root, 'apps');
9
- const dir = path.join(appsRoot, 'extension');
8
+ const dir = path.join(root, 'Extension');
10
9
  const toolchain = resolveToolchain(resolveToolchainChannel(process.env.ANHEDRAL_TOOLCHAIN));
11
10
  anhedralPrint.section('Chrome extension (WXT)');
12
11
  anhedralPrint.step('Scaffolding WXT extension');
13
- writeFile(path.join(appsRoot, '.gitkeep'), '');
14
- exec(`pnpm dlx ${toolPackageRef('wxt', toolchain.wxt)} init extension -t react --pm pnpm`, appsRoot);
12
+ exec(`pnpm dlx --allow-build=esbuild --allow-build=spawn-sync ${toolPackageRef('wxt', toolchain.wxt)} init Extension -t react --pm pnpm`, root);
15
13
  writePackageJson(dir, projectName);
16
14
  anhedralPrint.done('WXT extension scaffolded');
17
15
  anhedralPrint.step('Installing Clerk + React + Tailwind dependencies');
@@ -98,6 +96,11 @@ export default defineConfig({
98
96
  };
99
97
  },
100
98
  modules: ['@wxt-dev/module-react'],
99
+ vite: () => ({
100
+ build: {
101
+ chunkSizeWarningLimit: 3000,
102
+ },
103
+ }),
101
104
  });
102
105
  `);
103
106
  }
@@ -6,7 +6,7 @@ import { appendGitignore, writeFile, exec, execExpect, liftNestedProject } from
6
6
  import { FRONTEND_ADDON_DEPENDENCIES, withVersions } from '../dependencies.js';
7
7
  import { resolveToolchainChannel, resolveToolchain, toolPackageRef } from '../toolchain.js';
8
8
  export async function scaffoldFrontend(root, { projectName, displayName, skipInstall }) {
9
- const dir = path.join(root, 'apps/frontend');
9
+ const dir = path.join(root, 'Frontend');
10
10
  const toolchain = resolveToolchain(resolveToolchainChannel(process.env.ANHEDRAL_TOOLCHAIN));
11
11
  anhedralPrint.section('Frontend (Expo)');
12
12
  anhedralPrint.step('Scaffolding Expo app with react-native-reusables');
@@ -21,6 +21,7 @@ export async function scaffoldFrontend(root, { projectName, displayName, skipIns
21
21
  anhedralPrint.step('Installing frontend dependencies');
22
22
  patchFrontendPackageJson(dir);
23
23
  patchExpoAppConfig(dir);
24
+ patchFrontendTsConfig(dir);
24
25
  if (!skipInstall) {
25
26
  exec('pnpm install --no-frozen-lockfile', dir);
26
27
  exec('pnpm exec expo install --fix --pnpm', dir);
@@ -36,13 +37,14 @@ export async function scaffoldFrontend(root, { projectName, displayName, skipIns
36
37
  writeEnvExample(dir);
37
38
  writeEnvFile(dir);
38
39
  writeVercelConfig(dir);
40
+ writeEasConfig(dir);
39
41
  writeAnhedralLogo(dir);
40
42
  writeSubscriptionProvider(dir);
41
43
  writeUseSubscription(dir);
42
44
  anhedralPrint.step('Installing Expo native packages');
43
45
  if (skipInstall) {
44
46
  anhedralPrint.info('Skipping Expo native package install (--skip-install)');
45
- anhedralPrint.info('Run after init: pnpm --filter ./apps/frontend exec expo install --pnpm expo-image-picker');
47
+ anhedralPrint.info('Run after init: pnpm --filter ./Frontend exec expo install --pnpm expo-image-picker');
46
48
  }
47
49
  else {
48
50
  exec('pnpm exec expo install --pnpm expo-image-picker', dir);
@@ -56,7 +58,7 @@ export async function scaffoldFrontend(root, { projectName, displayName, skipIns
56
58
  '@revenuecat/purchases-js': FRONTEND_ADDON_DEPENDENCIES['@revenuecat/purchases-js'],
57
59
  });
58
60
  if (skipInstall) {
59
- anhedralPrint.info(`Skipping RevenueCat SDK install (--skip-install). Run after init: pnpm --filter ./apps/frontend add ${revenueCatDependencies.join(' ')}`);
61
+ anhedralPrint.info(`Skipping RevenueCat SDK install (--skip-install). Run after init: pnpm --filter ./Frontend add ${revenueCatDependencies.join(' ')}`);
60
62
  }
61
63
  else {
62
64
  exec(`pnpm add ${revenueCatDependencies.join(' ')}`, dir);
@@ -69,7 +71,7 @@ function patchFrontendPackageJson(dir) {
69
71
  packageJson.dependencies = {
70
72
  ...(packageJson.dependencies ?? {}),
71
73
  '@anhedral/api-client': FRONTEND_ADDON_DEPENDENCIES['@anhedral/api-client'],
72
- '@clerk/clerk-expo': FRONTEND_ADDON_DEPENDENCIES['@clerk/clerk-expo'],
74
+ '@clerk/expo': FRONTEND_ADDON_DEPENDENCIES['@clerk/expo'],
73
75
  'react-native-purchases': FRONTEND_ADDON_DEPENDENCIES['react-native-purchases'],
74
76
  'react-native-purchases-ui': FRONTEND_ADDON_DEPENDENCIES['react-native-purchases-ui'],
75
77
  '@revenuecat/purchases-js': FRONTEND_ADDON_DEPENDENCIES['@revenuecat/purchases-js'],
@@ -82,6 +84,17 @@ function patchFrontendPackageJson(dir) {
82
84
  };
83
85
  writeFile(filePath, JSON.stringify(packageJson, null, 2) + '\n');
84
86
  }
87
+ function patchFrontendTsConfig(dir) {
88
+ const filePath = path.join(dir, 'tsconfig.json');
89
+ if (!fs.existsSync(filePath)) {
90
+ return;
91
+ }
92
+ const tsConfig = JSON.parse(fs.readFileSync(filePath, 'utf8'));
93
+ if (tsConfig.extends === 'expo/tsconfig.base') {
94
+ tsConfig.extends = 'expo/tsconfig.base.json';
95
+ }
96
+ writeFile(filePath, JSON.stringify(tsConfig, null, 2) + '\n');
97
+ }
85
98
  function patchExpoAppConfig(dir) {
86
99
  const filePath = path.join(dir, 'app.json');
87
100
  if (!fs.existsSync(filePath)) {
@@ -94,6 +107,10 @@ function patchExpoAppConfig(dir) {
94
107
  bundler: 'metro',
95
108
  output: 'static',
96
109
  };
110
+ appJson.expo.plugins = Array.from(new Set([
111
+ ...(Array.isArray(appJson.expo.plugins) ? appJson.expo.plugins : []),
112
+ '@clerk/expo',
113
+ ]));
97
114
  writeFile(filePath, JSON.stringify(appJson, null, 2) + '\n');
98
115
  }
99
116
  function writeApiClient(dir) {
@@ -169,7 +186,7 @@ export function getPlatformRevenueCatApiKey(): string {
169
186
  `);
170
187
  }
171
188
  function writeApiHook(dir) {
172
- writeFile(path.join(dir, 'hooks/useAPI.ts'), `import { useAuth } from '@clerk/clerk-expo';
189
+ writeFile(path.join(dir, 'hooks/useAPI.ts'), `import { useAuth } from '@clerk/expo';
173
190
  import { useMemo } from 'react';
174
191
  import { APIClient } from '@/api/client';
175
192
  import { apiBaseUrl } from '@/lib/config';
@@ -191,13 +208,39 @@ function writeVercelConfig(dir) {
191
208
  rewrites: [
192
209
  {
193
210
  source: '/:path*',
194
- destination: '/index.html',
211
+ destination: '/',
195
212
  },
196
213
  ],
197
214
  }, null, 2) + '\n');
198
215
  }
216
+ function writeEasConfig(dir) {
217
+ writeFile(path.join(dir, 'eas.json'), JSON.stringify({
218
+ cli: {
219
+ version: '>= 16.24.0',
220
+ appVersionSource: 'remote',
221
+ },
222
+ build: {
223
+ development: {
224
+ developmentClient: true,
225
+ distribution: 'internal',
226
+ android: {
227
+ buildType: 'apk',
228
+ },
229
+ },
230
+ preview: {
231
+ distribution: 'internal',
232
+ },
233
+ production: {
234
+ autoIncrement: true,
235
+ },
236
+ },
237
+ submit: {
238
+ production: {},
239
+ },
240
+ }, null, 2) + '\n');
241
+ }
199
242
  function writeAccountHook(dir) {
200
- writeFile(path.join(dir, 'hooks/useAccount.ts'), `import { useAuth } from '@clerk/clerk-expo';
243
+ writeFile(path.join(dir, 'hooks/useAccount.ts'), `import { useAuth } from '@clerk/expo';
201
244
  import * as React from 'react';
202
245
  import { useAPI } from '@/hooks/useAPI';
203
246
 
@@ -295,7 +338,7 @@ import Purchases, { type CustomerInfo, type PurchasesOfferings } from 'react-nat
295
338
  import { Purchases as PurchasesWeb } from '@revenuecat/purchases-js';
296
339
  import { AppState, Platform } from 'react-native';
297
340
  import { subscriptionConfig, getPlatformRevenueCatApiKey } from '@/lib/config';
298
- import { useAuth, useUser } from '@clerk/clerk-expo';
341
+ import { useAuth, useUser } from '@clerk/expo';
299
342
  import { useAPI } from '@/hooks/useAPI';
300
343
  import RevenueCatUI, { PAYWALL_RESULT } from 'react-native-purchases-ui';
301
344
 
@@ -697,9 +740,10 @@ function writeAppShellFiles(dir, displayName) {
697
740
  writeFile(path.join(dir, 'app/_layout.tsx'), `import '@/global.css';
698
741
 
699
742
  import { SubscriptionProvider } from '@/contexts/SubscriptionProvider';
743
+ import { clerkPublishableKey } from '@/lib/config';
700
744
  import { NAV_THEME } from '@/lib/theme';
701
- import { ClerkProvider, useAuth } from '@clerk/clerk-expo';
702
- import { tokenCache } from '@clerk/clerk-expo/token-cache';
745
+ import { ClerkProvider, useAuth } from '@clerk/expo';
746
+ import { tokenCache } from '@clerk/expo/token-cache';
703
747
  import { ThemeProvider } from '@react-navigation/native';
704
748
  import { PortalHost } from '@rn-primitives/portal';
705
749
  import { Stack } from 'expo-router';
@@ -714,7 +758,7 @@ export default function RootLayout() {
714
758
  const { colorScheme } = useColorScheme();
715
759
 
716
760
  return (
717
- <ClerkProvider tokenCache={tokenCache}>
761
+ <ClerkProvider publishableKey={clerkPublishableKey} tokenCache={tokenCache}>
718
762
  <ThemeProvider value={NAV_THEME[colorScheme ?? 'light']}>
719
763
  <SubscriptionProvider>
720
764
  <StatusBar style={colorScheme === 'dark' ? 'light' : 'dark'} />
@@ -763,7 +807,7 @@ function Routes() {
763
807
  import { Button } from '@/components/ui/button';
764
808
  import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card';
765
809
  import { Text } from '@/components/ui/text';
766
- import { useAuth } from '@clerk/clerk-expo';
810
+ import { useAuth } from '@clerk/expo';
767
811
  import { Link } from 'expo-router';
768
812
  import { CloudIcon, CreditCardIcon, ShieldCheckIcon, DatabaseIcon } from 'lucide-react-native';
769
813
  import { ScrollView, View } from 'react-native';
@@ -1103,7 +1147,7 @@ import { Input } from '@/components/ui/input';
1103
1147
  import { Label } from '@/components/ui/label';
1104
1148
  import { Separator } from '@/components/ui/separator';
1105
1149
  import { Text } from '@/components/ui/text';
1106
- import { useSignIn } from '@clerk/clerk-expo';
1150
+ import { useSignIn } from '@clerk/expo/legacy';
1107
1151
  import { Link } from 'expo-router';
1108
1152
  import * as React from 'react';
1109
1153
  import { type TextInput, View } from 'react-native';
@@ -1217,7 +1261,7 @@ import { Input } from '@/components/ui/input';
1217
1261
  import { Label } from '@/components/ui/label';
1218
1262
  import { Separator } from '@/components/ui/separator';
1219
1263
  import { Text } from '@/components/ui/text';
1220
- import { useSignUp } from '@clerk/clerk-expo';
1264
+ import { useSignUp } from '@clerk/expo/legacy';
1221
1265
  import { Link, router } from 'expo-router';
1222
1266
  import * as React from 'react';
1223
1267
  import { TextInput, View } from 'react-native';
@@ -1321,7 +1365,7 @@ import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover
1321
1365
  import { Text } from '@/components/ui/text';
1322
1366
  import { useAccount } from '@/hooks/useAccount';
1323
1367
  import { useSubscription } from '@/hooks/useSubscription';
1324
- import { useAuth } from '@clerk/clerk-expo';
1368
+ import { useAuth } from '@clerk/expo';
1325
1369
  import type { TriggerRef } from '@rn-primitives/popover';
1326
1370
  import { CameraIcon, CreditCardIcon, CoinsIcon, LoaderCircleIcon, LogOutIcon } from 'lucide-react-native';
1327
1371
  import * as React from 'react';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anhedral",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Opinionated init CLI for Expo, Fastify, WXT, shared packages, Neon, Drizzle, Clerk, RevenueCat, Stripe, R2, and Vercel.",
5
5
  "type": "module",
6
6
  "bin": {