alepha 0.20.1 → 0.20.2

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.
Files changed (232) hide show
  1. package/dist/api/files/index.js +2 -1
  2. package/dist/api/files/index.js.map +1 -1
  3. package/dist/api/jobs/index.browser.js +64 -148
  4. package/dist/api/jobs/index.browser.js.map +1 -1
  5. package/dist/api/jobs/index.d.ts +371 -573
  6. package/dist/api/jobs/index.d.ts.map +1 -1
  7. package/dist/api/jobs/index.js +605 -1012
  8. package/dist/api/jobs/index.js.map +1 -1
  9. package/dist/api/notifications/index.d.ts +78 -17
  10. package/dist/api/notifications/index.d.ts.map +1 -1
  11. package/dist/api/notifications/index.js +90 -23
  12. package/dist/api/notifications/index.js.map +1 -1
  13. package/dist/api/payments/index.d.ts +2 -1
  14. package/dist/api/payments/index.d.ts.map +1 -1
  15. package/dist/api/payments/index.js +4 -2
  16. package/dist/api/payments/index.js.map +1 -1
  17. package/dist/api/users/index.d.ts +34 -31
  18. package/dist/api/users/index.d.ts.map +1 -1
  19. package/dist/api/users/index.js +13 -7
  20. package/dist/api/users/index.js.map +1 -1
  21. package/dist/api/verifications/index.js +2 -1
  22. package/dist/api/verifications/index.js.map +1 -1
  23. package/dist/cli/core/index.d.ts +8 -34
  24. package/dist/cli/core/index.d.ts.map +1 -1
  25. package/dist/cli/core/index.js +43 -232
  26. package/dist/cli/core/index.js.map +1 -1
  27. package/dist/cli/platform/index.d.ts +36 -11
  28. package/dist/cli/platform/index.d.ts.map +1 -1
  29. package/dist/cli/platform/index.js +93 -27
  30. package/dist/cli/platform/index.js.map +1 -1
  31. package/dist/command/index.d.ts +1 -1
  32. package/dist/core/index.browser.js +6 -0
  33. package/dist/core/index.browser.js.map +1 -1
  34. package/dist/core/index.d.ts +6 -0
  35. package/dist/core/index.d.ts.map +1 -1
  36. package/dist/core/index.js +6 -0
  37. package/dist/core/index.js.map +1 -1
  38. package/dist/core/index.native.js +6 -0
  39. package/dist/core/index.native.js.map +1 -1
  40. package/dist/core/index.workerd.js +6 -0
  41. package/dist/core/index.workerd.js.map +1 -1
  42. package/dist/react/form/index.d.ts +60 -1
  43. package/dist/react/form/index.d.ts.map +1 -1
  44. package/dist/react/form/index.js +86 -1
  45. package/dist/react/form/index.js.map +1 -1
  46. package/dist/react/head/index.browser.js +16 -1
  47. package/dist/react/head/index.browser.js.map +1 -1
  48. package/dist/react/head/index.d.ts +6 -0
  49. package/dist/react/head/index.d.ts.map +1 -1
  50. package/dist/react/head/index.js +16 -1
  51. package/dist/react/head/index.js.map +1 -1
  52. package/dist/react/router/index.browser.js +0 -10
  53. package/dist/react/router/index.browser.js.map +1 -1
  54. package/dist/react/router/index.d.ts +35 -12
  55. package/dist/react/router/index.d.ts.map +1 -1
  56. package/dist/react/router/index.js +0 -10
  57. package/dist/react/router/index.js.map +1 -1
  58. package/dist/react/ui/index.d.ts +124 -0
  59. package/dist/react/ui/index.d.ts.map +1 -0
  60. package/dist/react/ui/index.js +206 -0
  61. package/dist/react/ui/index.js.map +1 -0
  62. package/dist/router/index.d.ts +13 -13
  63. package/dist/router/index.d.ts.map +1 -1
  64. package/dist/router/index.js +45 -32
  65. package/dist/router/index.js.map +1 -1
  66. package/dist/system/index.d.ts.map +1 -1
  67. package/dist/system/index.js +1 -0
  68. package/dist/system/index.js.map +1 -1
  69. package/dist/topic/core/index.js +1 -1
  70. package/dist/topic/core/index.js.map +1 -1
  71. package/package.json +6 -23
  72. package/src/api/files/jobs/FileJobs.ts +2 -1
  73. package/src/api/jobs/__tests__/$job.spec.ts +316 -2867
  74. package/src/api/jobs/controllers/AdminJobController.ts +29 -138
  75. package/src/api/jobs/entities/jobExecutionEntity.ts +27 -19
  76. package/src/api/jobs/index.browser.ts +5 -7
  77. package/src/api/jobs/index.ts +23 -51
  78. package/src/api/jobs/primitives/$job.ts +66 -58
  79. package/src/api/jobs/providers/JobProvider.ts +561 -566
  80. package/src/api/jobs/providers/JobQueueProvider.ts +18 -19
  81. package/src/api/jobs/schemas/jobConfigAtom.ts +20 -23
  82. package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +3 -27
  83. package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +5 -7
  84. package/src/api/jobs/schemas/jobRegistrationSchema.ts +7 -4
  85. package/src/api/jobs/schemas/triggerJobSchema.ts +0 -1
  86. package/src/api/jobs/services/JobService.ts +90 -483
  87. package/src/api/notifications/controllers/AdminNotificationController.ts +19 -12
  88. package/src/api/notifications/index.ts +7 -4
  89. package/src/api/notifications/jobs/NotificationJobs.ts +83 -12
  90. package/src/api/payments/services/PaymentService.ts +4 -2
  91. package/src/api/users/__tests__/UserJobs.spec.ts +10 -49
  92. package/src/api/users/audits/UserAudits.ts +3 -1
  93. package/src/api/users/buckets/UserBuckets.ts +2 -1
  94. package/src/api/users/index.ts +1 -4
  95. package/src/api/users/jobs/UserJobs.ts +5 -4
  96. package/src/api/verifications/jobs/VerificationJobs.ts +2 -1
  97. package/src/cli/core/__tests__/init.spec.ts +1 -1
  98. package/src/cli/core/commands/init.ts +0 -12
  99. package/src/cli/core/services/PackageManagerUtils.ts +2 -9
  100. package/src/cli/core/services/ProjectScaffolder.ts +17 -65
  101. package/src/cli/core/templates/agentMd.ts +2 -8
  102. package/src/cli/core/templates/apiIndexTs.ts +4 -18
  103. package/src/cli/core/templates/mainCss.ts +1 -36
  104. package/src/cli/core/templates/vitestConfigTs.ts +17 -0
  105. package/src/cli/core/templates/webAppRouterTs.ts +2 -85
  106. package/src/cli/platform/__tests__/CloudflareAdapter.spec.ts +22 -71
  107. package/src/cli/platform/adapters/CloudflareAdapter.ts +12 -11
  108. package/src/cli/platform/atoms/platformOptions.ts +9 -0
  109. package/src/cli/platform/schemas/cloudflare.ts +3 -2
  110. package/src/cli/platform/services/CloudflareApi.ts +164 -25
  111. package/src/cli/platform/services/WranglerApi.ts +0 -17
  112. package/src/core/Alepha.ts +9 -0
  113. package/src/react/form/index.ts +2 -0
  114. package/src/react/form/services/parseField.ts +163 -0
  115. package/src/react/form/services/prettyName.ts +19 -0
  116. package/src/react/head/providers/BrowserHeadProvider.ts +31 -10
  117. package/src/react/router/primitives/$page.ts +35 -12
  118. package/src/react/ui/atoms/uiAtom.ts +28 -0
  119. package/src/react/ui/components/ColorScheme.tsx +36 -0
  120. package/src/react/ui/hooks/useColorMode.ts +49 -0
  121. package/src/react/ui/hooks/useSidebarState.ts +26 -0
  122. package/src/react/ui/hooks/useTheme.ts +22 -0
  123. package/src/react/ui/index.ts +35 -0
  124. package/src/react/ui/services/UiPersistence.ts +41 -0
  125. package/src/router/TemplatedPathParser.ts +50 -51
  126. package/src/router/__tests__/RouterProvider.spec.ts +62 -0
  127. package/src/router/__tests__/TemplatedPathParser.spec.ts +18 -0
  128. package/src/router/providers/RouterProvider.ts +10 -5
  129. package/src/system/providers/NodeShellProvider.ts +1 -0
  130. package/src/topic/core/providers/TopicProvider.ts +1 -1
  131. package/dist/api/invitations/index.d.ts +0 -790
  132. package/dist/api/invitations/index.d.ts.map +0 -1
  133. package/dist/api/invitations/index.js +0 -662
  134. package/dist/api/invitations/index.js.map +0 -1
  135. package/dist/api/issues/index.d.ts +0 -810
  136. package/dist/api/issues/index.d.ts.map +0 -1
  137. package/dist/api/issues/index.js +0 -444
  138. package/dist/api/issues/index.js.map +0 -1
  139. package/dist/api/subscriptions/index.d.ts +0 -1692
  140. package/dist/api/subscriptions/index.d.ts.map +0 -1
  141. package/dist/api/subscriptions/index.js +0 -1867
  142. package/dist/api/subscriptions/index.js.map +0 -1
  143. package/dist/api/workflows/index.browser.js +0 -246
  144. package/dist/api/workflows/index.browser.js.map +0 -1
  145. package/dist/api/workflows/index.d.ts +0 -1618
  146. package/dist/api/workflows/index.d.ts.map +0 -1
  147. package/dist/api/workflows/index.js +0 -1495
  148. package/dist/api/workflows/index.js.map +0 -1
  149. package/src/api/invitations/__tests__/InvitationService.spec.ts +0 -439
  150. package/src/api/invitations/controllers/AdminInvitationController.ts +0 -86
  151. package/src/api/invitations/controllers/InvitationController.ts +0 -84
  152. package/src/api/invitations/entities/invitations.ts +0 -33
  153. package/src/api/invitations/index.ts +0 -58
  154. package/src/api/invitations/jobs/InvitationJobs.ts +0 -37
  155. package/src/api/invitations/providers/InvitationProvider.ts +0 -45
  156. package/src/api/invitations/schemas/createInvitationSchema.ts +0 -12
  157. package/src/api/invitations/schemas/invitationConfigAtom.ts +0 -20
  158. package/src/api/invitations/schemas/invitationQuerySchema.ts +0 -15
  159. package/src/api/invitations/schemas/invitationResourceSchema.ts +0 -6
  160. package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +0 -22
  161. package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +0 -10
  162. package/src/api/invitations/services/InvitationService.ts +0 -556
  163. package/src/api/issues/__tests__/IssueService.spec.ts +0 -263
  164. package/src/api/issues/controllers/AdminIssueController.ts +0 -149
  165. package/src/api/issues/controllers/IssueController.ts +0 -44
  166. package/src/api/issues/entities/issues.ts +0 -49
  167. package/src/api/issues/index.ts +0 -50
  168. package/src/api/issues/schemas/createIssueSchema.ts +0 -13
  169. package/src/api/issues/schemas/issueConfigAtom.ts +0 -13
  170. package/src/api/issues/schemas/issueQuerySchema.ts +0 -18
  171. package/src/api/issues/schemas/issueResourceSchema.ts +0 -6
  172. package/src/api/issues/schemas/myIssueQuerySchema.ts +0 -10
  173. package/src/api/issues/schemas/updateIssueSchema.ts +0 -13
  174. package/src/api/issues/services/IssueService.ts +0 -264
  175. package/src/api/jobs/__tests__/$job-middleware.spec.ts +0 -126
  176. package/src/api/jobs/__tests__/JobService.spec.ts +0 -31
  177. package/src/api/jobs/entities/jobExecutionLogEntity.ts +0 -13
  178. package/src/api/jobs/schemas/jobActivitySchema.ts +0 -15
  179. package/src/api/jobs/schemas/jobCronInfoSchema.ts +0 -22
  180. package/src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts +0 -20
  181. package/src/api/jobs/schemas/jobFailureSchema.ts +0 -9
  182. package/src/api/jobs/schemas/jobQueueDepthSchema.ts +0 -14
  183. package/src/api/jobs/schemas/jobStatsSchema.ts +0 -14
  184. package/src/api/jobs/services/JobService-tests.ts +0 -157
  185. package/src/api/subscriptions/__tests__/BillingService.spec.ts +0 -218
  186. package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +0 -278
  187. package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +0 -212
  188. package/src/api/subscriptions/controllers/SubscriptionController.ts +0 -189
  189. package/src/api/subscriptions/entities/subscriptionEvents.ts +0 -54
  190. package/src/api/subscriptions/entities/subscriptions.ts +0 -68
  191. package/src/api/subscriptions/index.ts +0 -133
  192. package/src/api/subscriptions/jobs/SubscriptionJobs.ts +0 -382
  193. package/src/api/subscriptions/middleware/$requireLimit.ts +0 -50
  194. package/src/api/subscriptions/middleware/$requirePlan.ts +0 -49
  195. package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +0 -110
  196. package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +0 -8
  197. package/src/api/subscriptions/schemas/changePlanSchema.ts +0 -9
  198. package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +0 -11
  199. package/src/api/subscriptions/schemas/entitlementsSchema.ts +0 -21
  200. package/src/api/subscriptions/schemas/mrrSchema.ts +0 -13
  201. package/src/api/subscriptions/schemas/planDefinitionSchema.ts +0 -71
  202. package/src/api/subscriptions/schemas/planResourceSchema.ts +0 -25
  203. package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +0 -8
  204. package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +0 -19
  205. package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +0 -6
  206. package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +0 -32
  207. package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +0 -23
  208. package/src/api/subscriptions/services/BillingService.ts +0 -437
  209. package/src/api/subscriptions/services/SubscriptionConfig.ts +0 -56
  210. package/src/api/subscriptions/services/SubscriptionService.ts +0 -867
  211. package/src/api/subscriptions/services/UsageService.ts +0 -118
  212. package/src/api/workflows/__tests__/$workflow.spec.ts +0 -616
  213. package/src/api/workflows/controllers/AdminWorkflowController.ts +0 -191
  214. package/src/api/workflows/entities/workflowExecutions.ts +0 -74
  215. package/src/api/workflows/entities/workflowStepExecutions.ts +0 -74
  216. package/src/api/workflows/entities/workflowStepLogs.ts +0 -13
  217. package/src/api/workflows/index.browser.ts +0 -22
  218. package/src/api/workflows/index.ts +0 -115
  219. package/src/api/workflows/jobs/WorkflowJobs.ts +0 -77
  220. package/src/api/workflows/primitives/$workflow.ts +0 -202
  221. package/src/api/workflows/providers/WorkflowProvider.ts +0 -1284
  222. package/src/api/workflows/schemas/workflowActivitySchema.ts +0 -15
  223. package/src/api/workflows/schemas/workflowConfigAtom.ts +0 -51
  224. package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +0 -18
  225. package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +0 -26
  226. package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +0 -30
  227. package/src/api/workflows/schemas/workflowRegistrationSchema.ts +0 -26
  228. package/src/api/workflows/schemas/workflowStatsSchema.ts +0 -16
  229. package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +0 -15
  230. package/src/api/workflows/services/WorkflowService.ts +0 -382
  231. package/src/cli/core/templates/apiAppSecurityTs.ts +0 -43
  232. package/src/cli/core/templates/webAdminDashboardTsx.ts +0 -17
