alepha 0.20.1 → 0.20.3
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 +0 -1
- package/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/assets/swagger-ui/swagger-ui.css +1 -1
- package/dist/api/audits/index.browser.js +49 -0
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +49 -0
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +2 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +64 -148
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +339 -600
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +605 -1012
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.d.ts +79 -27
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +90 -23
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/organizations/index.d.ts.map +1 -1
- package/dist/api/parameters/index.browser.js +37 -0
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +4 -65
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +37 -0
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.d.ts +2 -1
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/payments/index.js +4 -2
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/users/index.d.ts +225 -5199
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +15 -11
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +4 -2
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/bucket/index.js +5 -1
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +5 -1
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/captcha/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +225 -11681
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +732 -257
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.js +7 -1
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +65 -63
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +140 -27
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.js +15 -0
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.d.ts +1 -1
- package/dist/command/index.js +1 -1
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +6 -0
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +8 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +6 -0
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +6 -0
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.js.map +1 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/smtp/index.js +2 -10522
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +4 -8085
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +3 -33554
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.js +32 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.js +5 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +1 -361
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +14 -406
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +96 -5117
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +23 -419
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +17 -20
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +2 -613
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +17 -20
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +60 -1
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +86 -1
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/head/index.browser.js +16 -1
- package/dist/react/head/index.browser.js.map +1 -1
- package/dist/react/head/index.d.ts +6 -0
- package/dist/react/head/index.d.ts.map +1 -1
- package/dist/react/head/index.js +16 -1
- package/dist/react/head/index.js.map +1 -1
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.js +22 -17
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +78 -12
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +57 -13
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +102 -14
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/index.d.ts +1 -411
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +13 -12293
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/ui/index.d.ts +124 -0
- package/dist/react/ui/index.d.ts.map +1 -0
- package/dist/react/ui/index.js +209 -0
- package/dist/react/ui/index.js.map +1 -0
- package/dist/react/websocket/index.js.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/router/index.d.ts +13 -13
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js +45 -32
- package/dist/router/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +1 -83
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +2 -391
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +2 -391
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +2 -325
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +3 -1362
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +1 -1054
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +16 -1224
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +1 -4
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +19 -4
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +1 -514
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +4 -4356
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.js +1 -1
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js.map +1 -1
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +1 -0
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.workerd.js.map +1 -1
- package/dist/topic/core/index.js +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/websocket/index.browser.js +21 -0
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.js +21 -0
- package/dist/websocket/index.js.map +1 -1
- package/package.json +23 -37
- package/src/api/files/__tests__/FileController.spec.ts +1 -1
- package/src/api/files/jobs/FileJobs.ts +2 -1
- package/src/api/jobs/__tests__/$job.spec.ts +320 -2867
- package/src/api/jobs/controllers/AdminJobController.ts +29 -138
- package/src/api/jobs/entities/jobExecutionEntity.ts +27 -19
- package/src/api/jobs/index.browser.ts +5 -7
- package/src/api/jobs/index.ts +23 -51
- package/src/api/jobs/primitives/$job.ts +66 -58
- package/src/api/jobs/providers/JobProvider.ts +561 -566
- package/src/api/jobs/providers/JobQueueProvider.ts +18 -19
- package/src/api/jobs/schemas/jobConfigAtom.ts +20 -23
- package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +3 -27
- package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +5 -7
- package/src/api/jobs/schemas/jobRegistrationSchema.ts +7 -4
- package/src/api/jobs/schemas/triggerJobSchema.ts +0 -1
- package/src/api/jobs/services/JobService.ts +90 -483
- package/src/api/notifications/controllers/AdminNotificationController.ts +19 -12
- package/src/api/notifications/index.ts +7 -4
- package/src/api/notifications/jobs/NotificationJobs.ts +83 -12
- package/src/api/payments/services/PaymentService.ts +4 -2
- package/src/api/users/__tests__/UserJobs.spec.ts +10 -49
- package/src/api/users/audits/UserAudits.ts +3 -1
- package/src/api/users/buckets/UserBuckets.ts +2 -1
- package/src/api/users/index.ts +1 -4
- package/src/api/users/jobs/UserJobs.ts +5 -4
- package/src/api/users/schemas/userQuerySchema.ts +0 -1
- package/src/api/users/services/UserService.ts +1 -5
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +14 -0
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +14 -0
- package/src/api/verifications/jobs/VerificationJobs.ts +2 -1
- package/src/api/verifications/services/VerificationService.ts +1 -0
- package/src/cli/core/__tests__/init.spec.ts +209 -1
- package/src/cli/core/commands/init.ts +9 -9
- package/src/cli/core/services/PackageManagerUtils.ts +22 -12
- package/src/cli/core/services/ProjectScaffolder.ts +300 -70
- package/src/cli/core/tasks/BuildDockerTask.ts +9 -10
- package/src/cli/core/tasks/BuildServerTask.ts +8 -0
- package/src/cli/core/templates/agentMd.ts +2 -8
- package/src/cli/core/templates/apiIndexTs.ts +22 -14
- package/src/cli/core/templates/componentsJsonTs.ts +39 -0
- package/src/cli/core/templates/mainCss.ts +2 -36
- package/src/cli/core/templates/saasAdminLayoutTsx.ts +77 -0
- package/src/cli/core/templates/saasAdminPagesTsx.ts +26 -0
- package/src/cli/core/templates/saasAuthLayoutTsx.ts +20 -0
- package/src/cli/core/templates/saasAuthPagesTsx.ts +62 -0
- package/src/cli/core/templates/saasRealmProviderTs.ts +46 -0
- package/src/cli/core/templates/vitestConfigTs.ts +17 -0
- package/src/cli/core/templates/webAppRouterTs.ts +102 -82
- package/src/cli/core/templates/webIndexTs.ts +23 -1
- package/src/cli/platform/__tests__/CloudflareAdapter.spec.ts +22 -71
- package/src/cli/platform/__tests__/SecretsCommand.spec.ts +2 -0
- package/src/cli/platform/adapters/CloudflareAdapter.ts +12 -11
- package/src/cli/platform/atoms/platformOptions.ts +9 -0
- package/src/cli/platform/schemas/cloudflare.ts +3 -2
- package/src/cli/platform/services/CloudflareApi.ts +164 -25
- package/src/cli/platform/services/WranglerApi.ts +0 -17
- package/src/command/providers/CliProvider.ts +1 -1
- package/src/core/Alepha.ts +9 -0
- package/src/core/interfaces/Service.ts +3 -1
- package/src/core/providers/TypeProvider.ts +1 -1
- package/src/logger/services/Logger.ts +1 -1
- package/src/mcp/__tests__/$resource.spec.ts +1 -1
- package/src/mcp/__tests__/$tool.spec.ts +1 -1
- package/src/mcp/__tests__/McpServerProvider.spec.ts +1 -1
- package/src/orm/__tests__/$repository-tests.ts +1 -0
- package/src/orm/__tests__/orm-next-tests.ts +2 -67
- package/src/orm/__tests__/orm-next.spec.ts +0 -21
- package/src/orm/core/index.shared.ts +0 -2
- package/src/orm/core/index.ts +1 -2
- package/src/orm/core/primitives/$repository.ts +3 -6
- package/src/orm/core/providers/drivers/DatabaseProvider.ts +0 -5
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +11 -13
- package/src/orm/core/services/ModelBuilder.ts +1 -13
- package/src/orm/core/services/Repository.ts +1 -42
- package/src/orm/core/services/SqliteModelBuilder.ts +2 -33
- package/src/orm/postgres/services/PostgresModelBuilder.ts +10 -45
- package/src/react/form/index.ts +2 -0
- package/src/react/form/services/parseField.ts +163 -0
- package/src/react/form/services/prettyName.ts +19 -0
- package/src/react/head/providers/BrowserHeadProvider.ts +31 -10
- package/src/react/intro/components/GettingStartedAuthSlide.tsx +11 -4
- package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +213 -2
- package/src/react/router/primitives/$page.ts +35 -12
- package/src/react/router/providers/ReactBrowserProvider.ts +73 -0
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +1 -1
- package/src/react/router/providers/ReactPreloadProvider.ts +1 -1
- package/src/react/router/providers/ReactServerProvider.ts +1 -0
- package/src/react/ui/atoms/uiAtom.ts +28 -0
- package/src/react/ui/components/ColorScheme.tsx +36 -0
- package/src/react/ui/hooks/useColorMode.ts +49 -0
- package/src/react/ui/hooks/useSidebarState.ts +26 -0
- package/src/react/ui/hooks/useTheme.ts +22 -0
- package/src/react/ui/index.ts +35 -0
- package/src/react/ui/services/UiPersistence.ts +41 -0
- package/src/router/TemplatedPathParser.ts +50 -51
- package/src/router/__tests__/RouterProvider.spec.ts +62 -0
- package/src/router/__tests__/TemplatedPathParser.spec.ts +18 -0
- package/src/router/providers/RouterProvider.ts +10 -5
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/primitives/$basicAuth.ts +1 -1
- package/src/server/auth/providers/ServerAuthProvider.ts +5 -1
- package/src/server/core/interfaces/ServerRequest.ts +1 -0
- package/src/server/core/providers/ServerProvider.ts +1 -1
- package/src/server/core/providers/ServerRouterProvider.ts +2 -2
- package/src/server/core/services/HttpClient.ts +1 -1
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +1 -1
- package/src/system/providers/NodeShellProvider.ts +1 -0
- package/src/topic/core/providers/TopicProvider.ts +1 -1
- package/dist/api/invitations/index.d.ts +0 -790
- package/dist/api/invitations/index.d.ts.map +0 -1
- package/dist/api/invitations/index.js +0 -662
- package/dist/api/invitations/index.js.map +0 -1
- package/dist/api/issues/index.d.ts +0 -810
- package/dist/api/issues/index.d.ts.map +0 -1
- package/dist/api/issues/index.js +0 -444
- package/dist/api/issues/index.js.map +0 -1
- package/dist/api/subscriptions/index.d.ts +0 -1692
- package/dist/api/subscriptions/index.d.ts.map +0 -1
- package/dist/api/subscriptions/index.js +0 -1867
- package/dist/api/subscriptions/index.js.map +0 -1
- package/dist/api/workflows/index.browser.js +0 -246
- package/dist/api/workflows/index.browser.js.map +0 -1
- package/dist/api/workflows/index.d.ts +0 -1618
- package/dist/api/workflows/index.d.ts.map +0 -1
- package/dist/api/workflows/index.js +0 -1495
- package/dist/api/workflows/index.js.map +0 -1
- package/dist/react/testing/chunk-DBEY4PJZ.js +0 -16
- package/src/api/invitations/__tests__/InvitationService.spec.ts +0 -439
- package/src/api/invitations/controllers/AdminInvitationController.ts +0 -86
- package/src/api/invitations/controllers/InvitationController.ts +0 -84
- package/src/api/invitations/entities/invitations.ts +0 -33
- package/src/api/invitations/index.ts +0 -58
- package/src/api/invitations/jobs/InvitationJobs.ts +0 -37
- package/src/api/invitations/providers/InvitationProvider.ts +0 -45
- package/src/api/invitations/schemas/createInvitationSchema.ts +0 -12
- package/src/api/invitations/schemas/invitationConfigAtom.ts +0 -20
- package/src/api/invitations/schemas/invitationQuerySchema.ts +0 -15
- package/src/api/invitations/schemas/invitationResourceSchema.ts +0 -6
- package/src/api/invitations/schemas/invitationWithResourceInfoSchema.ts +0 -22
- package/src/api/invitations/schemas/myInvitationsQuerySchema.ts +0 -10
- package/src/api/invitations/services/InvitationService.ts +0 -556
- package/src/api/issues/__tests__/IssueService.spec.ts +0 -263
- package/src/api/issues/controllers/AdminIssueController.ts +0 -149
- package/src/api/issues/controllers/IssueController.ts +0 -44
- package/src/api/issues/entities/issues.ts +0 -49
- package/src/api/issues/index.ts +0 -50
- package/src/api/issues/schemas/createIssueSchema.ts +0 -13
- package/src/api/issues/schemas/issueConfigAtom.ts +0 -13
- package/src/api/issues/schemas/issueQuerySchema.ts +0 -18
- package/src/api/issues/schemas/issueResourceSchema.ts +0 -6
- package/src/api/issues/schemas/myIssueQuerySchema.ts +0 -10
- package/src/api/issues/schemas/updateIssueSchema.ts +0 -13
- package/src/api/issues/services/IssueService.ts +0 -264
- package/src/api/jobs/__tests__/$job-middleware.spec.ts +0 -126
- package/src/api/jobs/__tests__/JobService.spec.ts +0 -31
- package/src/api/jobs/entities/jobExecutionLogEntity.ts +0 -13
- package/src/api/jobs/schemas/jobActivitySchema.ts +0 -15
- package/src/api/jobs/schemas/jobCronInfoSchema.ts +0 -22
- package/src/api/jobs/schemas/jobExecutionDetailResourceSchema.ts +0 -20
- package/src/api/jobs/schemas/jobFailureSchema.ts +0 -9
- package/src/api/jobs/schemas/jobQueueDepthSchema.ts +0 -14
- package/src/api/jobs/schemas/jobStatsSchema.ts +0 -14
- package/src/api/jobs/services/JobService-tests.ts +0 -157
- package/src/api/subscriptions/__tests__/BillingService.spec.ts +0 -218
- package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +0 -278
- package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +0 -212
- package/src/api/subscriptions/controllers/SubscriptionController.ts +0 -189
- package/src/api/subscriptions/entities/subscriptionEvents.ts +0 -54
- package/src/api/subscriptions/entities/subscriptions.ts +0 -68
- package/src/api/subscriptions/index.ts +0 -133
- package/src/api/subscriptions/jobs/SubscriptionJobs.ts +0 -382
- package/src/api/subscriptions/middleware/$requireLimit.ts +0 -50
- package/src/api/subscriptions/middleware/$requirePlan.ts +0 -49
- package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +0 -110
- package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +0 -8
- package/src/api/subscriptions/schemas/changePlanSchema.ts +0 -9
- package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +0 -11
- package/src/api/subscriptions/schemas/entitlementsSchema.ts +0 -21
- package/src/api/subscriptions/schemas/mrrSchema.ts +0 -13
- package/src/api/subscriptions/schemas/planDefinitionSchema.ts +0 -71
- package/src/api/subscriptions/schemas/planResourceSchema.ts +0 -25
- package/src/api/subscriptions/schemas/subscriptionEventResourceSchema.ts +0 -8
- package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +0 -19
- package/src/api/subscriptions/schemas/subscriptionResourceSchema.ts +0 -6
- package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +0 -32
- package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +0 -23
- package/src/api/subscriptions/services/BillingService.ts +0 -437
- package/src/api/subscriptions/services/SubscriptionConfig.ts +0 -56
- package/src/api/subscriptions/services/SubscriptionService.ts +0 -867
- package/src/api/subscriptions/services/UsageService.ts +0 -118
- package/src/api/workflows/__tests__/$workflow.spec.ts +0 -616
- package/src/api/workflows/controllers/AdminWorkflowController.ts +0 -191
- package/src/api/workflows/entities/workflowExecutions.ts +0 -74
- package/src/api/workflows/entities/workflowStepExecutions.ts +0 -74
- package/src/api/workflows/entities/workflowStepLogs.ts +0 -13
- package/src/api/workflows/index.browser.ts +0 -22
- package/src/api/workflows/index.ts +0 -115
- package/src/api/workflows/jobs/WorkflowJobs.ts +0 -77
- package/src/api/workflows/primitives/$workflow.ts +0 -202
- package/src/api/workflows/providers/WorkflowProvider.ts +0 -1284
- package/src/api/workflows/schemas/workflowActivitySchema.ts +0 -15
- package/src/api/workflows/schemas/workflowConfigAtom.ts +0 -51
- package/src/api/workflows/schemas/workflowExecutionDetailSchema.ts +0 -18
- package/src/api/workflows/schemas/workflowExecutionQuerySchema.ts +0 -26
- package/src/api/workflows/schemas/workflowExecutionResourceSchema.ts +0 -30
- package/src/api/workflows/schemas/workflowRegistrationSchema.ts +0 -26
- package/src/api/workflows/schemas/workflowStatsSchema.ts +0 -16
- package/src/api/workflows/schemas/workflowStepExecutionResourceSchema.ts +0 -15
- package/src/api/workflows/services/WorkflowService.ts +0 -382
- package/src/cli/core/templates/apiAppSecurityTs.ts +0 -43
- package/src/cli/core/templates/webAdminDashboardTsx.ts +0 -17
- package/src/orm/core/__tests__/parseQueryString.spec.ts +0 -196
- package/src/orm/core/helpers/parseQueryString.ts +0 -502
- package/src/orm/core/primitives/$view.ts +0 -88
package/dist/cli/core/index.js
CHANGED
|
@@ -37,7 +37,20 @@ const buildOptions = $atom({
|
|
|
37
37
|
name: "alepha.cli.build.options",
|
|
38
38
|
description: "Build configuration options",
|
|
39
39
|
schema: t.object({
|
|
40
|
+
/**
|
|
41
|
+
* Generate build stats report.
|
|
42
|
+
*
|
|
43
|
+
* - `true` - Generate a static HTML report
|
|
44
|
+
* - `"json"` - Generate a JSON report
|
|
45
|
+
*/
|
|
40
46
|
stats: t.optional(t.union([t.boolean(), t.enum(["json"])])),
|
|
47
|
+
/**
|
|
48
|
+
* Deployment target for the build output.
|
|
49
|
+
*
|
|
50
|
+
* - `docker` - Generate Dockerfile for containerized deployment
|
|
51
|
+
* - `vercel` - Generate Vercel deployment configuration (forces node runtime)
|
|
52
|
+
* - `cloudflare` - Generate Cloudflare Workers configuration (forces workerd runtime)
|
|
53
|
+
*/
|
|
41
54
|
target: t.optional(t.enum([
|
|
42
55
|
"bare",
|
|
43
56
|
"docker",
|
|
@@ -45,15 +58,45 @@ const buildOptions = $atom({
|
|
|
45
58
|
"cloudflare",
|
|
46
59
|
"static"
|
|
47
60
|
])),
|
|
61
|
+
/**
|
|
62
|
+
* JavaScript runtime for the build output.
|
|
63
|
+
*
|
|
64
|
+
* - `node` - Node.js runtime (default)
|
|
65
|
+
* - `bun` - Bun runtime (uses bun export conditions)
|
|
66
|
+
* - `workerd` - Cloudflare Workers runtime (auto-set with cloudflare target)
|
|
67
|
+
*
|
|
68
|
+
* Note: Some targets force a specific runtime:
|
|
69
|
+
* - `cloudflare` always uses `workerd`
|
|
70
|
+
* - `vercel` always uses `node`
|
|
71
|
+
*/
|
|
48
72
|
runtime: t.optional(t.enum([
|
|
49
73
|
"node",
|
|
50
74
|
"bun",
|
|
51
75
|
"workerd"
|
|
52
76
|
])),
|
|
77
|
+
/**
|
|
78
|
+
* Output directory configuration.
|
|
79
|
+
*/
|
|
53
80
|
output: t.optional(t.object({
|
|
81
|
+
/**
|
|
82
|
+
* Root dist directory.
|
|
83
|
+
*
|
|
84
|
+
* @default "dist"
|
|
85
|
+
*/
|
|
54
86
|
dist: t.optional(t.string({ default: "dist" })),
|
|
87
|
+
/**
|
|
88
|
+
* Public/client subdirectory.
|
|
89
|
+
*
|
|
90
|
+
* @default "public"
|
|
91
|
+
*/
|
|
55
92
|
public: t.optional(t.string({ default: "public" }))
|
|
56
93
|
})),
|
|
94
|
+
/**
|
|
95
|
+
* Vercel-specific deployment configuration.
|
|
96
|
+
*
|
|
97
|
+
* Note: Set `target: "vercel"` to enable Vercel deployment.
|
|
98
|
+
* This object is only for additional configuration.
|
|
99
|
+
*/
|
|
57
100
|
vercel: t.optional(t.object({
|
|
58
101
|
projectName: t.optional(t.string()),
|
|
59
102
|
orgId: t.optional(t.string()),
|
|
@@ -63,31 +106,143 @@ const buildOptions = $atom({
|
|
|
63
106
|
schedule: t.string()
|
|
64
107
|
}))) }))
|
|
65
108
|
})),
|
|
109
|
+
/**
|
|
110
|
+
* Cloudflare-specific deployment configuration.
|
|
111
|
+
*
|
|
112
|
+
* Note: Set `target: "cloudflare"` to enable Cloudflare deployment.
|
|
113
|
+
* This object is only for additional configuration.
|
|
114
|
+
*/
|
|
66
115
|
cloudflare: t.optional(t.object({ config: t.optional(t.json()) })),
|
|
116
|
+
/**
|
|
117
|
+
* Docker-specific deployment configuration.
|
|
118
|
+
*
|
|
119
|
+
* Note: Set `target: "docker"` to enable Docker deployment.
|
|
120
|
+
* This object is only for additional configuration.
|
|
121
|
+
*/
|
|
67
122
|
docker: t.optional(t.object({
|
|
123
|
+
/**
|
|
124
|
+
* Base image for the Dockerfile (FROM instruction).
|
|
125
|
+
*
|
|
126
|
+
* @default "node:24-alpine" for node runtime
|
|
127
|
+
* @default "oven/bun:alpine" for bun runtime
|
|
128
|
+
*/
|
|
68
129
|
from: t.optional(t.string()),
|
|
130
|
+
/**
|
|
131
|
+
* Command to run in the Docker container.
|
|
132
|
+
*
|
|
133
|
+
* @default "node" for node runtime
|
|
134
|
+
* @default "bun" for bun runtime
|
|
135
|
+
*/
|
|
69
136
|
command: t.optional(t.string()),
|
|
137
|
+
/**
|
|
138
|
+
* Docker build options (used when --image flag is passed).
|
|
139
|
+
*/
|
|
70
140
|
image: t.optional(t.object({
|
|
141
|
+
/**
|
|
142
|
+
* Default image tag (name without version).
|
|
143
|
+
*
|
|
144
|
+
* Used when --image is provided without a full override:
|
|
145
|
+
* - `--image` → `tag:latest`
|
|
146
|
+
* - `--image=1.3.4` → `tag:1.3.4`
|
|
147
|
+
* - `--image=other/img:v1` → `other/img:v1` (full override)
|
|
148
|
+
*
|
|
149
|
+
* @example "myproject/myapp"
|
|
150
|
+
* @example "ghcr.io/myorg/myapp"
|
|
151
|
+
*/
|
|
71
152
|
tag: t.string(),
|
|
153
|
+
/**
|
|
154
|
+
* Additional arguments to pass to `docker build`.
|
|
155
|
+
*
|
|
156
|
+
* @example '--platform linux/amd64 --no-cache'
|
|
157
|
+
*/
|
|
72
158
|
args: t.optional(t.string()),
|
|
159
|
+
/**
|
|
160
|
+
* Auto-add OCI standard labels (revision, created, version).
|
|
161
|
+
*
|
|
162
|
+
* Adds:
|
|
163
|
+
* - org.opencontainers.image.revision (git commit SHA)
|
|
164
|
+
* - org.opencontainers.image.created (build timestamp)
|
|
165
|
+
* - org.opencontainers.image.version (from image tag)
|
|
166
|
+
*/
|
|
73
167
|
oci: t.optional(t.boolean())
|
|
74
168
|
}))
|
|
75
169
|
})),
|
|
76
|
-
|
|
170
|
+
/**
|
|
171
|
+
* Static site deployment configuration.
|
|
172
|
+
*
|
|
173
|
+
* Note: Set `target: "static"` to enable static site generation.
|
|
174
|
+
*/
|
|
175
|
+
static: t.optional(t.object({
|
|
176
|
+
/**
|
|
177
|
+
* Surge domain for deployment.
|
|
178
|
+
*
|
|
179
|
+
* If set, a CNAME file is written to dist/public/.
|
|
180
|
+
* If not set, a domain is auto-generated from package.json name.
|
|
181
|
+
*
|
|
182
|
+
* @example "my-app.surge.sh"
|
|
183
|
+
* @example "my-custom-domain.com"
|
|
184
|
+
*/
|
|
185
|
+
domain: t.optional(t.string()) })),
|
|
186
|
+
/**
|
|
187
|
+
* PWA (Progressive Web App) configuration.
|
|
188
|
+
*
|
|
189
|
+
* Generates a web app manifest and enables installability.
|
|
190
|
+
* Requires a client-side bundle (React).
|
|
191
|
+
*/
|
|
77
192
|
pwa: t.optional(t.object({
|
|
193
|
+
/**
|
|
194
|
+
* Full application name displayed on the splash screen
|
|
195
|
+
* and in the OS app switcher.
|
|
196
|
+
*/
|
|
78
197
|
name: t.string(),
|
|
198
|
+
/**
|
|
199
|
+
* Short name displayed on the home screen icon.
|
|
200
|
+
* Falls back to `name` if omitted.
|
|
201
|
+
*/
|
|
79
202
|
shortName: t.optional(t.string()),
|
|
203
|
+
/**
|
|
204
|
+
* Theme color used for the browser toolbar and OS chrome.
|
|
205
|
+
*
|
|
206
|
+
* @default "#ffffff"
|
|
207
|
+
*/
|
|
80
208
|
themeColor: t.optional(t.string()),
|
|
209
|
+
/**
|
|
210
|
+
* Background color for the splash screen.
|
|
211
|
+
*
|
|
212
|
+
* @default "#ffffff"
|
|
213
|
+
*/
|
|
81
214
|
backgroundColor: t.optional(t.string()),
|
|
215
|
+
/**
|
|
216
|
+
* Display mode for the installed PWA.
|
|
217
|
+
*
|
|
218
|
+
* - `standalone` - Looks like a native app (default)
|
|
219
|
+
* - `fullscreen` - Uses entire screen (games, immersive)
|
|
220
|
+
* - `minimal-ui` - Like standalone with minimal browser UI
|
|
221
|
+
* - `browser` - Standard browser tab
|
|
222
|
+
*
|
|
223
|
+
* @default "standalone"
|
|
224
|
+
*/
|
|
82
225
|
display: t.optional(t.enum([
|
|
83
226
|
"standalone",
|
|
84
227
|
"fullscreen",
|
|
85
228
|
"minimal-ui",
|
|
86
229
|
"browser"
|
|
87
230
|
])),
|
|
231
|
+
/**
|
|
232
|
+
* Enable offline support via service worker.
|
|
233
|
+
*
|
|
234
|
+
* TODO: Not yet implemented.
|
|
235
|
+
*/
|
|
88
236
|
offline: t.optional(t.boolean())
|
|
89
237
|
})),
|
|
90
|
-
|
|
238
|
+
/**
|
|
239
|
+
* Sitemap generation configuration.
|
|
240
|
+
*/
|
|
241
|
+
sitemap: t.optional(t.object({
|
|
242
|
+
/**
|
|
243
|
+
* Base URL for sitemap entries.
|
|
244
|
+
*/
|
|
245
|
+
hostname: t.string() }))
|
|
91
246
|
}),
|
|
92
247
|
default: {}
|
|
93
248
|
});
|
|
@@ -102,7 +257,11 @@ const buildOptions = $atom({
|
|
|
102
257
|
const devOptions = $atom({
|
|
103
258
|
name: "alepha.cli.dev.options",
|
|
104
259
|
description: "Dev configuration options",
|
|
105
|
-
schema: t.object({
|
|
260
|
+
schema: t.object({
|
|
261
|
+
/**
|
|
262
|
+
* Disable Vite React plugin.
|
|
263
|
+
*/
|
|
264
|
+
noViteReactPlugin: t.optional(t.boolean({ default: false })) }),
|
|
106
265
|
default: {}
|
|
107
266
|
});
|
|
108
267
|
//#endregion
|
|
@@ -598,7 +757,7 @@ var AlephaCliUtils = class {
|
|
|
598
757
|
};
|
|
599
758
|
//#endregion
|
|
600
759
|
//#region ../../package.json
|
|
601
|
-
var version$1 = "0.20.
|
|
760
|
+
var version$1 = "0.20.3";
|
|
602
761
|
//#endregion
|
|
603
762
|
//#region ../../src/cli/core/alephaPackageJson.ts
|
|
604
763
|
const alephaPackageJson = {
|
|
@@ -627,18 +786,19 @@ const alephaPackageJson = {
|
|
|
627
786
|
"drizzle-orm": "^0.45.2",
|
|
628
787
|
"postgres": "^3.4.9",
|
|
629
788
|
"tsx": "^4.21.0",
|
|
630
|
-
"typebox": "^1.1.
|
|
631
|
-
"typescript": "^6.0.
|
|
632
|
-
"vite-bundle-analyzer": "^1.3.
|
|
789
|
+
"typebox": "^1.1.34",
|
|
790
|
+
"typescript": "^6.0.3",
|
|
791
|
+
"vite-bundle-analyzer": "^1.3.8",
|
|
633
792
|
"ws": "^8.20.0"
|
|
634
793
|
},
|
|
635
794
|
devDependencies: {
|
|
636
|
-
"@biomejs/biome": "^2.4.
|
|
637
|
-
"@electric-sql/pglite": "^0.4.
|
|
795
|
+
"@biomejs/biome": "^2.4.13",
|
|
796
|
+
"@electric-sql/pglite": "^0.4.5",
|
|
638
797
|
"@faker-js/faker": "^10.4.0",
|
|
798
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
639
799
|
"@testing-library/dom": "^10.4.1",
|
|
640
800
|
"@testing-library/react": "^16.3.2",
|
|
641
|
-
"@types/bun": "^1.3.
|
|
801
|
+
"@types/bun": "^1.3.13",
|
|
642
802
|
"@types/node": "^25.6.0",
|
|
643
803
|
"@types/nodemailer": "^8.0.0",
|
|
644
804
|
"@types/react": "^19.2.14",
|
|
@@ -646,17 +806,19 @@ const alephaPackageJson = {
|
|
|
646
806
|
"@types/ws": "^8.18.1",
|
|
647
807
|
"cron-schedule": "^6.0.0",
|
|
648
808
|
"drizzle-kit": "^0.31.10",
|
|
649
|
-
"jose": "^6.2.
|
|
650
|
-
"jsdom": "^29.0
|
|
651
|
-
"nodemailer": "^8.0.
|
|
652
|
-
"openid-client": "^6.8.
|
|
809
|
+
"jose": "^6.2.3",
|
|
810
|
+
"jsdom": "^29.1.0",
|
|
811
|
+
"nodemailer": "^8.0.7",
|
|
812
|
+
"openid-client": "^6.8.4",
|
|
653
813
|
"prom-client": "^15.1.3",
|
|
654
814
|
"react": "^19.2.5",
|
|
655
815
|
"react-dom": "^19.2.5",
|
|
656
|
-
"
|
|
657
|
-
"
|
|
658
|
-
"
|
|
659
|
-
"
|
|
816
|
+
"shadcn": "^4.6.0",
|
|
817
|
+
"swagger-ui-dist": "^5.32.5",
|
|
818
|
+
"tailwindcss": "^4.2.4",
|
|
819
|
+
"tsdown": "^0.21.10",
|
|
820
|
+
"vite": "^8.0.10",
|
|
821
|
+
"vitest": "^4.1.5"
|
|
660
822
|
},
|
|
661
823
|
peerDependencies: {
|
|
662
824
|
"react": "^19",
|
|
@@ -703,16 +865,6 @@ const alephaPackageJson = {
|
|
|
703
865
|
"import": "./src/api/files/index.ts",
|
|
704
866
|
"default": "./src/api/files/index.ts"
|
|
705
867
|
},
|
|
706
|
-
"./api/invitations": {
|
|
707
|
-
"types": "./src/api/invitations/index.ts",
|
|
708
|
-
"import": "./src/api/invitations/index.ts",
|
|
709
|
-
"default": "./src/api/invitations/index.ts"
|
|
710
|
-
},
|
|
711
|
-
"./api/issues": {
|
|
712
|
-
"types": "./src/api/issues/index.ts",
|
|
713
|
-
"import": "./src/api/issues/index.ts",
|
|
714
|
-
"default": "./src/api/issues/index.ts"
|
|
715
|
-
},
|
|
716
868
|
"./api/jobs": {
|
|
717
869
|
"types": "./src/api/jobs/index.ts",
|
|
718
870
|
"react-native": "./src/api/jobs/index.browser.ts",
|
|
@@ -751,11 +903,6 @@ const alephaPackageJson = {
|
|
|
751
903
|
"import": "./src/api/payments/index.ts",
|
|
752
904
|
"default": "./src/api/payments/index.ts"
|
|
753
905
|
},
|
|
754
|
-
"./api/subscriptions": {
|
|
755
|
-
"types": "./src/api/subscriptions/index.ts",
|
|
756
|
-
"import": "./src/api/subscriptions/index.ts",
|
|
757
|
-
"default": "./src/api/subscriptions/index.ts"
|
|
758
|
-
},
|
|
759
906
|
"./api/users": {
|
|
760
907
|
"types": "./src/api/users/index.ts",
|
|
761
908
|
"react-native": "./src/api/users/index.browser.ts",
|
|
@@ -770,13 +917,6 @@ const alephaPackageJson = {
|
|
|
770
917
|
"import": "./src/api/verifications/index.ts",
|
|
771
918
|
"default": "./src/api/verifications/index.ts"
|
|
772
919
|
},
|
|
773
|
-
"./api/workflows": {
|
|
774
|
-
"types": "./src/api/workflows/index.ts",
|
|
775
|
-
"react-native": "./src/api/workflows/index.browser.ts",
|
|
776
|
-
"browser": "./src/api/workflows/index.browser.ts",
|
|
777
|
-
"import": "./src/api/workflows/index.ts",
|
|
778
|
-
"default": "./src/api/workflows/index.ts"
|
|
779
|
-
},
|
|
780
920
|
"./batch": {
|
|
781
921
|
"types": "./src/batch/index.ts",
|
|
782
922
|
"import": "./src/batch/index.ts",
|
|
@@ -971,6 +1111,11 @@ const alephaPackageJson = {
|
|
|
971
1111
|
"import": "./src/react/testing/index.ts",
|
|
972
1112
|
"default": "./src/react/testing/index.ts"
|
|
973
1113
|
},
|
|
1114
|
+
"./react/ui": {
|
|
1115
|
+
"types": "./src/react/ui/index.ts",
|
|
1116
|
+
"import": "./src/react/ui/index.ts",
|
|
1117
|
+
"default": "./src/react/ui/index.ts"
|
|
1118
|
+
},
|
|
974
1119
|
"./react/websocket": {
|
|
975
1120
|
"types": "./src/react/websocket/index.ts",
|
|
976
1121
|
"import": "./src/react/websocket/index.ts",
|
|
@@ -1302,14 +1447,14 @@ var PackageManagerUtils = class {
|
|
|
1302
1447
|
"yarn.lock"
|
|
1303
1448
|
]);
|
|
1304
1449
|
await this.editPackageJson(root, (pkg) => {
|
|
1305
|
-
|
|
1450
|
+
pkg.packageManager = void 0;
|
|
1306
1451
|
return pkg;
|
|
1307
1452
|
});
|
|
1308
1453
|
}
|
|
1309
1454
|
async removePnpm(root) {
|
|
1310
1455
|
await this.removeFiles(root, ["pnpm-lock.yaml", "pnpm-workspace.yaml"]);
|
|
1311
1456
|
await this.editPackageJson(root, (pkg) => {
|
|
1312
|
-
|
|
1457
|
+
pkg.packageManager = void 0;
|
|
1313
1458
|
return pkg;
|
|
1314
1459
|
});
|
|
1315
1460
|
}
|
|
@@ -1359,7 +1504,7 @@ var PackageManagerUtils = class {
|
|
|
1359
1504
|
const alephaDeps = alephaPackageJson.devDependencies;
|
|
1360
1505
|
const dependencies = { alepha: `^${version}` };
|
|
1361
1506
|
const devDependencies = { vite: alephaDeps.vite };
|
|
1362
|
-
if (!
|
|
1507
|
+
if (!modes.react || modes.saas) devDependencies["drizzle-kit"] = alephaDeps["drizzle-kit"];
|
|
1363
1508
|
if (!modes.isPackage) {
|
|
1364
1509
|
devDependencies["@biomejs/biome"] = alephaDeps["@biomejs/biome"];
|
|
1365
1510
|
if (modes.test) devDependencies.vitest = alephaDeps.vitest;
|
|
@@ -1372,14 +1517,11 @@ var PackageManagerUtils = class {
|
|
|
1372
1517
|
verify: "alepha verify"
|
|
1373
1518
|
};
|
|
1374
1519
|
if (modes.test) scripts.test = "vitest run";
|
|
1375
|
-
if (modes.ui) {
|
|
1376
|
-
dependencies["@alepha/ui"] = `^${version}`;
|
|
1377
|
-
modes.react = true;
|
|
1378
|
-
}
|
|
1379
1520
|
if (modes.tailwind) {
|
|
1380
|
-
devDependencies.tailwindcss =
|
|
1381
|
-
devDependencies["@tailwindcss/vite"] = "
|
|
1521
|
+
devDependencies.tailwindcss = alephaDeps.tailwindcss;
|
|
1522
|
+
devDependencies["@tailwindcss/vite"] = alephaDeps["@tailwindcss/vite"];
|
|
1382
1523
|
}
|
|
1524
|
+
if (modes.shadcn) devDependencies.shadcn = alephaDeps.shadcn;
|
|
1383
1525
|
if (modes.react) {
|
|
1384
1526
|
dependencies.react = alephaDeps.react;
|
|
1385
1527
|
dependencies["react-dom"] = alephaDeps["react-dom"];
|
|
@@ -1402,11 +1544,7 @@ var PackageManagerUtils = class {
|
|
|
1402
1544
|
//#endregion
|
|
1403
1545
|
//#region ../../src/cli/core/templates/agentMd.ts
|
|
1404
1546
|
const agentMd = (options) => {
|
|
1405
|
-
|
|
1406
|
-
const docs = [`- Framework source: \`node_modules/alepha/src/\``];
|
|
1407
|
-
if (options.ui) docs.push(`- UI components: \`node_modules/@alepha/ui/src/\``);
|
|
1408
|
-
docs.push(`- Docs: https://alepha.dev/llms.txt`);
|
|
1409
|
-
return `${header}
|
|
1547
|
+
return `${options.type === "claude" ? `# CLAUDE.md` : `# AGENTS.md`}
|
|
1410
1548
|
|
|
1411
1549
|
This is an **Alepha** project.
|
|
1412
1550
|
|
|
@@ -1428,7 +1566,8 @@ alepha build # Build
|
|
|
1428
1566
|
|
|
1429
1567
|
## Documentation
|
|
1430
1568
|
|
|
1431
|
-
|
|
1569
|
+
- Framework source: \`node_modules/alepha/src/\`
|
|
1570
|
+
- Docs: https://alepha.dev/llms.txt
|
|
1432
1571
|
`.trim();
|
|
1433
1572
|
};
|
|
1434
1573
|
//#endregion
|
|
@@ -1460,49 +1599,6 @@ export default defineConfig({
|
|
|
1460
1599
|
`;
|
|
1461
1600
|
};
|
|
1462
1601
|
//#endregion
|
|
1463
|
-
//#region ../../src/cli/core/templates/apiAppSecurityTs.ts
|
|
1464
|
-
const apiAppSecurityTs = (opts = {}) => {
|
|
1465
|
-
return `
|
|
1466
|
-
import { $realm } from "alepha/api/users";
|
|
1467
|
-
|
|
1468
|
-
export class AppSecurity {
|
|
1469
|
-
users = $realm({
|
|
1470
|
-
settings: {
|
|
1471
|
-
// Auto-promote these users to admin on login
|
|
1472
|
-
adminEmails: ${opts.adminEmail ? `["${opts.adminEmail}"]` : "[]"},
|
|
1473
|
-
adminUsernames: [],
|
|
1474
|
-
|
|
1475
|
-
// Registration & login options
|
|
1476
|
-
registrationAllowed: true,
|
|
1477
|
-
email: "required",
|
|
1478
|
-
username: "none",
|
|
1479
|
-
phoneNumber: "none",
|
|
1480
|
-
|
|
1481
|
-
// Verification (requires notifications feature)
|
|
1482
|
-
verifyEmailRequired: false,
|
|
1483
|
-
verifyPhoneRequired: false,
|
|
1484
|
-
resetPasswordAllowed: false,
|
|
1485
|
-
},
|
|
1486
|
-
features: {
|
|
1487
|
-
// Enable additional features
|
|
1488
|
-
notifications: false,
|
|
1489
|
-
audits: false,
|
|
1490
|
-
apiKeys: false,
|
|
1491
|
-
sessionPurge: false,
|
|
1492
|
-
avatars: false,
|
|
1493
|
-
parameters: false,
|
|
1494
|
-
},
|
|
1495
|
-
identities: {
|
|
1496
|
-
// Enable authentication providers
|
|
1497
|
-
credentials: true,
|
|
1498
|
-
// google: true,
|
|
1499
|
-
// github: true,
|
|
1500
|
-
},
|
|
1501
|
-
});
|
|
1502
|
-
}
|
|
1503
|
-
`.trim();
|
|
1504
|
-
};
|
|
1505
|
-
//#endregion
|
|
1506
1602
|
//#region ../../src/cli/core/templates/apiHelloControllerTs.ts
|
|
1507
1603
|
const apiHelloControllerTs = (options = {}) => {
|
|
1508
1604
|
return `import { $action } from "alepha/server";
|
|
@@ -1539,21 +1635,26 @@ export type HelloResponse = Static<typeof helloResponseSchema>;
|
|
|
1539
1635
|
//#endregion
|
|
1540
1636
|
//#region ../../src/cli/core/templates/apiIndexTs.ts
|
|
1541
1637
|
const apiIndexTs = (options = {}) => {
|
|
1542
|
-
const { appName = "app",
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1638
|
+
const { appName = "app", saas = false } = options;
|
|
1639
|
+
if (saas) return `
|
|
1640
|
+
import { $module } from "alepha";
|
|
1641
|
+
import { AlephaApiUsers } from "alepha/api/users";
|
|
1642
|
+
import { HelloController } from "./controllers/HelloController.ts";
|
|
1643
|
+
import { RealmProvider } from "./providers/RealmProvider.ts";
|
|
1644
|
+
|
|
1645
|
+
export const ApiModule = $module({
|
|
1646
|
+
name: "${appName}.api",
|
|
1647
|
+
services: [HelloController, RealmProvider],
|
|
1648
|
+
imports: [AlephaApiUsers],
|
|
1649
|
+
});
|
|
1650
|
+
`.trim();
|
|
1551
1651
|
return `
|
|
1552
|
-
$
|
|
1652
|
+
import { $module } from "alepha";
|
|
1653
|
+
import { HelloController } from "./controllers/HelloController.ts";
|
|
1553
1654
|
|
|
1554
1655
|
export const ApiModule = $module({
|
|
1555
1656
|
name: "${appName}.api",
|
|
1556
|
-
services: [
|
|
1657
|
+
services: [HelloController],
|
|
1557
1658
|
});
|
|
1558
1659
|
`.trim();
|
|
1559
1660
|
};
|
|
@@ -1593,6 +1694,46 @@ const biomeJson = () => `
|
|
|
1593
1694
|
}
|
|
1594
1695
|
`.trim();
|
|
1595
1696
|
//#endregion
|
|
1697
|
+
//#region ../../src/cli/core/templates/componentsJsonTs.ts
|
|
1698
|
+
/**
|
|
1699
|
+
* `components.json` is the shadcn CLI's project config — it tells
|
|
1700
|
+
* `shadcn add` where to drop primitives, which tailwind tokens to use,
|
|
1701
|
+
* which icon library to wire up, and which custom registries to resolve.
|
|
1702
|
+
*
|
|
1703
|
+
* Aliases follow shadcn's defaults (`@/components`, `@/lib/utils`) so the
|
|
1704
|
+
* CLI honors them across `init` + `add` calls. Alepha app code lives at
|
|
1705
|
+
* `src/web/` (Home, AppRouter, …) and the shadcn primitives live at
|
|
1706
|
+
* `src/components/` — kept separate to make the registry components
|
|
1707
|
+
* trivially upgradable via `shadcn add --overwrite`.
|
|
1708
|
+
*
|
|
1709
|
+
* The `registries` block pre-wires the public Alepha registry — consumers
|
|
1710
|
+
* can immediately run e.g. `shadcn add @alepha/auth-login`.
|
|
1711
|
+
*/
|
|
1712
|
+
const componentsJsonTs = () => `{
|
|
1713
|
+
"$schema": "https://ui.shadcn.com/schema.json",
|
|
1714
|
+
"style": "new-york",
|
|
1715
|
+
"rsc": false,
|
|
1716
|
+
"tsx": true,
|
|
1717
|
+
"tailwind": {
|
|
1718
|
+
"config": "",
|
|
1719
|
+
"css": "src/main.css",
|
|
1720
|
+
"baseColor": "neutral",
|
|
1721
|
+
"cssVariables": true
|
|
1722
|
+
},
|
|
1723
|
+
"aliases": {
|
|
1724
|
+
"components": "@/components",
|
|
1725
|
+
"utils": "@/lib/utils",
|
|
1726
|
+
"ui": "@/components/ui",
|
|
1727
|
+
"lib": "@/lib",
|
|
1728
|
+
"hooks": "@/hooks"
|
|
1729
|
+
},
|
|
1730
|
+
"iconLibrary": "lucide",
|
|
1731
|
+
"registries": {
|
|
1732
|
+
"@alepha": "https://alepha.dev/r/{name}.json"
|
|
1733
|
+
}
|
|
1734
|
+
}
|
|
1735
|
+
`;
|
|
1736
|
+
//#endregion
|
|
1596
1737
|
//#region ../../src/cli/core/templates/dummySpecTs.ts
|
|
1597
1738
|
const dummySpecTs = () => `
|
|
1598
1739
|
import { test, expect } from "vitest";
|
|
@@ -1725,37 +1866,6 @@ run(alepha);
|
|
|
1725
1866
|
//#endregion
|
|
1726
1867
|
//#region ../../src/cli/core/templates/mainCss.ts
|
|
1727
1868
|
const mainCss = (opts = {}) => {
|
|
1728
|
-
if (opts.ui) return `/**
|
|
1729
|
-
* Alepha UI - Based on Mantine component library
|
|
1730
|
-
* Mantine Docs: https://mantine.dev
|
|
1731
|
-
* Mantine LLM context: https://mantine.dev/llms.txt
|
|
1732
|
-
*
|
|
1733
|
-
* Switch theme index: alepha.set(alephaThemeAtom, { index: 1 })
|
|
1734
|
-
*
|
|
1735
|
-
* Custom themes (in src/web/index.ts):
|
|
1736
|
-
*
|
|
1737
|
-
* import { alephaThemeListAtom } from "@alepha/ui";
|
|
1738
|
-
*
|
|
1739
|
-
* export const WebModule = $module({
|
|
1740
|
-
* name: "app.web",
|
|
1741
|
-
* services: [AppRouter],
|
|
1742
|
-
* register(alepha) {
|
|
1743
|
-
* alepha.register(AppRouter);
|
|
1744
|
-
* alepha.set(alephaThemeListAtom, [{
|
|
1745
|
-
* name: "My Theme",
|
|
1746
|
-
* description: "Custom theme",
|
|
1747
|
-
* primaryColor: "blue",
|
|
1748
|
-
* defaultColorScheme: "dark",
|
|
1749
|
-
* // ...MantineThemeOverride options
|
|
1750
|
-
* }]);
|
|
1751
|
-
* },
|
|
1752
|
-
* });
|
|
1753
|
-
*
|
|
1754
|
-
* Alternatives (remove the import below):
|
|
1755
|
-
* - Tailwind CSS: https://tailwindcss.com/docs/installation/using-vite
|
|
1756
|
-
* - Raw CSS: Write your own styles
|
|
1757
|
-
*/
|
|
1758
|
-
@import "@alepha/ui/styles";`;
|
|
1759
1869
|
if (opts.tailwind) return `@import "tailwindcss";
|
|
1760
1870
|
|
|
1761
1871
|
/* Add your styles here */
|
|
@@ -1764,8 +1874,8 @@ const mainCss = (opts = {}) => {
|
|
|
1764
1874
|
* Global styles for your application.
|
|
1765
1875
|
*
|
|
1766
1876
|
* Options:
|
|
1767
|
-
* - @alepha/ui: Use \`alepha init --ui\` to add Mantine-based components
|
|
1768
1877
|
* - Tailwind CSS: Use \`alepha init --tailwind\` to add Tailwind CSS
|
|
1878
|
+
* - shadcn/ui: Use \`alepha init --shadcn\` to add shadcn/ui setup
|
|
1769
1879
|
* - Raw CSS: Write your own styles below
|
|
1770
1880
|
*/
|
|
1771
1881
|
|
|
@@ -1796,6 +1906,225 @@ run(alepha);
|
|
|
1796
1906
|
`.trim();
|
|
1797
1907
|
};
|
|
1798
1908
|
//#endregion
|
|
1909
|
+
//#region ../../src/cli/core/templates/saasAdminLayoutTsx.ts
|
|
1910
|
+
/**
|
|
1911
|
+
* SaaS admin layout — full AppShell on /admin with a sidebar, breadcrumbs,
|
|
1912
|
+
* a Sonner toaster, and a confirm provider. The page list grows with
|
|
1913
|
+
* whatever `admin-*` registry components the user adds.
|
|
1914
|
+
*
|
|
1915
|
+
* All UI primitives come from `src/components/*` where `shadcn add` drops
|
|
1916
|
+
* them; alepha app code lives in `src/web/*` and references them via the
|
|
1917
|
+
* `@/components/*` alias.
|
|
1918
|
+
*/
|
|
1919
|
+
const saasAdminLayoutTsx = () => `import { AppShell } from "@/components/app-shell";
|
|
1920
|
+
import { Toaster } from "@/components/ui/sonner";
|
|
1921
|
+
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
1922
|
+
import { ConfirmProvider } from "@/components/use-confirm";
|
|
1923
|
+
import { NestedView, useRouterState } from "alepha/react/router";
|
|
1924
|
+
import { ShieldCheck, Users } from "lucide-react";
|
|
1925
|
+
|
|
1926
|
+
const NAV = [
|
|
1927
|
+
{
|
|
1928
|
+
label: "Identity",
|
|
1929
|
+
items: [
|
|
1930
|
+
{ href: "/admin/users", label: "Users", icon: Users },
|
|
1931
|
+
{ href: "/admin/sessions", label: "Sessions", icon: ShieldCheck },
|
|
1932
|
+
],
|
|
1933
|
+
},
|
|
1934
|
+
] as const;
|
|
1935
|
+
|
|
1936
|
+
const findCrumbs = (pathname: string): { label: string; href?: string }[] => {
|
|
1937
|
+
for (const group of NAV) {
|
|
1938
|
+
const match = group.items.find((it) => it.href === pathname);
|
|
1939
|
+
if (match) return [{ label: group.label }, { label: match.label }];
|
|
1940
|
+
}
|
|
1941
|
+
return [];
|
|
1942
|
+
};
|
|
1943
|
+
|
|
1944
|
+
const AdminLayout = () => {
|
|
1945
|
+
const state = useRouterState();
|
|
1946
|
+
const crumbs = findCrumbs(state.url.pathname);
|
|
1947
|
+
|
|
1948
|
+
return (
|
|
1949
|
+
<TooltipProvider>
|
|
1950
|
+
<ConfirmProvider>
|
|
1951
|
+
<AppShell
|
|
1952
|
+
brand={
|
|
1953
|
+
<a
|
|
1954
|
+
href="/admin"
|
|
1955
|
+
className="flex items-center gap-2 px-2 py-2 font-semibold group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0"
|
|
1956
|
+
>
|
|
1957
|
+
<span className="bg-primary text-primary-foreground flex size-7 shrink-0 items-center justify-center rounded">
|
|
1958
|
+
α
|
|
1959
|
+
</span>
|
|
1960
|
+
<span className="truncate group-data-[collapsible=icon]:hidden">
|
|
1961
|
+
Admin
|
|
1962
|
+
</span>
|
|
1963
|
+
</a>
|
|
1964
|
+
}
|
|
1965
|
+
nav={NAV.map((group) => ({
|
|
1966
|
+
label: group.label,
|
|
1967
|
+
items: group.items.map((it) => ({
|
|
1968
|
+
href: it.href,
|
|
1969
|
+
label: it.label,
|
|
1970
|
+
icon: it.icon,
|
|
1971
|
+
active: it.href === state.url.pathname,
|
|
1972
|
+
})),
|
|
1973
|
+
}))}
|
|
1974
|
+
breadcrumbs={crumbs.length ? crumbs : undefined}
|
|
1975
|
+
>
|
|
1976
|
+
<NestedView />
|
|
1977
|
+
</AppShell>
|
|
1978
|
+
<Toaster />
|
|
1979
|
+
</ConfirmProvider>
|
|
1980
|
+
</TooltipProvider>
|
|
1981
|
+
);
|
|
1982
|
+
};
|
|
1983
|
+
|
|
1984
|
+
export default AdminLayout;
|
|
1985
|
+
`;
|
|
1986
|
+
//#endregion
|
|
1987
|
+
//#region ../../src/cli/core/templates/saasAdminPagesTsx.ts
|
|
1988
|
+
/**
|
|
1989
|
+
* Admin pages — each is a thin wrapper around the matching `admin-*`
|
|
1990
|
+
* registry component (placed at `src/components/admin/*`). The starter
|
|
1991
|
+
* ships with Users + Sessions; add more by `shadcn add @alepha/admin-…`
|
|
1992
|
+
* and a matching `$page(...)` in AppRouter.
|
|
1993
|
+
*/
|
|
1994
|
+
const saasAdminUsersTsx = () => `import { AdminUsers } from "@/components/admin/admin-users";
|
|
1995
|
+
|
|
1996
|
+
const AdminUsersPage = () => {
|
|
1997
|
+
return <AdminUsers />;
|
|
1998
|
+
};
|
|
1999
|
+
|
|
2000
|
+
export default AdminUsersPage;
|
|
2001
|
+
`;
|
|
2002
|
+
const saasAdminSessionsTsx = () => `import { AdminSessions } from "@/components/admin/admin-sessions";
|
|
2003
|
+
|
|
2004
|
+
const AdminSessionsPage = () => {
|
|
2005
|
+
return <AdminSessions />;
|
|
2006
|
+
};
|
|
2007
|
+
|
|
2008
|
+
export default AdminSessionsPage;
|
|
2009
|
+
`;
|
|
2010
|
+
//#endregion
|
|
2011
|
+
//#region ../../src/cli/core/templates/saasAuthLayoutTsx.ts
|
|
2012
|
+
/**
|
|
2013
|
+
* SaaS auth layout — wraps every /auth/* page with a centered card.
|
|
2014
|
+
* Routes (login, register, reset-password, verify-email) are mounted as
|
|
2015
|
+
* children so they share this shell.
|
|
2016
|
+
*/
|
|
2017
|
+
const saasAuthLayoutTsx = () => `import { NestedView } from "alepha/react/router";
|
|
2018
|
+
|
|
2019
|
+
const AuthLayout = () => {
|
|
2020
|
+
return (
|
|
2021
|
+
<div className="bg-background flex min-h-screen items-center justify-center p-4">
|
|
2022
|
+
<div className="w-full max-w-md">
|
|
2023
|
+
<NestedView />
|
|
2024
|
+
</div>
|
|
2025
|
+
</div>
|
|
2026
|
+
);
|
|
2027
|
+
};
|
|
2028
|
+
|
|
2029
|
+
export default AuthLayout;
|
|
2030
|
+
`;
|
|
2031
|
+
//#endregion
|
|
2032
|
+
//#region ../../src/cli/core/templates/saasAuthPagesTsx.ts
|
|
2033
|
+
/**
|
|
2034
|
+
* Per-page wrapper around the registry components. The registry component
|
|
2035
|
+
* receives the realm config from the page loader; the page itself stays a
|
|
2036
|
+
* thin shell so apps can layer their branding around it.
|
|
2037
|
+
*
|
|
2038
|
+
* Registry components land at `src/components/auth/*` (shadcn defaults).
|
|
2039
|
+
*/
|
|
2040
|
+
const saasAuthLoginTsx = () => `import { AuthLogin } from "@/components/auth/auth-login";
|
|
2041
|
+
import type { RealmConfig } from "alepha/api/users";
|
|
2042
|
+
|
|
2043
|
+
export interface AuthLoginPageProps {
|
|
2044
|
+
realmConfig: RealmConfig;
|
|
2045
|
+
}
|
|
2046
|
+
|
|
2047
|
+
const AuthLoginPage = (props: AuthLoginPageProps) => {
|
|
2048
|
+
return <AuthLogin realmConfig={props.realmConfig} />;
|
|
2049
|
+
};
|
|
2050
|
+
|
|
2051
|
+
export default AuthLoginPage;
|
|
2052
|
+
`;
|
|
2053
|
+
const saasAuthRegisterTsx = () => `import { AuthRegister } from "@/components/auth/auth-register";
|
|
2054
|
+
import type { RealmConfig } from "alepha/api/users";
|
|
2055
|
+
|
|
2056
|
+
export interface AuthRegisterPageProps {
|
|
2057
|
+
realmConfig: RealmConfig;
|
|
2058
|
+
}
|
|
2059
|
+
|
|
2060
|
+
const AuthRegisterPage = (props: AuthRegisterPageProps) => {
|
|
2061
|
+
return <AuthRegister realmConfig={props.realmConfig} />;
|
|
2062
|
+
};
|
|
2063
|
+
|
|
2064
|
+
export default AuthRegisterPage;
|
|
2065
|
+
`;
|
|
2066
|
+
const saasAuthResetPasswordTsx = () => `import { AuthResetPassword } from "@/components/auth/auth-reset-password";
|
|
2067
|
+
import type { RealmConfig } from "alepha/api/users";
|
|
2068
|
+
|
|
2069
|
+
export interface AuthResetPasswordPageProps {
|
|
2070
|
+
realmConfig: RealmConfig;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
const AuthResetPasswordPage = (props: AuthResetPasswordPageProps) => {
|
|
2074
|
+
return <AuthResetPassword realmConfig={props.realmConfig} />;
|
|
2075
|
+
};
|
|
2076
|
+
|
|
2077
|
+
export default AuthResetPasswordPage;
|
|
2078
|
+
`;
|
|
2079
|
+
const saasAuthVerifyEmailTsx = () => `import { AuthVerifyEmail } from "@/components/auth/auth-verify-email";
|
|
2080
|
+
|
|
2081
|
+
const AuthVerifyEmailPage = () => {
|
|
2082
|
+
return <AuthVerifyEmail />;
|
|
2083
|
+
};
|
|
2084
|
+
|
|
2085
|
+
export default AuthVerifyEmailPage;
|
|
2086
|
+
`;
|
|
2087
|
+
//#endregion
|
|
2088
|
+
//#region ../../src/cli/core/templates/saasRealmProviderTs.ts
|
|
2089
|
+
/**
|
|
2090
|
+
* Realm provider scaffolded by `alepha init --saas`.
|
|
2091
|
+
*
|
|
2092
|
+
* Minimal hello-world setup: credentials login with email, one admin seeded
|
|
2093
|
+
* with the developer's git email at scaffold time, and an `admin:ui`
|
|
2094
|
+
* permission used by the AppRouter to gate `/admin/*`. The default `admin`
|
|
2095
|
+
* role grants `*` (so it inherits `admin:ui`); the default `user` role
|
|
2096
|
+
* excludes `admin:*` (so non-admins get a 403 before the shell renders).
|
|
2097
|
+
*
|
|
2098
|
+
* Add `$env`, more permissions, or stricter settings as the project grows.
|
|
2099
|
+
*/
|
|
2100
|
+
const saasRealmProviderTs = (options = {}) => {
|
|
2101
|
+
const adminEmail = options.adminEmail ?? "admin@example.com";
|
|
2102
|
+
return `import { $realm } from "alepha/api/users";
|
|
2103
|
+
import { $permission } from "alepha/security";
|
|
2104
|
+
|
|
2105
|
+
export class RealmProvider {
|
|
2106
|
+
/**
|
|
2107
|
+
* Permission required to open the admin UI. Wired into AppRouter.adminLayout
|
|
2108
|
+
* via \`$secure({ permissions: ["admin:ui"] })\`.
|
|
2109
|
+
*/
|
|
2110
|
+
adminUi = $permission({
|
|
2111
|
+
group: "admin",
|
|
2112
|
+
name: "ui",
|
|
2113
|
+
description: "Access to the admin UI shell",
|
|
2114
|
+
});
|
|
2115
|
+
|
|
2116
|
+
realm = $realm({
|
|
2117
|
+
settings: {
|
|
2118
|
+
adminEmails: [${JSON.stringify(adminEmail)}],
|
|
2119
|
+
},
|
|
2120
|
+
identities: {
|
|
2121
|
+
credentials: true,
|
|
2122
|
+
},
|
|
2123
|
+
});
|
|
2124
|
+
}
|
|
2125
|
+
`;
|
|
2126
|
+
};
|
|
2127
|
+
//#endregion
|
|
1799
2128
|
//#region ../../src/cli/core/templates/tsconfigJson.ts
|
|
1800
2129
|
const tsconfigJson = () => `
|
|
1801
2130
|
{
|
|
@@ -1819,89 +2148,42 @@ export default defineConfig({
|
|
|
1819
2148
|
`;
|
|
1820
2149
|
};
|
|
1821
2150
|
//#endregion
|
|
1822
|
-
//#region ../../src/cli/core/templates/
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
</Text>
|
|
1832
|
-
<Text c="dimmed">Welcome to the admin panel.</Text>
|
|
1833
|
-
</Flex>
|
|
1834
|
-
);
|
|
1835
|
-
};
|
|
2151
|
+
//#region ../../src/cli/core/templates/vitestConfigTs.ts
|
|
2152
|
+
/**
|
|
2153
|
+
* Minimal Vitest config for a freshly scaffolded Alepha project.
|
|
2154
|
+
*
|
|
2155
|
+
* Defines `test.root` explicitly so Vitest doesn't walk up the directory
|
|
2156
|
+
* tree and inherit a parent monorepo config (which can pull in unrelated
|
|
2157
|
+
* setup files, database connections, etc.).
|
|
2158
|
+
*/
|
|
2159
|
+
const vitestConfigTs = () => `import { defineConfig } from "vitest/config";
|
|
1836
2160
|
|
|
1837
|
-
export default
|
|
2161
|
+
export default defineConfig({
|
|
2162
|
+
test: {
|
|
2163
|
+
root: ".",
|
|
2164
|
+
globals: true,
|
|
2165
|
+
},
|
|
2166
|
+
});
|
|
1838
2167
|
`;
|
|
1839
|
-
};
|
|
1840
2168
|
//#endregion
|
|
1841
2169
|
//#region ../../src/cli/core/templates/webAppRouterTs.ts
|
|
1842
2170
|
const webAppRouterTs = (options) => {
|
|
1843
|
-
|
|
2171
|
+
if (options.saas) return saasAppRouterTs();
|
|
2172
|
+
return basicAppRouterTs(options);
|
|
2173
|
+
};
|
|
2174
|
+
const basicAppRouterTs = (options) => {
|
|
2175
|
+
const imports = ["import { $page } from \"alepha/react/router\";"];
|
|
1844
2176
|
const classMembers = [];
|
|
1845
|
-
if (options.ui) imports.push("import { $ui } from \"@alepha/ui\";");
|
|
1846
|
-
if (options.auth) imports.push("import { $uiAuth } from \"@alepha/ui/auth\";");
|
|
1847
|
-
if (options.admin) {
|
|
1848
|
-
imports.push("import { $uiAdmin } from \"@alepha/ui/admin\";");
|
|
1849
|
-
imports.push("import { AdminUserRouter } from \"@alepha/ui/admin-users\";");
|
|
1850
|
-
imports.push("import { AdminSessionRouter } from \"@alepha/ui/admin-sessions\";");
|
|
1851
|
-
imports.push("import { $inject } from \"alepha\";");
|
|
1852
|
-
imports.push("import { IconLayoutDashboard, IconUsers } from \"@tabler/icons-react\";");
|
|
1853
|
-
}
|
|
1854
|
-
imports.push("import { $page } from \"alepha/react/router\";");
|
|
1855
2177
|
if (options.api) {
|
|
1856
2178
|
imports.push("import { $client } from \"alepha/server/links\";");
|
|
1857
2179
|
imports.push("import type { HelloController } from \"../api/controllers/HelloController.ts\";");
|
|
1858
2180
|
classMembers.push(" api = $client<HelloController>();");
|
|
1859
|
-
|
|
1860
|
-
if (options.ui) {
|
|
1861
|
-
classMembers.push(" ui = $ui();");
|
|
1862
|
-
if (options.auth) classMembers.push(" uiAuth = $uiAuth();");
|
|
1863
|
-
if (options.admin) classMembers.push(` // ── Admin Dashboard ─────────────────────────────
|
|
1864
|
-
// Defined first so it can be referenced by the admin panel below.
|
|
1865
|
-
// \`$uiAdmin\` auto-parents listed pages under the admin layout.
|
|
1866
|
-
adminDashboard = $page({
|
|
1867
|
-
path: "/",
|
|
1868
|
-
label: "Dashboard",
|
|
1869
|
-
icon: IconLayoutDashboard,
|
|
1870
|
-
lazy: () => import("./components/AdminDashboard.tsx"),
|
|
1871
|
-
});
|
|
1872
|
-
|
|
1873
|
-
// ── Admin Domain Routers ──────────────────────────
|
|
1874
|
-
protected users = $inject(AdminUserRouter);
|
|
1875
|
-
protected sessions = $inject(AdminSessionRouter);
|
|
1876
|
-
|
|
1877
|
-
// ── Admin Panel ─────────────────────────────────
|
|
1878
|
-
admin = $uiAdmin({
|
|
1879
|
-
pages: [
|
|
1880
|
-
this.adminDashboard,
|
|
1881
|
-
this.users.adminUsers,
|
|
1882
|
-
this.users.adminUserLayout,
|
|
1883
|
-
this.sessions.adminSessions,
|
|
1884
|
-
],
|
|
1885
|
-
sidebarItems: [
|
|
1886
|
-
this.adminDashboard,
|
|
1887
|
-
{
|
|
1888
|
-
label: "Identity",
|
|
1889
|
-
icon: IconUsers,
|
|
1890
|
-
children: [this.users.adminUsers, this.sessions.adminSessions],
|
|
1891
|
-
},
|
|
1892
|
-
],
|
|
1893
|
-
});`);
|
|
1894
|
-
classMembers.push(` layout = $page({
|
|
1895
|
-
parent: this.ui.root,
|
|
1896
|
-
children: () => [this.home],
|
|
1897
|
-
});`);
|
|
1898
|
-
}
|
|
1899
|
-
if (options.api) classMembers.push(` home = $page({
|
|
2181
|
+
classMembers.push(` home = $page({
|
|
1900
2182
|
path: "/",
|
|
1901
2183
|
lazy: () => import("./components/Home.tsx"),
|
|
1902
2184
|
loader: () => this.api.hello(),
|
|
1903
2185
|
});`);
|
|
1904
|
-
else classMembers.push(` home = $page({
|
|
2186
|
+
} else classMembers.push(` home = $page({
|
|
1905
2187
|
path: "/",
|
|
1906
2188
|
lazy: () => import("./components/Home.tsx"),
|
|
1907
2189
|
});`);
|
|
@@ -1911,6 +2193,95 @@ export class AppRouter {
|
|
|
1911
2193
|
${classMembers.join("\n\n")}
|
|
1912
2194
|
}`;
|
|
1913
2195
|
};
|
|
2196
|
+
/**
|
|
2197
|
+
* SaaS router wires three trees onto the app:
|
|
2198
|
+
* / → Home
|
|
2199
|
+
* /auth/* → AuthLayout + login / register / reset / verify
|
|
2200
|
+
* /admin/* → AdminLayout + users / sessions / api-keys / parameters / audits
|
|
2201
|
+
*
|
|
2202
|
+
* Each auth page resolves the realm config from its loader, so the registry
|
|
2203
|
+
* components render with everything they need on first paint.
|
|
2204
|
+
*/
|
|
2205
|
+
const saasAppRouterTs = () => `import type { RealmController } from "alepha/api/users";
|
|
2206
|
+
import { $page, NotFound } from "alepha/react/router";
|
|
2207
|
+
import { $secure } from "alepha/security";
|
|
2208
|
+
import { $client } from "alepha/server/links";
|
|
2209
|
+
import type { HelloController } from "../api/controllers/HelloController.ts";
|
|
2210
|
+
|
|
2211
|
+
export class AppRouter {
|
|
2212
|
+
protected readonly api = $client<HelloController>();
|
|
2213
|
+
protected readonly realmApi = $client<RealmController>();
|
|
2214
|
+
|
|
2215
|
+
home = $page({
|
|
2216
|
+
path: "/",
|
|
2217
|
+
lazy: () => import("./components/Home.tsx"),
|
|
2218
|
+
loader: () => this.api.hello(),
|
|
2219
|
+
});
|
|
2220
|
+
|
|
2221
|
+
// ── /auth — login, register, reset, verify ─────────────────────────────
|
|
2222
|
+
authLayout = $page({
|
|
2223
|
+
path: "/auth",
|
|
2224
|
+
lazy: () => import("./components/auth/AuthLayout.tsx"),
|
|
2225
|
+
});
|
|
2226
|
+
|
|
2227
|
+
login = $page({
|
|
2228
|
+
parent: this.authLayout,
|
|
2229
|
+
path: "/login",
|
|
2230
|
+
name: "login",
|
|
2231
|
+
head: { title: "Sign in" },
|
|
2232
|
+
lazy: () => import("./components/auth/Login.tsx"),
|
|
2233
|
+
loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
|
|
2234
|
+
});
|
|
2235
|
+
|
|
2236
|
+
register = $page({
|
|
2237
|
+
parent: this.authLayout,
|
|
2238
|
+
path: "/register",
|
|
2239
|
+
name: "register",
|
|
2240
|
+
head: { title: "Sign up" },
|
|
2241
|
+
lazy: () => import("./components/auth/Register.tsx"),
|
|
2242
|
+
loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
|
|
2243
|
+
});
|
|
2244
|
+
|
|
2245
|
+
resetPassword = $page({
|
|
2246
|
+
parent: this.authLayout,
|
|
2247
|
+
path: "/reset-password",
|
|
2248
|
+
head: { title: "Reset password" },
|
|
2249
|
+
lazy: () => import("./components/auth/ResetPassword.tsx"),
|
|
2250
|
+
loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
|
|
2251
|
+
});
|
|
2252
|
+
|
|
2253
|
+
verifyEmail = $page({
|
|
2254
|
+
parent: this.authLayout,
|
|
2255
|
+
path: "/verify-email",
|
|
2256
|
+
head: { title: "Verify email" },
|
|
2257
|
+
lazy: () => import("./components/auth/VerifyEmail.tsx"),
|
|
2258
|
+
});
|
|
2259
|
+
|
|
2260
|
+
// ── /admin — gated by 'admin:ui' permission, declared in RealmProvider.
|
|
2261
|
+
// Children inherit the gate via the parent chain.
|
|
2262
|
+
adminLayout = $page({
|
|
2263
|
+
path: "/admin",
|
|
2264
|
+
use: [$secure({ permissions: ["admin:ui"] })],
|
|
2265
|
+
lazy: () => import("./components/admin/AdminLayout.tsx"),
|
|
2266
|
+
});
|
|
2267
|
+
|
|
2268
|
+
adminUsers = $page({
|
|
2269
|
+
parent: this.adminLayout,
|
|
2270
|
+
path: "/users",
|
|
2271
|
+
head: { title: "Users" },
|
|
2272
|
+
lazy: () => import("./components/admin/Users.tsx"),
|
|
2273
|
+
});
|
|
2274
|
+
|
|
2275
|
+
adminSessions = $page({
|
|
2276
|
+
parent: this.adminLayout,
|
|
2277
|
+
path: "/sessions",
|
|
2278
|
+
head: { title: "Sessions" },
|
|
2279
|
+
lazy: () => import("./components/admin/Sessions.tsx"),
|
|
2280
|
+
});
|
|
2281
|
+
|
|
2282
|
+
notFound = $page({ path: "/*", component: NotFound });
|
|
2283
|
+
}
|
|
2284
|
+
`;
|
|
1914
2285
|
//#endregion
|
|
1915
2286
|
//#region ../../src/cli/core/templates/webHomeComponentTsx.ts
|
|
1916
2287
|
const webHomeComponentTsx = (options = {}) => {
|
|
@@ -1939,7 +2310,19 @@ export default Home;
|
|
|
1939
2310
|
//#endregion
|
|
1940
2311
|
//#region ../../src/cli/core/templates/webIndexTs.ts
|
|
1941
2312
|
const webIndexTs = (options = {}) => {
|
|
1942
|
-
const { appName = "app" } = options;
|
|
2313
|
+
const { appName = "app", saas = false } = options;
|
|
2314
|
+
if (saas) return `
|
|
2315
|
+
import { $module } from "alepha";
|
|
2316
|
+
import { AlephaReactAuth } from "alepha/react/auth";
|
|
2317
|
+
import { AlephaReactI18n } from "alepha/react/i18n";
|
|
2318
|
+
import { AppRouter } from "./AppRouter.ts";
|
|
2319
|
+
|
|
2320
|
+
export const WebModule = $module({
|
|
2321
|
+
name: "${appName}.web",
|
|
2322
|
+
services: [AppRouter],
|
|
2323
|
+
imports: [AlephaReactAuth, AlephaReactI18n],
|
|
2324
|
+
});
|
|
2325
|
+
`.trim();
|
|
1943
2326
|
return `
|
|
1944
2327
|
import { $module } from "alepha";
|
|
1945
2328
|
import { AppRouter } from "./AppRouter.ts";
|
|
@@ -1965,6 +2348,7 @@ var ProjectScaffolder = class {
|
|
|
1965
2348
|
log = $logger();
|
|
1966
2349
|
colors = $inject(ConsoleColorProvider);
|
|
1967
2350
|
fs = $inject(FileSystemProvider);
|
|
2351
|
+
shell = $inject(ShellProvider);
|
|
1968
2352
|
pm = $inject(PackageManagerUtils);
|
|
1969
2353
|
utils = $inject(AlephaCliUtils);
|
|
1970
2354
|
/**
|
|
@@ -1986,7 +2370,10 @@ var ProjectScaffolder = class {
|
|
|
1986
2370
|
const force = opts.force ?? false;
|
|
1987
2371
|
const checkWorkspace = opts.checkWorkspace ?? false;
|
|
1988
2372
|
if (opts.packageJson) tasks.push(this.pm.ensurePackageJson(root, typeof opts.packageJson === "boolean" ? {} : opts.packageJson).then(() => {}));
|
|
1989
|
-
if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root, {
|
|
2373
|
+
if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root, {
|
|
2374
|
+
force,
|
|
2375
|
+
localOnly: opts.tsconfigJson === "local"
|
|
2376
|
+
}));
|
|
1990
2377
|
if (opts.biomeJson) tasks.push(this.ensureBiomeConfig(root, {
|
|
1991
2378
|
force,
|
|
1992
2379
|
checkWorkspace
|
|
@@ -2002,7 +2389,8 @@ var ProjectScaffolder = class {
|
|
|
2002
2389
|
await Promise.all(tasks);
|
|
2003
2390
|
}
|
|
2004
2391
|
async ensureTsConfig(root, opts = {}) {
|
|
2005
|
-
|
|
2392
|
+
const exists = opts.localOnly ? await this.fs.exists(this.fs.join(root, "tsconfig.json")) : await this.existsInParents(root, "tsconfig.json");
|
|
2393
|
+
if (!opts.force && exists) return;
|
|
2006
2394
|
await this.fs.writeFile(this.fs.join(root, "tsconfig.json"), tsconfigJson());
|
|
2007
2395
|
}
|
|
2008
2396
|
async ensureBiomeConfig(root, opts = {}) {
|
|
@@ -2063,11 +2451,30 @@ var ProjectScaffolder = class {
|
|
|
2063
2451
|
await this.fs.mkdir(this.fs.join(root, "src/api/schemas"), { recursive: true });
|
|
2064
2452
|
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({
|
|
2065
2453
|
appName,
|
|
2066
|
-
|
|
2454
|
+
saas: opts.saas
|
|
2067
2455
|
}), opts.force);
|
|
2068
2456
|
await this.ensureFile(root, "src/api/controllers/HelloController.ts", apiHelloControllerTs({ appName }), opts.force);
|
|
2069
2457
|
await this.ensureFile(root, "src/api/schemas/helloResponseSchema.ts", apiHelloResponseSchemaTs(), opts.force);
|
|
2070
|
-
if (opts.
|
|
2458
|
+
if (opts.saas) {
|
|
2459
|
+
await this.fs.mkdir(this.fs.join(root, "src/api/providers"), { recursive: true });
|
|
2460
|
+
const adminEmail = await this.detectGitEmail();
|
|
2461
|
+
await this.ensureFile(root, "src/api/providers/RealmProvider.ts", saasRealmProviderTs({ adminEmail }), opts.force);
|
|
2462
|
+
}
|
|
2463
|
+
}
|
|
2464
|
+
/**
|
|
2465
|
+
* Best-effort lookup for the developer's git email (used as the seeded
|
|
2466
|
+
* `adminEmails` entry in the SaaS realm). Returns undefined if git isn't
|
|
2467
|
+
* available or if `user.email` isn't configured — the template falls back
|
|
2468
|
+
* to `admin@example.com` in that case.
|
|
2469
|
+
*/
|
|
2470
|
+
async detectGitEmail() {
|
|
2471
|
+
try {
|
|
2472
|
+
const email = (await this.shell.run("git config --get user.email", { capture: true }) ?? "").trim();
|
|
2473
|
+
if (!email || !email.includes("@")) return void 0;
|
|
2474
|
+
return email;
|
|
2475
|
+
} catch {
|
|
2476
|
+
return;
|
|
2477
|
+
}
|
|
2071
2478
|
}
|
|
2072
2479
|
/**
|
|
2073
2480
|
* Ensure web/React project structure exists.
|
|
@@ -2080,30 +2487,46 @@ var ProjectScaffolder = class {
|
|
|
2080
2487
|
async ensureWebProject(root, opts = {}) {
|
|
2081
2488
|
const appName = this.getAppName(root);
|
|
2082
2489
|
await this.fs.mkdir(this.fs.join(root, "src/web/components"), { recursive: true });
|
|
2490
|
+
if (opts.saas) {
|
|
2491
|
+
await this.fs.mkdir(this.fs.join(root, "src/web/components/auth"), { recursive: true });
|
|
2492
|
+
await this.fs.mkdir(this.fs.join(root, "src/web/components/admin"), { recursive: true });
|
|
2493
|
+
}
|
|
2083
2494
|
await this.fs.mkdir(this.fs.join(root, "public"), { recursive: true });
|
|
2084
2495
|
await this.ensureFile(root, "public/favicon.svg", logoSvg, opts.force);
|
|
2085
|
-
await this.ensureFile(root, "src/main.css", mainCss({
|
|
2086
|
-
ui: opts.ui,
|
|
2087
|
-
tailwind: opts.tailwind
|
|
2088
|
-
}), opts.force);
|
|
2496
|
+
await this.ensureFile(root, "src/main.css", mainCss({ tailwind: opts.tailwind }), opts.force);
|
|
2089
2497
|
if (opts.tailwind) await this.ensureFile(root, "vite.config.ts", viteConfigTs(), opts.force);
|
|
2090
|
-
await this.ensureFile(root, "
|
|
2498
|
+
if (opts.shadcn) await this.ensureFile(root, "components.json", componentsJsonTs(), opts.force);
|
|
2499
|
+
await this.ensureFile(root, "src/web/index.ts", webIndexTs({
|
|
2500
|
+
appName,
|
|
2501
|
+
saas: opts.saas
|
|
2502
|
+
}), opts.force);
|
|
2091
2503
|
await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({
|
|
2092
2504
|
api: opts.api,
|
|
2093
|
-
|
|
2094
|
-
auth: opts.auth,
|
|
2095
|
-
admin: opts.admin
|
|
2505
|
+
saas: opts.saas
|
|
2096
2506
|
}), opts.force);
|
|
2097
2507
|
await this.ensureFile(root, "src/web/components/Home.tsx", webHomeComponentTsx({ api: opts.api }), opts.force);
|
|
2098
|
-
if (opts.admin) await this.ensureFile(root, "src/web/components/AdminDashboard.tsx", webAdminDashboardTsx(), opts.force);
|
|
2099
2508
|
await this.ensureFile(root, "src/main.browser.ts", mainBrowserTs(), opts.force);
|
|
2509
|
+
if (opts.saas) {
|
|
2510
|
+
await this.ensureFile(root, "src/web/components/auth/AuthLayout.tsx", saasAuthLayoutTsx(), opts.force);
|
|
2511
|
+
await this.ensureFile(root, "src/web/components/auth/Login.tsx", saasAuthLoginTsx(), opts.force);
|
|
2512
|
+
await this.ensureFile(root, "src/web/components/auth/Register.tsx", saasAuthRegisterTsx(), opts.force);
|
|
2513
|
+
await this.ensureFile(root, "src/web/components/auth/ResetPassword.tsx", saasAuthResetPasswordTsx(), opts.force);
|
|
2514
|
+
await this.ensureFile(root, "src/web/components/auth/VerifyEmail.tsx", saasAuthVerifyEmailTsx(), opts.force);
|
|
2515
|
+
await this.ensureFile(root, "src/web/components/admin/AdminLayout.tsx", saasAdminLayoutTsx(), opts.force);
|
|
2516
|
+
await this.ensureFile(root, "src/web/components/admin/Users.tsx", saasAdminUsersTsx(), opts.force);
|
|
2517
|
+
await this.ensureFile(root, "src/web/components/admin/Sessions.tsx", saasAdminSessionsTsx(), opts.force);
|
|
2518
|
+
}
|
|
2100
2519
|
}
|
|
2101
2520
|
/**
|
|
2102
|
-
* Ensure test directory exists with a dummy test file
|
|
2521
|
+
* Ensure test directory exists with a dummy test file + a self-contained
|
|
2522
|
+
* `vitest.config.ts`. Pinning `test.root` prevents Vitest from walking up
|
|
2523
|
+
* to a parent monorepo config (e.g. one that boots a Postgres container).
|
|
2103
2524
|
*/
|
|
2104
2525
|
async ensureTestDir(root) {
|
|
2105
2526
|
const testDir = this.fs.join(root, "test");
|
|
2106
2527
|
const dummyPath = this.fs.join(testDir, "dummy.spec.ts");
|
|
2528
|
+
const vitestConfigPath = this.fs.join(root, "vitest.config.ts");
|
|
2529
|
+
if (!await this.fs.exists(vitestConfigPath)) await this.fs.writeFile(vitestConfigPath, vitestConfigTs());
|
|
2107
2530
|
if (!await this.fs.exists(testDir)) {
|
|
2108
2531
|
await this.fs.mkdir(testDir, { recursive: true });
|
|
2109
2532
|
await this.fs.writeFile(dummyPath, dummySpecTs());
|
|
@@ -2119,20 +2542,23 @@ var ProjectScaffolder = class {
|
|
|
2119
2542
|
root = this.fs.join(root, args);
|
|
2120
2543
|
await this.fs.mkdir(root, { force: true });
|
|
2121
2544
|
}
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2545
|
+
const shadcnPreset = typeof flags.saas === "string" && flags.saas || typeof flags.shadcn === "string" && flags.shadcn || "b0";
|
|
2546
|
+
const f = flags;
|
|
2547
|
+
f.shadcn = !!flags.shadcn;
|
|
2548
|
+
f.saas = !!flags.saas;
|
|
2549
|
+
if (f.saas) {
|
|
2550
|
+
f.shadcn = true;
|
|
2551
|
+
f.api = true;
|
|
2125
2552
|
}
|
|
2126
|
-
if (
|
|
2553
|
+
if (f.shadcn) f.tailwind = true;
|
|
2127
2554
|
if (flags.tailwind) flags.react = true;
|
|
2128
|
-
if ((flags.
|
|
2555
|
+
if ((flags.api || flags.react || flags.tailwind || flags.shadcn || flags.saas) && !flags.force) {
|
|
2129
2556
|
if ((await this.fs.ls(root)).filter((f) => f !== "package.json").length > 0) throw new AlephaError(`Target directory is not empty (${root}). Use --force to overwrite existing files.`);
|
|
2130
2557
|
}
|
|
2131
2558
|
const workspace = await this.pm.getWorkspaceContext(root);
|
|
2132
2559
|
let agentType = false;
|
|
2133
2560
|
if (!workspace.isPackage) agentType = await this.utils.isInstalledAsync("claude") ? "claude" : "agents";
|
|
2134
2561
|
const isExpo = await this.pm.hasExpo(root);
|
|
2135
|
-
const adminEmail = flags.saas ? await this.utils.getGitEmail() : void 0;
|
|
2136
2562
|
const force = !!flags.force;
|
|
2137
2563
|
await run({
|
|
2138
2564
|
name: "ensuring configuration files",
|
|
@@ -2140,16 +2566,13 @@ var ProjectScaffolder = class {
|
|
|
2140
2566
|
await this.ensureConfig(root, {
|
|
2141
2567
|
force,
|
|
2142
2568
|
packageJson: {
|
|
2143
|
-
...
|
|
2569
|
+
...f,
|
|
2144
2570
|
isPackage: workspace.isPackage
|
|
2145
2571
|
},
|
|
2146
|
-
tsconfigJson: !workspace.config.tsconfigJson,
|
|
2572
|
+
tsconfigJson: f.shadcn ? "local" : !workspace.config.tsconfigJson,
|
|
2147
2573
|
biomeJson: true,
|
|
2148
2574
|
editorconfig: !workspace.config.editorconfig,
|
|
2149
|
-
agentMd: agentType ? {
|
|
2150
|
-
type: agentType,
|
|
2151
|
-
ui: !!flags.ui
|
|
2152
|
-
} : false
|
|
2575
|
+
agentMd: agentType ? { type: agentType } : false
|
|
2153
2576
|
});
|
|
2154
2577
|
await this.ensureAlephaConfig(root, { force });
|
|
2155
2578
|
await this.ensureMainServerTs(root, {
|
|
@@ -2158,16 +2581,14 @@ var ProjectScaffolder = class {
|
|
|
2158
2581
|
force
|
|
2159
2582
|
});
|
|
2160
2583
|
if (flags.api) await this.ensureApiProject(root, {
|
|
2161
|
-
|
|
2162
|
-
adminEmail,
|
|
2584
|
+
saas: !!flags.saas,
|
|
2163
2585
|
force
|
|
2164
2586
|
});
|
|
2165
2587
|
if (flags.react && !isExpo) await this.ensureWebProject(root, {
|
|
2166
2588
|
api: !!flags.api,
|
|
2167
|
-
ui: !!flags.ui,
|
|
2168
|
-
auth: !!flags.saas,
|
|
2169
|
-
admin: !!flags.saas,
|
|
2170
2589
|
tailwind: !!flags.tailwind,
|
|
2590
|
+
shadcn: !!flags.shadcn,
|
|
2591
|
+
saas: !!flags.saas,
|
|
2171
2592
|
force
|
|
2172
2593
|
});
|
|
2173
2594
|
}
|
|
@@ -2185,10 +2606,26 @@ var ProjectScaffolder = class {
|
|
|
2185
2606
|
root: installRoot
|
|
2186
2607
|
});
|
|
2187
2608
|
if (flags.test) await this.ensureTestDir(root);
|
|
2188
|
-
|
|
2189
|
-
|
|
2609
|
+
const exec = pmExecPrefix(pmName);
|
|
2610
|
+
if (flags.shadcn) {
|
|
2611
|
+
await run(`${exec} shadcn init --no-monorepo --base radix -t vite --yes --force --reinstall --preset ${escapeShellArg(shadcnPreset)}`, {
|
|
2612
|
+
alias: `running shadcn init (preset ${shadcnPreset})`,
|
|
2613
|
+
root
|
|
2614
|
+
});
|
|
2615
|
+
await this.fs.writeFile(this.fs.join(root, "components.json"), componentsJsonTs());
|
|
2616
|
+
}
|
|
2617
|
+
if (flags.saas) await run(`${exec} shadcn add @alepha/saas --yes --overwrite`, {
|
|
2618
|
+
alias: "adding alepha saas registry bundle",
|
|
2190
2619
|
root
|
|
2191
2620
|
});
|
|
2621
|
+
try {
|
|
2622
|
+
await run(`${pmName} run lint`, {
|
|
2623
|
+
alias: "running linter",
|
|
2624
|
+
root
|
|
2625
|
+
});
|
|
2626
|
+
} catch (err) {
|
|
2627
|
+
this.log.warn("Linter reported issues during init — continuing. Run `lint` again later to inspect.", { error: err instanceof Error ? err.message : String(err) });
|
|
2628
|
+
}
|
|
2192
2629
|
if (!workspace.isPackage) {
|
|
2193
2630
|
if (await this.ensureGitRepo(root, { force })) await run("git add .", {
|
|
2194
2631
|
alias: "staging generated files",
|
|
@@ -2205,11 +2642,6 @@ var ProjectScaffolder = class {
|
|
|
2205
2642
|
this.log.info("");
|
|
2206
2643
|
this.log.info(` ${c.set("GREY_DARK", "$")} cd ${c.set("CYAN", projectName)}`);
|
|
2207
2644
|
this.log.info(` ${c.set("GREY_DARK", "$")} ${c.set("CYAN", `${pmRun} dev`)}`);
|
|
2208
|
-
if (adminEmail) {
|
|
2209
|
-
this.log.info("");
|
|
2210
|
-
this.log.info(` Admin email: ${c.set("GREEN", adminEmail)}`);
|
|
2211
|
-
this.log.info(` ${c.set("GREY_DARK", "(from git config, change in src/api/AppSecurity.ts)")}`);
|
|
2212
|
-
}
|
|
2213
2645
|
this.log.info("");
|
|
2214
2646
|
}
|
|
2215
2647
|
/**
|
|
@@ -2232,6 +2664,30 @@ var ProjectScaffolder = class {
|
|
|
2232
2664
|
}
|
|
2233
2665
|
}
|
|
2234
2666
|
};
|
|
2667
|
+
/**
|
|
2668
|
+
* Map a package manager name to the command that runs a project-local binary.
|
|
2669
|
+
*
|
|
2670
|
+
* - npm: `npx`
|
|
2671
|
+
* - yarn: `yarn` (yarn auto-resolves binary names; `yarn shadcn ...` works)
|
|
2672
|
+
* - pnpm: `pnpm exec`
|
|
2673
|
+
* - bun: `bunx`
|
|
2674
|
+
*
|
|
2675
|
+
* Used to invoke `shadcn init` / `shadcn add` regardless of the user's PM —
|
|
2676
|
+
* `npm shadcn ...` is invalid (it tries to run a script named `shadcn`).
|
|
2677
|
+
*/
|
|
2678
|
+
/** Quote a value so it survives shell parsing. */
|
|
2679
|
+
const escapeShellArg = (value) => {
|
|
2680
|
+
if (/^[A-Za-z0-9_./@:-]+$/.test(value)) return value;
|
|
2681
|
+
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
2682
|
+
};
|
|
2683
|
+
const pmExecPrefix = (pmName) => {
|
|
2684
|
+
switch (pmName) {
|
|
2685
|
+
case "npm": return "npx";
|
|
2686
|
+
case "pnpm": return "pnpm exec";
|
|
2687
|
+
case "bun": return "bunx";
|
|
2688
|
+
default: return "yarn";
|
|
2689
|
+
}
|
|
2690
|
+
};
|
|
2235
2691
|
//#endregion
|
|
2236
2692
|
//#region ../../src/cli/core/tasks/BuildTask.ts
|
|
2237
2693
|
/**
|
|
@@ -2643,7 +3099,7 @@ var BuildCompressTask = class extends BuildTask {
|
|
|
2643
3099
|
*
|
|
2644
3100
|
* Creates:
|
|
2645
3101
|
* - Dockerfile with configurable base image
|
|
2646
|
-
* - Copies
|
|
3102
|
+
* - Copies migrations directory if it exists
|
|
2647
3103
|
* - Builds Docker image when `--image` flag is provided
|
|
2648
3104
|
*/
|
|
2649
3105
|
var BuildDockerTask = class extends BuildTask {
|
|
@@ -2658,15 +3114,15 @@ var BuildDockerTask = class extends BuildTask {
|
|
|
2658
3114
|
await ctx.run({
|
|
2659
3115
|
name: "generate deploy config (docker)",
|
|
2660
3116
|
handler: async () => {
|
|
2661
|
-
await this.
|
|
3117
|
+
await this.copyMigrations(ctx.root, distDir);
|
|
2662
3118
|
await this.writeDockerfile(ctx.root, distDir, dockerFrom, dockerCommand);
|
|
2663
3119
|
}
|
|
2664
3120
|
});
|
|
2665
3121
|
if (ctx.flags?.image) await this.buildDockerImage(ctx, distDir);
|
|
2666
3122
|
}
|
|
2667
|
-
async
|
|
2668
|
-
const
|
|
2669
|
-
if (await this.fs.exists(
|
|
3123
|
+
async copyMigrations(root, distDir) {
|
|
3124
|
+
const migrationsDir = this.fs.join(root, "migrations");
|
|
3125
|
+
if (await this.fs.exists(migrationsDir)) await this.fs.cp(migrationsDir, this.fs.join(root, distDir, "migrations"));
|
|
2670
3126
|
}
|
|
2671
3127
|
async writeDockerfile(root, distDir, image, command) {
|
|
2672
3128
|
const dockerfile = `# This file was automatically generated. DO NOT MODIFY.
|
|
@@ -2927,6 +3383,10 @@ var BuildServerTask = class extends BuildTask {
|
|
|
2927
3383
|
chunkFileNames: "[hash].js",
|
|
2928
3384
|
assetFileNames: "[hash][extname]",
|
|
2929
3385
|
format: "esm",
|
|
3386
|
+
codeSplitting: { groups: [{
|
|
3387
|
+
name: "react",
|
|
3388
|
+
test: /node_modules\/react(\/|-dom\/)/
|
|
3389
|
+
}] },
|
|
2930
3390
|
minify: {
|
|
2931
3391
|
mangle: { keepNames: true },
|
|
2932
3392
|
compress: { keepNames: {
|
|
@@ -4467,7 +4927,12 @@ const DEFAULT_IGNORE = [
|
|
|
4467
4927
|
*/
|
|
4468
4928
|
const changelogOptions = $atom({
|
|
4469
4929
|
name: "alepha.cli.changelog.options",
|
|
4470
|
-
schema: t.object({
|
|
4930
|
+
schema: t.object({
|
|
4931
|
+
/**
|
|
4932
|
+
* Scopes to ignore (e.g., "project", "release", "chore").
|
|
4933
|
+
* Commits like `feat(chore): ...` will be excluded from changelog.
|
|
4934
|
+
*/
|
|
4935
|
+
ignore: t.optional(t.array(t.string())) }),
|
|
4471
4936
|
default: { ignore: DEFAULT_IGNORE }
|
|
4472
4937
|
});
|
|
4473
4938
|
//#endregion
|
|
@@ -4609,10 +5074,20 @@ var ChangelogCommand = class {
|
|
|
4609
5074
|
name: "changelog",
|
|
4610
5075
|
description: "Generate changelog from conventional commits (outputs to stdout)",
|
|
4611
5076
|
flags: t.object({
|
|
5077
|
+
/**
|
|
5078
|
+
* Show changes from this ref (tag, commit, branch).
|
|
5079
|
+
* Defaults to the latest version tag.
|
|
5080
|
+
* Example: --from=1.0.0
|
|
5081
|
+
*/
|
|
4612
5082
|
from: t.optional(t.string({
|
|
4613
5083
|
aliases: ["f"],
|
|
4614
5084
|
description: "Starting ref (default: latest tag)"
|
|
4615
5085
|
})),
|
|
5086
|
+
/**
|
|
5087
|
+
* Show changes up to this ref (tag, commit, branch).
|
|
5088
|
+
* Defaults to HEAD.
|
|
5089
|
+
* Example: --to=main
|
|
5090
|
+
*/
|
|
4616
5091
|
to: t.optional(t.string({
|
|
4617
5092
|
aliases: ["t"],
|
|
4618
5093
|
description: "Ending ref (default: HEAD)"
|
|
@@ -4774,9 +5249,9 @@ var InitCommand = class {
|
|
|
4774
5249
|
aliases: ["r"],
|
|
4775
5250
|
description: "Include React dependencies and web module (src/web/)"
|
|
4776
5251
|
})),
|
|
4777
|
-
ui: t.optional(t.boolean({ description: "Include @alepha/ui (components, auth portal, admin portal)" })),
|
|
4778
|
-
saas: t.optional(t.boolean({ description: "Include authentication, admin portal, API, UI, and React. Everything you need for a SaaS app." })),
|
|
4779
5252
|
tailwind: t.optional(t.boolean({ description: "Include Tailwind CSS with Vite plugin. Implies --react" })),
|
|
5253
|
+
shadcn: t.optional(t.union([t.boolean(), t.text()], { description: "Set up shadcn/ui (components.json, cn helper, theme tokens, alepha registry). Pass an optional preset id (default: b0). Implies --react and --tailwind" })),
|
|
5254
|
+
saas: t.optional(t.union([t.boolean(), t.text()], { description: "Scaffold a SaaS starter: auth (login/register/reset/verify) + admin panel (/admin AppShell with users/sessions/api-keys/parameters/audits). Pass an optional preset id (default: b0). Implies --shadcn and --api" })),
|
|
4780
5255
|
test: t.optional(t.boolean({ description: "Include Vitest and create test directory" })),
|
|
4781
5256
|
force: t.optional(t.boolean({
|
|
4782
5257
|
aliases: ["f"],
|