@@ -5,7 +5,6 @@ import { $logger, ConsoleColorProvider } from "alepha/logger";
5
5
  import { FileSystemProvider } from "alepha/system";
6
6
  import { type AgentMdOptions, agentMd } from "../templates/agentMd.ts";
7
7
  import { alephaConfigTs } from "../templates/alephaConfigTs.ts";
8
- import { apiAppSecurityTs } from "../templates/apiAppSecurityTs.ts";
9
8
  import { apiHelloControllerTs } from "../templates/apiHelloControllerTs.ts";
10
9
  import { apiHelloResponseSchemaTs } from "../templates/apiHelloResponseSchemaTs.ts";
11
10
  import { apiIndexTs } from "../templates/apiIndexTs.ts";
@@ -19,7 +18,7 @@ import { mainCss } from "../templates/mainCss.ts";
19
18
  import { mainServerTs } from "../templates/mainServerTs.ts";
20
19
  import { tsconfigJson } from "../templates/tsconfigJson.ts";
21
20
  import { viteConfigTs } from "../templates/viteConfigTs.ts";
22
- import { webAdminDashboardTsx } from "../templates/webAdminDashboardTsx.ts";
21
+ import { vitestConfigTs } from "../templates/vitestConfigTs.ts";
23
22
  import { webAppRouterTs } from "../templates/webAppRouterTs.ts";
24
23
  import { webHomeComponentTsx } from "../templates/webHomeComponentTsx.ts";
25
24
  import { webIndexTs } from "../templates/webIndexTs.ts";
@@ -241,7 +240,7 @@ export class ProjectScaffolder {
241
240
  */
242
241
  public async ensureApiProject(
243
242
  root: string,
244
- opts: { auth?: boolean; adminEmail?: string; force?: boolean } = {},
243
+ opts: { force?: boolean } = {},
245
244
  ): Promise<void> {
246
245
  const appName = this.getAppName(root);
247
246
 
@@ -257,7 +256,7 @@ export class ProjectScaffolder {
257
256
  await this.ensureFile(
258
257
  root,
259
258
  "src/api/index.ts",
260
- apiIndexTs({ appName, auth: opts.auth }),
259
+ apiIndexTs({ appName }),
261
260
  opts.force,
262
261
  );
263
262
  await this.ensureFile(
@@ -272,16 +271,6 @@ export class ProjectScaffolder {
272
271
  apiHelloResponseSchemaTs(),
273
272
  opts.force,
274
273
  );
275
-
276
- // Create AppSecurity if auth is enabled
277
- if (opts.auth) {
278
- await this.ensureFile(
279
- root,
280
- "src/api/AppSecurity.ts",
281
- apiAppSecurityTs({ adminEmail: opts.adminEmail }),
282
- opts.force,
283
- );
284
- }
285
274
  }
286
275
 
287
276
  // ===========================================
@@ -300,9 +289,6 @@ export class ProjectScaffolder {
300
289
  root: string,
301
290
  opts: {
302
291
  api?: boolean;
303
- ui?: boolean;
304
- auth?: boolean;
305
- admin?: boolean;
306
292
  tailwind?: boolean;
307
293
  force?: boolean;
308
294
  } = {},
@@ -322,7 +308,7 @@ export class ProjectScaffolder {
322
308
  await this.ensureFile(
323
309
  root,
324
310
  "src/main.css",
325
- mainCss({ ui: opts.ui, tailwind: opts.tailwind }),
311
+ mainCss({ tailwind: opts.tailwind }),
326
312
  opts.force,
327
313
  );
328
314
 
@@ -341,12 +327,7 @@ export class ProjectScaffolder {
341
327
  await this.ensureFile(
342
328
  root,
343
329
  "src/web/AppRouter.ts",
344
- webAppRouterTs({
345
- api: opts.api,
346
- ui: opts.ui,
347
- auth: opts.auth,
348
- admin: opts.admin,
349
- }),
330
+ webAppRouterTs({ api: opts.api }),
350
331
  opts.force,
351
332
  );
352
333
  await this.ensureFile(
@@ -355,14 +336,6 @@ export class ProjectScaffolder {
355
336
  webHomeComponentTsx({ api: opts.api }),
356
337
  opts.force,
357
338
  );
358
- if (opts.admin) {
359
- await this.ensureFile(
360
- root,
361
- "src/web/components/AdminDashboard.tsx",
362
- webAdminDashboardTsx(),
363
- opts.force,
364
- );
365
- }
366
339
  await this.ensureFile(
367
340
  root,
368
341
  "src/main.browser.ts",
@@ -376,11 +349,18 @@ export class ProjectScaffolder {
376
349
  // ===========================================
377
350
 
378
351
  /**
379
- * Ensure test directory exists with a dummy test file.
352
+ * Ensure test directory exists with a dummy test file + a self-contained
353
+ * `vitest.config.ts`. Pinning `test.root` prevents Vitest from walking up
354
+ * to a parent monorepo config (e.g. one that boots a Postgres container).
380
355
  */
381
356
  public async ensureTestDir(root: string): Promise<void> {
382
357
  const testDir = this.fs.join(root, "test");
383
358
  const dummyPath = this.fs.join(testDir, "dummy.spec.ts");
359
+ const vitestConfigPath = this.fs.join(root, "vitest.config.ts");
360
+
361
+ if (!(await this.fs.exists(vitestConfigPath))) {
362
+ await this.fs.writeFile(vitestConfigPath, vitestConfigTs());
363
+ }
384
364
 
385
365
  if (!(await this.fs.exists(testDir))) {
386
366
  await this.fs.mkdir(testDir, { recursive: true });
@@ -413,8 +393,6 @@ export class ProjectScaffolder {
413
393
  pm?: "yarn" | "npm" | "pnpm" | "bun";
414
394
  api?: boolean;
415
395
  react?: boolean;
416
- ui?: boolean;
417
- saas?: boolean;
418
396
  tailwind?: boolean;
419
397
  test?: boolean;
420
398
  force?: boolean;
@@ -426,21 +404,13 @@ export class ProjectScaffolder {
426
404
  await this.fs.mkdir(root, { force: true });
427
405
  }
428
406
 
429
- // Flag cascading: --saas → --api + --ui → --react
430
- if (flags.saas) {
431
- flags.api = true;
432
- flags.ui = true;
433
- }
434
- if (flags.ui) {
435
- flags.react = true;
436
- }
407
+ // Flag cascading: --tailwind → --react
437
408
  if (flags.tailwind) {
438
409
  flags.react = true;
439
410
  }
440
411
 
441
412
  // When codegen flags are set, target directory must be empty (unless --force)
442
- const hasCodegenFlags =
443
- flags.saas || flags.api || flags.ui || flags.react || flags.tailwind;
413
+ const hasCodegenFlags = flags.api || flags.react || flags.tailwind;
444
414
  if (hasCodegenFlags && !flags.force) {
445
415
  const files = await this.fs.ls(root);
446
416
  // Allow a directory that only has package.json (common for monorepo packages)
@@ -464,9 +434,6 @@ export class ProjectScaffolder {
464
434
 
465
435
  const isExpo = await this.pm.hasExpo(root);
466
436
 
467
- // Get git email for admin auto-promotion (if saas enabled)
468
- const adminEmail = flags.saas ? await this.utils.getGitEmail() : undefined;
469
-
470
437
  const force = !!flags.force;
471
438
 
472
439
  await run({
@@ -479,7 +446,7 @@ export class ProjectScaffolder {
479
446
  tsconfigJson: !workspace.config.tsconfigJson,
480
447
  biomeJson: true,
481
448
  editorconfig: !workspace.config.editorconfig,
482
- agentMd: agentType ? { type: agentType, ui: !!flags.ui } : false,
449
+ agentMd: agentType ? { type: agentType } : false,
483
450
  });
484
451
 
485
452
  // Create alepha.config.ts with documented options
@@ -492,18 +459,11 @@ export class ProjectScaffolder {
492
459
  force,
493
460
  });
494
461
  if (flags.api) {
495
- await this.ensureApiProject(root, {
496
- auth: !!flags.saas,
497
- adminEmail,
498
- force,
499
- });
462
+ await this.ensureApiProject(root, { force });
500
463
  }
501
464
  if (flags.react && !isExpo) {
502
465
  await this.ensureWebProject(root, {
503
466
  api: !!flags.api,
504
- ui: !!flags.ui,
505
- auth: !!flags.saas,
506
- admin: !!flags.saas,
507
467
  tailwind: !!flags.tailwind,
508
468
  force,
509
469
  });
@@ -584,14 +544,6 @@ export class ProjectScaffolder {
584
544
  ` ${c.set("GREY_DARK", "$")} ${c.set("CYAN", `${pmRun} dev`)}`,
585
545
  );
586
546
 
587
- if (adminEmail) {
588
- this.log.info("");
589
- this.log.info(` Admin email: ${c.set("GREEN", adminEmail)}`);
590
- this.log.info(
591
- ` ${c.set("GREY_DARK", "(from git config, change in src/api/AppSecurity.ts)")}`,
592
- );
593
- }
594
-
595
547
  this.log.info("");
596
548
  }
597
549
 
@@ -2,18 +2,11 @@ export type AgentMdType = "claude" | "agents";
2
2
 
3
3
  export interface AgentMdOptions {
4
4
  type: AgentMdType;
5
- ui?: boolean;
6
5
  }
7
6
 
8
7
  export const agentMd = (options: AgentMdOptions): string => {
9
8
  const header = options.type === "claude" ? `# CLAUDE.md` : `# AGENTS.md`;
10
9
 
11
- const docs = [`- Framework source: \`node_modules/alepha/src/\``];
12
- if (options.ui) {
13
- docs.push(`- UI components: \`node_modules/@alepha/ui/src/\``);
14
- }
15
- docs.push(`- Docs: https://alepha.dev/llms.txt`);
16
-
17
10
  return `${header}
18
11
 
19
12
  This is an **Alepha** project.
@@ -36,6 +29,7 @@ alepha build # Build
36
29
 
37
30
  ## Documentation
38
31
 
39
- ${docs.join("\n")}
32
+ - Framework source: \`node_modules/alepha/src/\`
33
+ - Docs: https://alepha.dev/llms.txt
40
34
  `.trim();
41
35
  };
@@ -1,30 +1,16 @@
1
1
  export interface ApiIndexTsOptions {
2
2
  appName?: string;
3
- auth?: boolean;
4
3
  }
5
4
 
6
5
  export const apiIndexTs = (options: ApiIndexTsOptions = {}) => {
7
- const { appName = "app", auth = false } = options;
8
-
9
- const imports: string[] = ['import { $module } from "alepha";'];
10
- const services: string[] = [];
11
-
12
- if (auth) {
13
- imports.push('import { AppSecurity } from "./AppSecurity.ts";');
14
- services.push("AppSecurity");
15
- }
16
-
17
- imports.push(
18
- 'import { HelloController } from "./controllers/HelloController.ts";',
19
- );
20
- services.push("HelloController");
21
-
6
+ const { appName = "app" } = options;
22
7
  return `
23
- ${imports.join("\n")}
8
+ import { $module } from "alepha";
9
+ import { HelloController } from "./controllers/HelloController.ts";
24
10
 
25
11
  export const ApiModule = $module({
26
12
  name: "${appName}.api",
27
- services: [${services.join(", ")}],
13
+ services: [HelloController],
28
14
  });
29
15
  `.trim();
30
16
  };
@@ -1,38 +1,4 @@
1
- export const mainCss = (opts: { ui?: boolean; tailwind?: boolean } = {}) => {
2
- if (opts.ui) {
3
- return `/**
4
- * Alepha UI - Based on Mantine component library
5
- * Mantine Docs: https://mantine.dev
6
- * Mantine LLM context: https://mantine.dev/llms.txt
7
- *
8
- * Switch theme index: alepha.set(alephaThemeAtom, { index: 1 })
9
- *
10
- * Custom themes (in src/web/index.ts):
11
- *
12
- * import { alephaThemeListAtom } from "@alepha/ui";
13
- *
14
- * export const WebModule = $module({
15
- * name: "app.web",
16
- * services: [AppRouter],
17
- * register(alepha) {
18
- * alepha.register(AppRouter);
19
- * alepha.set(alephaThemeListAtom, [{
20
- * name: "My Theme",
21
- * description: "Custom theme",
22
- * primaryColor: "blue",
23
- * defaultColorScheme: "dark",
24
- * // ...MantineThemeOverride options
25
- * }]);
26
- * },
27
- * });
28
- *
29
- * Alternatives (remove the import below):
30
- * - Tailwind CSS: https://tailwindcss.com/docs/installation/using-vite
31
- * - Raw CSS: Write your own styles
32
- */
33
- @import "@alepha/ui/styles";`;
34
- }
35
-
1
+ export const mainCss = (opts: { tailwind?: boolean } = {}) => {
36
2
  if (opts.tailwind) {
37
3
  return `@import "tailwindcss";
38
4
 
@@ -44,7 +10,6 @@ export const mainCss = (opts: { ui?: boolean; tailwind?: boolean } = {}) => {
44
10
  * Global styles for your application.
45
11
  *
46
12
  * Options:
47
- * - @alepha/ui: Use \`alepha init --ui\` to add Mantine-based components
48
13
  * - Tailwind CSS: Use \`alepha init --tailwind\` to add Tailwind CSS
49
14
  * - Raw CSS: Write your own styles below
50
15
  */
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Minimal Vitest config for a freshly scaffolded Alepha project.
3
+ *
4
+ * Defines `test.root` explicitly so Vitest doesn't walk up the directory
5
+ * tree and inherit a parent monorepo config (which can pull in unrelated
6
+ * setup files, database connections, etc.).
7
+ */
8
+ export const vitestConfigTs = () =>
9
+ `import { defineConfig } from "vitest/config";
10
+
11
+ export default defineConfig({
12
+ test: {
13
+ root: ".",
14
+ globals: true,
15
+ },
16
+ });
17
+ `;
@@ -1,97 +1,14 @@
1
- export const webAppRouterTs = (options: {
2
- api?: boolean;
3
- ui?: boolean;
4
- auth?: boolean;
5
- admin?: boolean;
6
- }) => {
7
- const imports: string[] = [];
1
+ export const webAppRouterTs = (options: { api?: boolean }) => {
2
+ const imports: string[] = ['import { $page } from "alepha/react/router";'];
8
3
  const classMembers: string[] = [];
9
4
 
10
- // UI import and setup
11
- if (options.ui) {
12
- imports.push('import { $ui } from "@alepha/ui";');
13
- }
14
-
15
- // Auth import
16
- if (options.auth) {
17
- imports.push('import { $uiAuth } from "@alepha/ui/auth";');
18
- }
19
-
20
- // Admin imports
21
- if (options.admin) {
22
- imports.push('import { $uiAdmin } from "@alepha/ui/admin";');
23
- imports.push('import { AdminUserRouter } from "@alepha/ui/admin-users";');
24
- imports.push(
25
- 'import { AdminSessionRouter } from "@alepha/ui/admin-sessions";',
26
- );
27
- imports.push('import { $inject } from "alepha";');
28
- imports.push(
29
- 'import { IconLayoutDashboard, IconUsers } from "@tabler/icons-react";',
30
- );
31
- }
32
-
33
- // Page import
34
- imports.push('import { $page } from "alepha/react/router";');
35
-
36
- // API imports (only if api flag is set)
37
5
  if (options.api) {
38
6
  imports.push('import { $client } from "alepha/server/links";');
39
7
  imports.push(
40
8
  'import type { HelloController } from "../api/controllers/HelloController.ts";',
41
9
  );
42
10
  classMembers.push(" api = $client<HelloController>();");
43
- }
44
-
45
- // UI layout setup
46
- if (options.ui) {
47
- classMembers.push(" ui = $ui();");
48
-
49
- if (options.auth) {
50
- classMembers.push(" uiAuth = $uiAuth();");
51
- }
52
-
53
- if (options.admin) {
54
- classMembers.push(` // ── Admin Dashboard ─────────────────────────────
55
- // Defined first so it can be referenced by the admin panel below.
56
- // \`$uiAdmin\` auto-parents listed pages under the admin layout.
57
- adminDashboard = $page({
58
- path: "/",
59
- label: "Dashboard",
60
- icon: IconLayoutDashboard,
61
- lazy: () => import("./components/AdminDashboard.tsx"),
62
- });
63
-
64
- // ── Admin Domain Routers ──────────────────────────
65
- protected users = $inject(AdminUserRouter);
66
- protected sessions = $inject(AdminSessionRouter);
67
11
 
68
- // ── Admin Panel ─────────────────────────────────
69
- admin = $uiAdmin({
70
- pages: [
71
- this.adminDashboard,
72
- this.users.adminUsers,
73
- this.users.adminUserLayout,
74
- this.sessions.adminSessions,
75
- ],
76
- sidebarItems: [
77
- this.adminDashboard,
78
- {
79
- label: "Identity",
80
- icon: IconUsers,
81
- children: [this.users.adminUsers, this.sessions.adminSessions],
82
- },
83
- ],
84
- });`);
85
- }
86
-
87
- classMembers.push(` layout = $page({
88
- parent: this.ui.root,
89
- children: () => [this.home],
90
- });`);
91
- }
92
-
93
- // Home page - with or without loader
94
- if (options.api) {
95
12
  classMembers.push(` home = $page({
96
13
  path: "/",
97
14
  lazy: () => import("./components/Home.tsx"),
@@ -119,6 +119,18 @@ class MemoryCloudflareApi extends CloudflareApi {
119
119
  return this.secrets.get(scriptName) ?? [];
120
120
  }
121
121
 
122
+ public override async putSecret(
123
+ scriptName: string,
124
+ name: string,
125
+ _value: string,
126
+ ) {
127
+ const existing = this.secrets.get(scriptName) ?? [];
128
+ if (!existing.some((s) => s.name === name)) {
129
+ existing.push({ name, type: "secret_text" });
130
+ }
131
+ this.secrets.set(scriptName, existing);
132
+ }
133
+
122
134
  public override async listDeployments() {
123
135
  return [];
124
136
  }
@@ -379,10 +391,10 @@ describe("CloudflareAdapter", () => {
379
391
  });
380
392
 
381
393
  describe("secrets", () => {
382
- test("pushes non-binding env vars via wrangler secret bulk", async ({
394
+ test("pushes non-binding env vars via REST putSecret", async ({
383
395
  expect,
384
396
  }) => {
385
- const { adapter, fs, shell, naming } = createTestEnv();
397
+ const { adapter, fs, naming, api } = createTestEnv();
386
398
  const ctx = makeCtx(naming, {
387
399
  apps: [
388
400
  {
@@ -400,7 +412,6 @@ describe("CloudflareAdapter", () => {
400
412
  ],
401
413
  });
402
414
 
403
- // Write .env.production with a mix of secrets and excluded vars
404
415
  await fs.writeFile(
405
416
  "/project/.env.production",
406
417
  [
@@ -418,62 +429,13 @@ describe("CloudflareAdapter", () => {
418
429
  const run = createMockRun();
419
430
  await adapter.secrets(ctx, run);
420
431
 
421
- // Should call wrangler secret bulk with the worker name
422
- expect(
423
- shell.wasCalledMatching(
424
- /wrangler secret bulk.*--name=acme-portal-production/,
425
- ),
426
- ).toBe(true);
427
-
428
- // Verify the secrets JSON was written (only non-excluded vars)
429
- expect(
430
- fs.wasWrittenMatching(
431
- "/project/node_modules/.alepha/secrets.json",
432
- /GOOGLE_API_KEY/,
433
- ),
434
- ).toBe(true);
435
- expect(
436
- fs.wasWrittenMatching(
437
- "/project/node_modules/.alepha/secrets.json",
438
- /APP_SECRET/,
439
- ),
440
- ).toBe(true);
441
-
442
- // Excluded vars should NOT be in the secrets file
443
- expect(
444
- fs.wasWrittenMatching(
445
- "/project/node_modules/.alepha/secrets.json",
446
- /DATABASE_URL/,
447
- ),
448
- ).toBe(false);
449
- expect(
450
- fs.wasWrittenMatching(
451
- "/project/node_modules/.alepha/secrets.json",
452
- /R2_BUCKET_NAME/,
453
- ),
454
- ).toBe(false);
455
- expect(
456
- fs.wasWrittenMatching(
457
- "/project/node_modules/.alepha/secrets.json",
458
- /CLOUDFLARE_DOMAIN/,
459
- ),
460
- ).toBe(false);
461
- expect(
462
- fs.wasWrittenMatching(
463
- "/project/node_modules/.alepha/secrets.json",
464
- /VITE_PUBLIC_KEY/,
465
- ),
466
- ).toBe(false);
467
- expect(
468
- fs.wasWrittenMatching(
469
- "/project/node_modules/.alepha/secrets.json",
470
- /NODE_ENV/,
471
- ),
472
- ).toBe(false);
432
+ const pushed = api.secrets.get("acme-portal-production") ?? [];
433
+ const names = pushed.map((s) => s.name).sort();
434
+ expect(names).toEqual(["APP_SECRET", "GOOGLE_API_KEY"]);
473
435
  });
474
436
 
475
437
  test("skips when no env file exists", async ({ expect }) => {
476
- const { adapter, shell, naming } = createTestEnv();
438
+ const { adapter, naming, api } = createTestEnv();
477
439
  const ctx = makeCtx(naming, {
478
440
  apps: [
479
441
  {
@@ -494,11 +456,11 @@ describe("CloudflareAdapter", () => {
494
456
  const run = createMockRun();
495
457
  await adapter.secrets(ctx, run);
496
458
 
497
- expect(shell.wasCalledMatching(/wrangler secret/)).toBe(false);
459
+ expect(api.secrets.size).toBe(0);
498
460
  });
499
461
 
500
462
  test("skips comments and empty lines", async ({ expect }) => {
501
- const { adapter, fs, shell, naming } = createTestEnv();
463
+ const { adapter, fs, naming, api } = createTestEnv();
502
464
  const ctx = makeCtx(naming, {
503
465
  apps: [
504
466
  {
@@ -524,19 +486,8 @@ describe("CloudflareAdapter", () => {
524
486
  const run = createMockRun();
525
487
  await adapter.secrets(ctx, run);
526
488
 
527
- expect(shell.wasCalledMatching(/wrangler secret bulk/)).toBe(true);
528
- expect(
529
- fs.wasWrittenMatching(
530
- "/project/node_modules/.alepha/secrets.json",
531
- /ONLY_SECRET/,
532
- ),
533
- ).toBe(true);
534
- expect(
535
- fs.wasWrittenMatching(
536
- "/project/node_modules/.alepha/secrets.json",
537
- /comment/,
538
- ),
539
- ).toBe(false);
489
+ const pushed = api.secrets.get("acme-portal-production") ?? [];
490
+ expect(pushed.map((s) => s.name)).toEqual(["ONLY_SECRET"]);
540
491
  });
541
492
  });
542
493
 
@@ -1,5 +1,4 @@
1
1
  import { $inject, Alepha } from "alepha";
2
- import { AlephaCliUtils } from "alepha/cli";
3
2
  import { EnvUtils, Runner, type RunnerMethod } from "alepha/command";
4
3
  import { $logger } from "alepha/logger";
5
4
  import { FileSystemProvider, ShellProvider } from "alepha/system";
@@ -24,7 +23,6 @@ export class CloudflareAdapter extends PlatformAdapter {
24
23
  protected readonly log = $logger();
25
24
  protected readonly fs = $inject(FileSystemProvider);
26
25
  protected readonly shell = $inject(ShellProvider);
27
- protected readonly utils = $inject(AlephaCliUtils);
28
26
  protected readonly cache = $inject(PlatformCacheProvider);
29
27
  protected readonly alepha = $inject(Alepha);
30
28
  protected readonly envUtils = $inject(EnvUtils);
@@ -57,6 +55,7 @@ export class CloudflareAdapter extends PlatformAdapter {
57
55
  */
58
56
  protected configureApi(ctx: PlatformContext): void {
59
57
  this.api.setJurisdiction(ctx.envConfig.jurisdiction);
58
+ this.api.setAccountId(ctx.envConfig.accountId);
60
59
  }
61
60
 
62
61
  protected async runShell(
@@ -256,7 +255,9 @@ export class CloudflareAdapter extends PlatformAdapter {
256
255
  return;
257
256
  }
258
257
 
259
- // Push secrets to each worker
258
+ // Push secrets to each worker via the REST API (one PUT per secret).
259
+ // Historically we shelled out to `wrangler secret bulk`, but it has an
260
+ // open hang issue (workers-sdk#10555) and is redundant given putSecret.
260
261
  for (const app of ctx.apps) {
261
262
  const workerName = ctx.naming.worker(
262
263
  ctx.apps.length > 1 ? app.name : undefined,
@@ -265,13 +266,9 @@ export class CloudflareAdapter extends PlatformAdapter {
265
266
  await run({
266
267
  name: `push secrets to ${workerName}`,
267
268
  handler: async () => {
268
- const secretsPath = await this.utils.writeConfigFile(
269
- "secrets.json",
270
- JSON.stringify(secrets),
271
- ctx.root,
272
- );
273
-
274
- await this.wrangler.secretBulk(secretsPath, workerName);
269
+ for (const [name, value] of Object.entries(secrets)) {
270
+ await this.api.putSecret(workerName, name, value);
271
+ }
275
272
  },
276
273
  });
277
274
  }
@@ -882,7 +879,11 @@ export class CloudflareAdapter extends PlatformAdapter {
882
879
  > {
883
880
  const deployments = await this.api.listDeployments(workerName);
884
881
 
885
- const latest = deployments.at(-1);
882
+ // API ordering is not guaranteed across releases — sort explicitly.
883
+ const sorted = [...deployments].sort((a, b) =>
884
+ b.created_on.localeCompare(a.created_on),
885
+ );
886
+ const latest = sorted[0];
886
887
  if (!latest?.versions?.[0]) {
887
888
  return undefined;
888
889
  }
@@ -74,6 +74,14 @@ export const platformOptions = $atom({
74
74
  * Omit for the default (global) jurisdiction.
75
75
  */
76
76
  jurisdiction: t.optional(t.enum(["eu", "fedramp"])),
77
+ /**
78
+ * Cloudflare account ID to deploy into.
79
+ *
80
+ * Falls back to `CLOUDFLARE_ACCOUNT_ID` env var, then to the
81
+ * token's account when the token is scoped to exactly one.
82
+ * Required when the token has access to multiple accounts.
83
+ */
84
+ accountId: t.optional(t.text()),
77
85
  }),
78
86
  ),
79
87
  }),
@@ -93,4 +101,5 @@ export interface EnvironmentConfig {
93
101
  domain?: string;
94
102
  vars?: Record<string, string>;
95
103
  jurisdiction?: "eu" | "fedramp";
104
+ accountId?: string;
96
105
  }
@@ -40,7 +40,7 @@ export type CloudflareKV = Static<typeof cloudflareKVSchema>;
40
40
 
41
41
  export const cloudflareR2Schema = t.object({
42
42
  name: t.string(),
43
- creation_date: t.string(),
43
+ creation_date: t.optional(t.string()),
44
44
  });
45
45
 
46
46
  export type CloudflareR2 = Static<typeof cloudflareR2Schema>;
@@ -61,8 +61,9 @@ export const cloudflareQueueSchema = t.object({
61
61
  export type CloudflareQueue = Static<typeof cloudflareQueueSchema>;
62
62
 
63
63
  export const cloudflareQueueConsumerSchema = t.object({
64
+ consumer_id: t.string(),
64
65
  service: t.string(),
65
- environment: t.string(),
66
+ environment: t.optional(t.string()),
66
67
  });
67
68
 
68
69
  export type CloudflareQueueConsumer = Static<