alepha 0.21.2 → 0.23.0
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/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts +393 -403
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +25 -56
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.browser.js +31 -1
- package/dist/api/files/index.browser.js.map +1 -1
- package/dist/api/files/index.d.ts +313 -208
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +152 -42
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +2 -2
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +282 -285
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +39 -33
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +217 -222
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +188 -195
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/oauth/index.d.ts +71 -76
- package/dist/api/oauth/index.d.ts.map +1 -1
- package/dist/api/oauth/index.js.map +1 -1
- package/dist/api/organizations/index.browser.js.map +1 -1
- package/dist/api/organizations/index.d.ts +104 -109
- package/dist/api/organizations/index.d.ts.map +1 -1
- package/dist/api/organizations/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +43 -16
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +488 -344
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +175 -35
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.d.ts +396 -402
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/subscriptions/index.d.ts +644 -652
- package/dist/api/subscriptions/index.d.ts.map +1 -1
- package/dist/api/subscriptions/index.js +1 -1
- package/dist/api/subscriptions/index.js.map +1 -1
- package/dist/api/users/index.browser.js +7 -0
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +1106 -1005
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +307 -64
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.browser.js.map +1 -1
- package/dist/api/verifications/index.d.ts +137 -143
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/background/index.d.ts +95 -0
- package/dist/background/index.d.ts.map +1 -0
- package/dist/background/index.js +121 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/index.workerd.js +110 -0
- package/dist/background/index.workerd.js.map +1 -0
- package/dist/batch/index.d.ts +5 -7
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/bin/index.js.map +1 -1
- package/dist/bucket/index.d.ts +76 -54
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +58 -11
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +200 -5
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.d.ts +7 -10
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/cache/database/index.d.ts +22 -26
- package/dist/cache/database/index.d.ts.map +1 -1
- package/dist/cache/database/index.js.map +1 -1
- package/dist/cache/redis/index.d.ts +4 -7
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/captcha/index.d.ts +3 -6
- package/dist/captcha/index.d.ts.map +1 -1
- package/dist/captcha/index.js.map +1 -1
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +458 -249
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +372 -660
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +3 -5
- package/dist/cli/devtools/index.d.ts.map +1 -1
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/i18n/index.d.ts +20 -17
- package/dist/cli/i18n/index.d.ts.map +1 -1
- package/dist/cli/i18n/index.js +45 -11
- package/dist/cli/i18n/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +126 -1342
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +136 -2374
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/platform-lib/index.d.ts +1472 -0
- package/dist/cli/platform-lib/index.d.ts.map +1 -0
- package/dist/cli/platform-lib/index.js +2660 -0
- package/dist/cli/platform-lib/index.js.map +1 -0
- package/dist/cli/vendor/index.d.ts +17 -21
- package/dist/cli/vendor/index.d.ts.map +1 -1
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.d.ts +20 -19
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +39 -10
- package/dist/command/index.js.map +1 -1
- package/dist/{containers → container}/core/index.d.ts +13 -15
- package/dist/container/core/index.d.ts.map +1 -0
- package/dist/{containers → container}/core/index.js +23 -14
- package/dist/container/core/index.js.map +1 -0
- package/dist/{containers → container}/core/index.workerd.js +37 -22
- package/dist/container/core/index.workerd.js.map +1 -0
- package/dist/core/index.browser.js +27 -1
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +48 -24
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +27 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +27 -1
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +27 -1
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.browser.js.map +1 -1
- package/dist/crypto/index.d.ts +5 -8
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.js.map +1 -1
- package/dist/datetime/index.d.ts +3 -4
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/brevo/index.d.ts +2 -4
- package/dist/email/brevo/index.d.ts.map +1 -1
- package/dist/email/brevo/index.js.map +1 -1
- package/dist/email/cloudflare/index.d.ts +20 -7
- package/dist/email/cloudflare/index.d.ts.map +1 -1
- package/dist/email/cloudflare/index.js +46 -9
- package/dist/email/cloudflare/index.js.map +1 -1
- package/dist/email/core/index.d.ts +6 -9
- package/dist/email/core/index.d.ts.map +1 -1
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/core/index.workerd.js.map +1 -1
- package/dist/email/smtp/index.d.ts +10 -13
- package/dist/email/smtp/index.d.ts.map +1 -1
- package/dist/email/smtp/index.js +107 -32
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +1 -2
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +9 -14
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.d.ts +2 -4
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.d.ts +105 -76
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +196 -174
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +25 -20
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +23 -0
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +19 -1
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +76 -62
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +20 -2
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +28 -20
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +12 -15
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/core/index.js.map +1 -1
- package/dist/queue/core/index.workerd.js.map +1 -1
- package/dist/queue/redis/index.d.ts +3 -5
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/queue/redis/index.js.map +1 -1
- package/dist/react/auth/index.browser.js +9 -2
- package/dist/react/auth/index.browser.js.map +1 -1
- package/dist/react/auth/index.d.ts +14 -9
- package/dist/react/auth/index.d.ts.map +1 -1
- package/dist/react/auth/index.js +9 -2
- package/dist/react/auth/index.js.map +1 -1
- package/dist/react/core/index.d.ts +7 -8
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +6 -3
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +2 -5
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +16 -15
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/head/index.browser.js.map +1 -1
- package/dist/react/head/index.d.ts +2 -4
- package/dist/react/head/index.d.ts.map +1 -1
- package/dist/react/head/index.js.map +1 -1
- package/dist/react/i18n/index.d.ts +90 -11
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/i18n/index.js +147 -11
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.d.ts +1 -2
- package/dist/react/intro/index.d.ts.map +1 -1
- package/dist/react/intro/index.js +2 -2
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +193 -24
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +434 -222
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +249 -35
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/sitemap/index.browser.js +35 -0
- package/dist/react/sitemap/index.browser.js.map +1 -0
- package/dist/react/sitemap/index.d.ts +92 -0
- package/dist/react/sitemap/index.d.ts.map +1 -0
- package/dist/react/sitemap/index.js +131 -0
- package/dist/react/sitemap/index.js.map +1 -0
- package/dist/react/testing/index.d.ts +1 -2
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +16 -17
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/ui/index.d.ts +20 -25
- package/dist/react/ui/index.d.ts.map +1 -1
- package/dist/react/ui/index.js.map +1 -1
- package/dist/redis/index.bun.js.map +1 -1
- package/dist/redis/index.d.ts +17 -19
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts +2 -4
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/retry/index.js.map +1 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +10 -13
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +45 -48
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.browser.js.map +1 -1
- package/dist/server/auth/index.d.ts +272 -173
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +1608 -15
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.browser.js.map +1 -1
- package/dist/server/cookies/index.d.ts +20 -7
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +22 -3
- 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 +106 -73
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +44 -0
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +11 -14
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/etag/index.d.ts +6 -9
- package/dist/server/etag/index.d.ts.map +1 -1
- package/dist/server/etag/index.js.map +1 -1
- package/dist/server/health/index.d.ts +18 -21
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/health/index.js.map +1 -1
- package/dist/server/links/index.browser.js +2 -0
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +63 -67
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +2 -0
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +5 -7
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/proxy/index.d.ts +3 -5
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/proxy/index.js.map +1 -1
- package/dist/server/rate-limit/index.d.ts +10 -13
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +3 -5
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +5 -8
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +3 -5
- package/dist/sms/index.d.ts.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 +2 -4
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.workerd.js.map +1 -1
- package/dist/topic/core/index.d.ts +4 -6
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/topic/redis/index.d.ts +5 -8
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/topic/redis/index.js.map +1 -1
- package/package.json +59 -23
- package/src/api/audits/__tests__/AuditService.spec.ts +18 -110
- package/src/api/audits/controllers/AdminAuditController.ts +14 -0
- package/src/api/audits/services/AuditService.ts +21 -88
- package/src/api/files/__tests__/FileService.spec.ts +207 -2
- package/src/api/files/index.ts +3 -0
- package/src/api/files/schemas/fileCreatorSummarySchema.ts +22 -0
- package/src/api/files/schemas/fileResourceSchema.ts +10 -1
- package/src/api/files/services/FileService.ts +170 -72
- package/src/api/jobs/__tests__/$job.spec.ts +24 -1
- package/src/api/jobs/index.ts +4 -3
- package/src/api/jobs/primitives/$job.ts +7 -3
- package/src/api/jobs/providers/DirectJobDispatcher.ts +17 -36
- package/src/api/jobs/providers/JobProvider.ts +53 -24
- package/src/api/jobs/schemas/jobConfigAtom.ts +1 -1
- package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +4 -1
- package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +3 -1
- package/src/api/parameters/__tests__/$parameter.spec.ts +19 -2
- package/src/api/parameters/audits/ParameterAudits.ts +17 -0
- package/src/api/parameters/controllers/AdminParameterController.ts +95 -19
- package/src/api/parameters/index.ts +3 -0
- package/src/api/parameters/schemas/activateParameterBodySchema.ts +3 -3
- package/src/api/parameters/schemas/createParameterVersionBodySchema.ts +3 -2
- package/src/api/parameters/schemas/parameterCreatorSummarySchema.ts +25 -0
- package/src/api/parameters/schemas/parameterResponseSchema.ts +5 -0
- package/src/api/parameters/schemas/rollbackParameterBodySchema.ts +4 -2
- package/src/api/parameters/services/ParameterProvider.ts +69 -6
- package/src/api/subscriptions/jobs/SubscriptionJobs.ts +1 -1
- package/src/api/users/__tests__/AdminSessionController.spec.ts +37 -0
- package/src/api/users/audits/SessionAudits.ts +33 -0
- package/src/api/users/audits/UserAudits.ts +19 -43
- package/src/api/users/controllers/AdminUserController.ts +66 -1
- package/src/api/users/controllers/RealmController.ts +1 -0
- package/src/api/users/entities/sessions.ts +6 -0
- package/src/api/users/entities/users.ts +2 -0
- package/src/api/users/index.ts +9 -1
- package/src/api/users/primitives/$realm.ts +29 -0
- package/src/api/users/providers/RealmProvider.ts +15 -0
- package/src/api/users/schemas/realmConfigSchema.ts +14 -0
- package/src/api/users/schemas/sessionResourceSchema.ts +16 -0
- package/src/api/users/schemas/updateUserSchema.ts +1 -8
- package/src/api/users/schemas/userQuerySchema.ts +7 -0
- package/src/api/users/services/CredentialService.ts +15 -6
- package/src/api/users/services/IdentityService.ts +2 -1
- package/src/api/users/services/RegistrationService.ts +2 -1
- package/src/api/users/services/SessionCrudService.ts +19 -2
- package/src/api/users/services/SessionService.ts +39 -19
- package/src/api/users/services/UserService.ts +106 -8
- package/src/background/__tests__/BackgroundTaskProvider.spec.ts +96 -0
- package/src/background/index.ts +37 -0
- package/src/background/index.workerd.ts +28 -0
- package/src/background/providers/BackgroundTaskProvider.ts +70 -0
- package/src/background/providers/WorkerdBackgroundTaskProvider.ts +43 -0
- package/src/bucket/__tests__/$bucket.spec.ts +18 -0
- package/src/bucket/__tests__/LocalFileStorageProvider.spec.ts +5 -0
- package/src/bucket/__tests__/MemoryFileStorageProvider.spec.ts +5 -0
- package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +23 -4
- package/src/bucket/__tests__/shared.ts +30 -0
- package/src/bucket/index.ts +5 -5
- package/src/bucket/index.workerd.ts +11 -4
- package/src/bucket/primitives/$bucket.ts +27 -0
- package/src/bucket/providers/FileStorageProvider.ts +13 -0
- package/src/bucket/providers/LocalFileStorageProvider.ts +17 -1
- package/src/bucket/providers/MemoryFileStorageProvider.ts +7 -0
- package/src/bucket/providers/{CloudflareR2Provider.ts → R2FileStorageProvider.ts} +10 -1
- package/src/bucket/providers/{NodeS3BucketProvider.ts → S3FileStorageProvider.ts} +27 -5
- package/src/cli/core/__tests__/BuildDockerTask.spec.ts +25 -1
- package/src/cli/core/__tests__/init.spec.ts +0 -219
- package/src/cli/core/atoms/buildOptions.ts +0 -12
- package/src/cli/core/commands/__tests__/BuildCommand.spec.ts +43 -0
- package/src/cli/core/commands/build.ts +105 -37
- package/src/cli/core/commands/init.ts +0 -12
- package/src/cli/core/commands/pack.ts +133 -0
- package/src/cli/core/index.ts +3 -3
- package/src/cli/core/providers/ViteDevServerProvider.ts +40 -16
- package/src/cli/core/services/PackageManagerUtils.ts +0 -16
- package/src/cli/core/services/ProjectScaffolder.ts +29 -291
- package/src/cli/core/tasks/BuildCloudflareTask.ts +382 -56
- package/src/cli/core/tasks/BuildDockerTask.ts +33 -3
- package/src/cli/core/tasks/BuildPrerenderTask.ts +44 -7
- package/src/cli/core/tasks/BuildTask.ts +34 -0
- package/src/cli/core/templates/apiIndexTs.ts +1 -22
- package/src/cli/core/templates/mainCss.ts +0 -1
- package/src/cli/core/templates/webAppRouterTs.ts +0 -99
- package/src/cli/core/templates/webIndexTs.ts +1 -22
- package/src/cli/i18n/__tests__/I18nCheckService.spec.ts +48 -0
- package/src/cli/i18n/services/I18nCheckService.ts +65 -11
- package/src/cli/platform/__tests__/SecretsCommand.spec.ts +5 -3
- package/src/cli/platform/commands/SecretsCommand.ts +8 -6
- package/src/cli/platform/commands/platform.ts +192 -46
- package/src/cli/platform/index.ts +12 -52
- package/src/cli/{platform → platform-lib}/__tests__/CloudflareAdapter.spec.ts +426 -169
- package/src/cli/{platform → platform-lib}/__tests__/NamingService.spec.ts +91 -4
- package/src/cli/{platform → platform-lib}/__tests__/VercelAdapter.spec.ts +56 -85
- package/src/cli/{platform → platform-lib}/adapters/CloudflareAdapter.ts +519 -190
- package/src/cli/{platform → platform-lib}/adapters/PlatformAdapter.ts +62 -35
- package/src/cli/{platform → platform-lib}/adapters/VercelAdapter.ts +6 -10
- package/src/cli/{platform → platform-lib}/atoms/platformOptions.ts +34 -1
- package/src/cli/platform-lib/index.ts +67 -0
- package/src/cli/platform-lib/services/NamingService.ts +136 -0
- package/src/cli/{platform → platform-lib}/services/PlatformInspector.ts +60 -13
- package/src/cli/{platform → platform-lib}/services/PlatformOrchestrator.ts +54 -43
- package/src/cli/{platform → platform-lib}/services/WranglerApi.ts +4 -2
- package/src/command/__tests__/Runner.spec.ts +20 -0
- package/src/command/helpers/EnvUtils.ts +19 -3
- package/src/command/helpers/Runner.ts +12 -2
- package/src/command/providers/CliProvider.ts +34 -1
- package/src/{containers → container}/core/__tests__/$container.spec.ts +5 -5
- package/src/{containers → container}/core/index.ts +4 -4
- package/src/{containers → container}/core/index.workerd.ts +19 -3
- package/src/{containers → container}/core/primitives/$container.ts +1 -1
- package/src/{containers → container}/core/providers/CloudflareContainerProvider.ts +17 -19
- package/src/{containers → container}/core/providers/ContainerProvider.ts +16 -2
- package/src/{containers → container}/core/providers/MockContainerProvider.ts +1 -1
- package/src/core/Alepha.ts +49 -1
- package/src/core/__tests__/$env.spec.ts +42 -0
- package/src/core/__tests__/dump.spec.ts +47 -0
- package/src/email/cloudflare/__tests__/CloudflareEmailProvider.spec.ts +42 -10
- package/src/email/cloudflare/index.ts +14 -5
- package/src/email/cloudflare/providers/CloudflareEmailProvider.ts +54 -9
- package/src/logger/__tests__/Logger.spec.ts +55 -0
- package/src/logger/index.ts +13 -0
- package/src/logger/services/Logger.ts +31 -1
- package/src/mcp/__tests__/McpServerProvider.spec.ts +71 -0
- package/src/mcp/providers/McpServerProvider.ts +55 -0
- package/src/orm/__tests__/orm-showcase-tests.ts +27 -0
- package/src/orm/__tests__/orm-showcase.spec.ts +12 -0
- package/src/orm/core/interfaces/PgQuery.ts +4 -1
- package/src/orm/core/services/Repository.ts +27 -11
- package/src/react/auth/hooks/useAuth.ts +10 -5
- package/src/react/core/__tests__/useQuery.browser.spec.tsx +25 -0
- package/src/react/core/hooks/useAction.ts +14 -3
- package/src/react/core/hooks/useQuery.ts +24 -4
- package/src/react/form/__tests__/FormModel-submit-loading.spec.ts +71 -0
- package/src/react/form/__tests__/form-submitting-reactive.browser.spec.tsx +96 -0
- package/src/react/form/services/FormModel.ts +57 -39
- package/src/react/i18n/__tests__/I18nProvider.spec.ts +89 -0
- package/src/react/i18n/__tests__/locale-routing.spec.ts +107 -0
- package/src/react/i18n/components/Translate.tsx +47 -0
- package/src/react/i18n/index.ts +2 -0
- package/src/react/i18n/providers/I18nProvider.ts +171 -12
- package/src/react/intro/components/GettingStartedAdminSlide.tsx +2 -2
- package/src/react/router/__tests__/$page.spec.tsx +3 -2
- package/src/react/router/__tests__/RouterLocaleProvider.spec.ts +127 -0
- package/src/react/router/__tests__/page-can.spec.ts +18 -13
- package/src/react/router/hooks/useQueryParams.ts +114 -14
- package/src/react/router/index.browser.ts +4 -0
- package/src/react/router/index.shared.ts +1 -0
- package/src/react/router/index.ts +9 -0
- package/src/react/router/primitives/$page.ts +85 -4
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +18 -8
- package/src/react/router/providers/ReactPageProvider.ts +12 -1
- package/src/react/router/providers/ReactServerProvider.ts +96 -14
- package/src/react/router/providers/RootComponentsProvider.ts +13 -0
- package/src/react/router/providers/RouterLocaleProvider.ts +125 -0
- package/src/react/router/providers/__tests__/RootComponentsProvider.spec.ts +15 -0
- package/src/react/router/providers/__tests__/rootComponents.ssr.browser.spec.tsx +67 -0
- package/src/react/sitemap/__tests__/$sitemap.spec.ts +131 -0
- package/src/react/sitemap/index.browser.ts +21 -0
- package/src/react/sitemap/index.ts +25 -0
- package/src/react/sitemap/primitives/$sitemap.browser.ts +26 -0
- package/src/react/sitemap/primitives/$sitemap.ts +196 -0
- package/src/react/ui/services/SchemaControl.ts +3 -4
- package/src/server/auth/__tests__/appleClientSecret.spec.ts +34 -0
- package/src/server/auth/__tests__/authFederationClient.spec.ts +40 -0
- package/src/server/auth/__tests__/federationAssertion.spec.ts +146 -0
- package/src/server/auth/__tests__/federationRedirectReplay.spec.ts +44 -0
- package/src/server/auth/helpers/appleClientSecret.ts +24 -0
- package/src/server/auth/helpers/federationAssertion.ts +74 -0
- package/src/server/auth/helpers/jtiReplayGuard.ts +41 -0
- package/src/server/auth/helpers/safeRedirectPath.ts +19 -0
- package/src/server/auth/index.ts +4 -0
- package/src/server/auth/primitives/$authFederationBroker.ts +273 -0
- package/src/server/auth/primitives/$authFederationClient.ts +89 -0
- package/src/server/auth/providers/ServerAuthProvider.ts +18 -4
- package/src/server/cookies/__tests__/ServerCookiesProvider.spec.ts +70 -0
- package/src/server/cookies/providers/ServerCookiesProvider.ts +23 -3
- package/src/server/core/interfaces/ServerRequest.ts +8 -0
- package/src/server/core/primitives/$route.ts +27 -0
- package/src/server/core/providers/ServerMultipartProvider.ts +19 -0
- package/src/server/links/providers/LinkProvider.ts +10 -0
- package/dist/containers/core/index.d.ts.map +0 -1
- package/dist/containers/core/index.js.map +0 -1
- package/dist/containers/core/index.workerd.js.map +0 -1
- package/src/cli/core/tasks/BuildSitemapTask.ts +0 -130
- package/src/cli/core/templates/componentsJsonTs.ts +0 -39
- package/src/cli/core/templates/saasAdminLayoutTsx.ts +0 -77
- package/src/cli/core/templates/saasAdminPagesTsx.ts +0 -26
- package/src/cli/core/templates/saasAuthLayoutTsx.ts +0 -22
- package/src/cli/core/templates/saasAuthPagesTsx.ts +0 -62
- package/src/cli/core/templates/saasRealmProviderTs.ts +0 -52
- package/src/cli/platform/services/NamingService.ts +0 -54
- /package/dist/orm/core/{chunk-o8xxKEmq.js → chunk-B4FMCO8f.js} +0 -0
- /package/dist/react/testing/{chunk-6Ep1yQYe.js → chunk-BpyX8vjI.js} +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/GitHubSecretStore.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/PlatformCacheProvider.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/PlatformInspector.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/PlatformOrchestrator.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/SecretFilterService.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/detectResources.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/GitHubSecretStore.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/MemorySecretStore.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/PlatformCacheProvider.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/SecretStoreProvider.ts +0 -0
- /package/src/cli/{platform → platform-lib}/schemas/cloudflare.ts +0 -0
- /package/src/cli/{platform → platform-lib}/schemas/platform.ts +0 -0
- /package/src/cli/{platform → platform-lib}/schemas/vercel.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/CloudflareApi.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/SecretFilterService.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/VercelApi.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/VercelCli.ts +0 -0
- /package/src/{containers → container}/core/interfaces/ContainerOptions.ts +0 -0
- /package/src/{containers → container}/core/providers/NodeContainerProvider.ts +0 -0
package/dist/cli/core/index.js
CHANGED
|
@@ -10,9 +10,7 @@ import { basename, dirname, isAbsolute, join, relative, resolve } from "node:pat
|
|
|
10
10
|
import pkg from "alepha/package.json" with { type: "json" };
|
|
11
11
|
import { analyzer } from "vite-bundle-analyzer";
|
|
12
12
|
import { KV_DEFAULT_BINDING } from "alepha/cache";
|
|
13
|
-
import {
|
|
14
|
-
import { EmailProvider } from "alepha/email";
|
|
15
|
-
import { CloudflareEmailProvider, SEND_EMAIL_DEFAULT_BINDING } from "alepha/email/cloudflare";
|
|
13
|
+
import { SEND_EMAIL_DEFAULT_BINDING } from "alepha/email/cloudflare";
|
|
16
14
|
import { QUEUE_DEFAULT_BINDING } from "alepha/queue";
|
|
17
15
|
import { promisify } from "node:util";
|
|
18
16
|
import { brotliCompress, gzip } from "node:zlib";
|
|
@@ -289,15 +287,7 @@ domain: t.optional(t.string()) })),
|
|
|
289
287
|
* TODO: Not yet implemented.
|
|
290
288
|
*/
|
|
291
289
|
offline: t.optional(t.boolean())
|
|
292
|
-
}))
|
|
293
|
-
/**
|
|
294
|
-
* Sitemap generation configuration.
|
|
295
|
-
*/
|
|
296
|
-
sitemap: t.optional(t.object({
|
|
297
|
-
/**
|
|
298
|
-
* Base URL for sitemap entries.
|
|
299
|
-
*/
|
|
300
|
-
hostname: t.string() }))
|
|
290
|
+
}))
|
|
301
291
|
}),
|
|
302
292
|
default: {}
|
|
303
293
|
});
|
|
@@ -1109,7 +1099,6 @@ var PackageManagerUtils = class {
|
|
|
1109
1099
|
devDependencies.tailwindcss = alephaDeps.tailwindcss;
|
|
1110
1100
|
devDependencies["@tailwindcss/vite"] = alephaDeps["@tailwindcss/vite"];
|
|
1111
1101
|
}
|
|
1112
|
-
if (modes.shadcn) devDependencies.shadcn = alephaDeps.shadcn;
|
|
1113
1102
|
if (modes.react) {
|
|
1114
1103
|
dependencies.react = alephaDeps.react;
|
|
1115
1104
|
dependencies["react-dom"] = alephaDeps["react-dom"];
|
|
@@ -1279,19 +1268,7 @@ export type HelloResponse = Static<typeof helloResponseSchema>;
|
|
|
1279
1268
|
//#endregion
|
|
1280
1269
|
//#region ../../src/cli/core/templates/apiIndexTs.ts
|
|
1281
1270
|
const apiIndexTs = (options = {}) => {
|
|
1282
|
-
const { appName = "app"
|
|
1283
|
-
if (saas) return `
|
|
1284
|
-
import { $module } from "alepha";
|
|
1285
|
-
import { AlephaApiUsers } from "alepha/api/users";
|
|
1286
|
-
import { HelloController } from "./controllers/HelloController.ts";
|
|
1287
|
-
import { RealmProvider } from "./providers/RealmProvider.ts";
|
|
1288
|
-
|
|
1289
|
-
export const ApiModule = $module({
|
|
1290
|
-
name: "${appName}.api",
|
|
1291
|
-
services: [HelloController, RealmProvider],
|
|
1292
|
-
imports: [AlephaApiUsers],
|
|
1293
|
-
});
|
|
1294
|
-
`.trim();
|
|
1271
|
+
const { appName = "app" } = options;
|
|
1295
1272
|
return `
|
|
1296
1273
|
import { $module } from "alepha";
|
|
1297
1274
|
import { HelloController } from "./controllers/HelloController.ts";
|
|
@@ -1362,46 +1339,6 @@ const biomeJson = () => `
|
|
|
1362
1339
|
}
|
|
1363
1340
|
`.trim();
|
|
1364
1341
|
//#endregion
|
|
1365
|
-
//#region ../../src/cli/core/templates/componentsJsonTs.ts
|
|
1366
|
-
/**
|
|
1367
|
-
* `components.json` is the shadcn CLI's project config — it tells
|
|
1368
|
-
* `shadcn add` where to drop primitives, which tailwind tokens to use,
|
|
1369
|
-
* which icon library to wire up, and which custom registries to resolve.
|
|
1370
|
-
*
|
|
1371
|
-
* Aliases follow shadcn's defaults (`@/components`, `@/lib/utils`) so the
|
|
1372
|
-
* CLI honors them across `init` + `add` calls. Alepha app code lives at
|
|
1373
|
-
* `src/web/` (Home, AppRouter, …) and the shadcn primitives live at
|
|
1374
|
-
* `src/components/` — kept separate to make the registry components
|
|
1375
|
-
* trivially upgradable via `shadcn add --overwrite`.
|
|
1376
|
-
*
|
|
1377
|
-
* The `registries` block pre-wires the public Alepha registry — consumers
|
|
1378
|
-
* can immediately run e.g. `shadcn add @alepha/auth-login`.
|
|
1379
|
-
*/
|
|
1380
|
-
const componentsJsonTs = () => `{
|
|
1381
|
-
"$schema": "https://ui.shadcn.com/schema.json",
|
|
1382
|
-
"style": "new-york",
|
|
1383
|
-
"rsc": false,
|
|
1384
|
-
"tsx": true,
|
|
1385
|
-
"tailwind": {
|
|
1386
|
-
"config": "",
|
|
1387
|
-
"css": "src/main.css",
|
|
1388
|
-
"baseColor": "neutral",
|
|
1389
|
-
"cssVariables": true
|
|
1390
|
-
},
|
|
1391
|
-
"aliases": {
|
|
1392
|
-
"components": "@/components",
|
|
1393
|
-
"utils": "@/lib/utils",
|
|
1394
|
-
"ui": "@/components/ui",
|
|
1395
|
-
"lib": "@/lib",
|
|
1396
|
-
"hooks": "@/hooks"
|
|
1397
|
-
},
|
|
1398
|
-
"iconLibrary": "lucide",
|
|
1399
|
-
"registries": {
|
|
1400
|
-
"@alepha": "https://alepha.dev/r/{name}.json"
|
|
1401
|
-
}
|
|
1402
|
-
}
|
|
1403
|
-
`;
|
|
1404
|
-
//#endregion
|
|
1405
1342
|
//#region ../../src/cli/core/templates/dummySpecTs.ts
|
|
1406
1343
|
/**
|
|
1407
1344
|
* Starter spec written by `alepha init`. It doubles as a worked example:
|
|
@@ -1555,7 +1492,6 @@ const mainCss = (opts = {}) => {
|
|
|
1555
1492
|
*
|
|
1556
1493
|
* Options:
|
|
1557
1494
|
* - Tailwind CSS: Use \`alepha init --tailwind\` to add Tailwind CSS
|
|
1558
|
-
* - shadcn/ui: Use \`alepha init --shadcn\` to add shadcn/ui setup
|
|
1559
1495
|
* - Raw CSS: Write your own styles below
|
|
1560
1496
|
*/
|
|
1561
1497
|
|
|
@@ -1586,241 +1522,6 @@ run(alepha);
|
|
|
1586
1522
|
`.trim();
|
|
1587
1523
|
};
|
|
1588
1524
|
//#endregion
|
|
1589
|
-
//#region ../../src/cli/core/templates/saasAdminLayoutTsx.ts
|
|
1590
|
-
/**
|
|
1591
|
-
* SaaS admin layout — full AppShell on /admin with a sidebar, breadcrumbs,
|
|
1592
|
-
* a Sonner toaster, and a confirm provider. The page list grows with
|
|
1593
|
-
* whatever `admin-*` registry components the user adds.
|
|
1594
|
-
*
|
|
1595
|
-
* All UI primitives come from `src/components/*` where `shadcn add` drops
|
|
1596
|
-
* them; alepha app code lives in `src/web/*` and references them via the
|
|
1597
|
-
* `@/components/*` alias.
|
|
1598
|
-
*/
|
|
1599
|
-
const saasAdminLayoutTsx = () => `import { AppShell } from "@/components/app-shell/app-shell";
|
|
1600
|
-
import { Toaster } from "@/components/ui/sonner";
|
|
1601
|
-
import { TooltipProvider } from "@/components/ui/tooltip";
|
|
1602
|
-
import { DialogProvider } from "@/components/use-dialog/use-dialog";
|
|
1603
|
-
import { NestedView, useRouterState } from "alepha/react/router";
|
|
1604
|
-
import { ShieldCheck, Users } from "lucide-react";
|
|
1605
|
-
|
|
1606
|
-
const NAV = [
|
|
1607
|
-
{
|
|
1608
|
-
label: "Identity",
|
|
1609
|
-
items: [
|
|
1610
|
-
{ href: "/admin/users", label: "Users", icon: Users },
|
|
1611
|
-
{ href: "/admin/sessions", label: "Sessions", icon: ShieldCheck },
|
|
1612
|
-
],
|
|
1613
|
-
},
|
|
1614
|
-
] as const;
|
|
1615
|
-
|
|
1616
|
-
const findCrumbs = (pathname: string): { label: string; href?: string }[] => {
|
|
1617
|
-
for (const group of NAV) {
|
|
1618
|
-
const match = group.items.find((it) => it.href === pathname);
|
|
1619
|
-
if (match) return [{ label: group.label }, { label: match.label }];
|
|
1620
|
-
}
|
|
1621
|
-
return [];
|
|
1622
|
-
};
|
|
1623
|
-
|
|
1624
|
-
const AdminLayout = () => {
|
|
1625
|
-
const state = useRouterState();
|
|
1626
|
-
const crumbs = findCrumbs(state.url.pathname);
|
|
1627
|
-
|
|
1628
|
-
return (
|
|
1629
|
-
<TooltipProvider>
|
|
1630
|
-
<DialogProvider>
|
|
1631
|
-
<AppShell
|
|
1632
|
-
brand={
|
|
1633
|
-
<a
|
|
1634
|
-
href="/admin"
|
|
1635
|
-
className="flex items-center gap-2 px-2 py-2 font-semibold group-data-[collapsible=icon]:justify-center group-data-[collapsible=icon]:px-0"
|
|
1636
|
-
>
|
|
1637
|
-
<span className="bg-primary text-primary-foreground flex size-7 shrink-0 items-center justify-center rounded">
|
|
1638
|
-
α
|
|
1639
|
-
</span>
|
|
1640
|
-
<span className="truncate group-data-[collapsible=icon]:hidden">
|
|
1641
|
-
Admin
|
|
1642
|
-
</span>
|
|
1643
|
-
</a>
|
|
1644
|
-
}
|
|
1645
|
-
nav={NAV.map((group) => ({
|
|
1646
|
-
label: group.label,
|
|
1647
|
-
items: group.items.map((it) => ({
|
|
1648
|
-
href: it.href,
|
|
1649
|
-
label: it.label,
|
|
1650
|
-
icon: it.icon,
|
|
1651
|
-
active: it.href === state.url.pathname,
|
|
1652
|
-
})),
|
|
1653
|
-
}))}
|
|
1654
|
-
breadcrumbs={crumbs.length ? crumbs : undefined}
|
|
1655
|
-
>
|
|
1656
|
-
<NestedView />
|
|
1657
|
-
</AppShell>
|
|
1658
|
-
<Toaster />
|
|
1659
|
-
</DialogProvider>
|
|
1660
|
-
</TooltipProvider>
|
|
1661
|
-
);
|
|
1662
|
-
};
|
|
1663
|
-
|
|
1664
|
-
export default AdminLayout;
|
|
1665
|
-
`;
|
|
1666
|
-
//#endregion
|
|
1667
|
-
//#region ../../src/cli/core/templates/saasAdminPagesTsx.ts
|
|
1668
|
-
/**
|
|
1669
|
-
* Admin pages — each is a thin wrapper around the matching `admin-*`
|
|
1670
|
-
* registry component (placed at `src/components/admin/*`). The starter
|
|
1671
|
-
* ships with Users + Sessions; add more by `shadcn add @alepha/admin-…`
|
|
1672
|
-
* and a matching `$page(...)` in AppRouter.
|
|
1673
|
-
*/
|
|
1674
|
-
const saasAdminUsersTsx = () => `import { AdminUsers } from "@/components/admin/admin-users";
|
|
1675
|
-
|
|
1676
|
-
const AdminUsersPage = () => {
|
|
1677
|
-
return <AdminUsers />;
|
|
1678
|
-
};
|
|
1679
|
-
|
|
1680
|
-
export default AdminUsersPage;
|
|
1681
|
-
`;
|
|
1682
|
-
const saasAdminSessionsTsx = () => `import { AdminSessions } from "@/components/admin/admin-sessions";
|
|
1683
|
-
|
|
1684
|
-
const AdminSessionsPage = () => {
|
|
1685
|
-
return <AdminSessions />;
|
|
1686
|
-
};
|
|
1687
|
-
|
|
1688
|
-
export default AdminSessionsPage;
|
|
1689
|
-
`;
|
|
1690
|
-
//#endregion
|
|
1691
|
-
//#region ../../src/cli/core/templates/saasAuthLayoutTsx.ts
|
|
1692
|
-
/**
|
|
1693
|
-
* SaaS auth layout — route parent for every /auth/* page (login, register,
|
|
1694
|
-
* reset-password, verify-email), mounted as children so they share it.
|
|
1695
|
-
*
|
|
1696
|
-
* The auth-* blocks from the registry are self-contained full-page layouts
|
|
1697
|
-
* (they own their own min-height, centering and padding), so this layout is
|
|
1698
|
-
* just a passthrough — wrapping them in another centered, padded, full-height
|
|
1699
|
-
* box would overflow the viewport and add a scrollbar.
|
|
1700
|
-
*/
|
|
1701
|
-
const saasAuthLayoutTsx = () => `import { NestedView } from "alepha/react/router";
|
|
1702
|
-
|
|
1703
|
-
const AuthLayout = () => {
|
|
1704
|
-
return (
|
|
1705
|
-
<div className="bg-background">
|
|
1706
|
-
<NestedView />
|
|
1707
|
-
</div>
|
|
1708
|
-
);
|
|
1709
|
-
};
|
|
1710
|
-
|
|
1711
|
-
export default AuthLayout;
|
|
1712
|
-
`;
|
|
1713
|
-
//#endregion
|
|
1714
|
-
//#region ../../src/cli/core/templates/saasAuthPagesTsx.ts
|
|
1715
|
-
/**
|
|
1716
|
-
* Per-page wrapper around the registry components. The registry component
|
|
1717
|
-
* receives the realm config from the page loader; the page itself stays a
|
|
1718
|
-
* thin shell so apps can layer their branding around it.
|
|
1719
|
-
*
|
|
1720
|
-
* Registry components land at `src/components/auth/*` (shadcn defaults).
|
|
1721
|
-
*/
|
|
1722
|
-
const saasAuthLoginTsx = () => `import { AuthLogin } from "@/components/auth/auth-login";
|
|
1723
|
-
import type { RealmConfig } from "alepha/api/users";
|
|
1724
|
-
|
|
1725
|
-
export interface AuthLoginPageProps {
|
|
1726
|
-
realmConfig: RealmConfig;
|
|
1727
|
-
}
|
|
1728
|
-
|
|
1729
|
-
const AuthLoginPage = (props: AuthLoginPageProps) => {
|
|
1730
|
-
return <AuthLogin realmConfig={props.realmConfig} />;
|
|
1731
|
-
};
|
|
1732
|
-
|
|
1733
|
-
export default AuthLoginPage;
|
|
1734
|
-
`;
|
|
1735
|
-
const saasAuthRegisterTsx = () => `import { AuthRegister } from "@/components/auth/auth-register";
|
|
1736
|
-
import type { RealmConfig } from "alepha/api/users";
|
|
1737
|
-
|
|
1738
|
-
export interface AuthRegisterPageProps {
|
|
1739
|
-
realmConfig: RealmConfig;
|
|
1740
|
-
}
|
|
1741
|
-
|
|
1742
|
-
const AuthRegisterPage = (props: AuthRegisterPageProps) => {
|
|
1743
|
-
return <AuthRegister realmConfig={props.realmConfig} />;
|
|
1744
|
-
};
|
|
1745
|
-
|
|
1746
|
-
export default AuthRegisterPage;
|
|
1747
|
-
`;
|
|
1748
|
-
const saasAuthResetPasswordTsx = () => `import { AuthResetPassword } from "@/components/auth/auth-reset-password";
|
|
1749
|
-
import type { RealmConfig } from "alepha/api/users";
|
|
1750
|
-
|
|
1751
|
-
export interface AuthResetPasswordPageProps {
|
|
1752
|
-
realmConfig: RealmConfig;
|
|
1753
|
-
}
|
|
1754
|
-
|
|
1755
|
-
const AuthResetPasswordPage = (props: AuthResetPasswordPageProps) => {
|
|
1756
|
-
return <AuthResetPassword realmConfig={props.realmConfig} />;
|
|
1757
|
-
};
|
|
1758
|
-
|
|
1759
|
-
export default AuthResetPasswordPage;
|
|
1760
|
-
`;
|
|
1761
|
-
const saasAuthVerifyEmailTsx = () => `import { AuthVerifyEmail } from "@/components/auth/auth-verify-email";
|
|
1762
|
-
|
|
1763
|
-
const AuthVerifyEmailPage = () => {
|
|
1764
|
-
return <AuthVerifyEmail />;
|
|
1765
|
-
};
|
|
1766
|
-
|
|
1767
|
-
export default AuthVerifyEmailPage;
|
|
1768
|
-
`;
|
|
1769
|
-
//#endregion
|
|
1770
|
-
//#region ../../src/cli/core/templates/saasRealmProviderTs.ts
|
|
1771
|
-
/**
|
|
1772
|
-
* Realm provider scaffolded by `alepha init --saas`.
|
|
1773
|
-
*
|
|
1774
|
-
* Minimal hello-world setup: credentials login with email, admins seeded
|
|
1775
|
-
* from the `ADMIN_EMAILS` env var, and an `admin:ui` permission used by the
|
|
1776
|
-
* AppRouter to gate `/admin/*`. The default `admin` role grants `*` (so it
|
|
1777
|
-
* inherits `admin:ui`); the default `user` role excludes `admin:*` (so
|
|
1778
|
-
* non-admins get a 403 before the shell renders).
|
|
1779
|
-
*
|
|
1780
|
-
* Admin emails are read from the environment, never hard-coded — they are
|
|
1781
|
-
* deployment config (different per environment, and personal data) and
|
|
1782
|
-
* belong in `.env`, not in committed source.
|
|
1783
|
-
*/
|
|
1784
|
-
const saasRealmProviderTs = () => {
|
|
1785
|
-
return `import { $env, t } from "alepha";
|
|
1786
|
-
import { $realm } from "alepha/api/users";
|
|
1787
|
-
import { $permission } from "alepha/security";
|
|
1788
|
-
|
|
1789
|
-
export class RealmProvider {
|
|
1790
|
-
/**
|
|
1791
|
-
* Permission required to open the admin UI. Wired into AppRouter.adminLayout
|
|
1792
|
-
* via \`$secure({ permissions: ["admin:ui"] })\`.
|
|
1793
|
-
*/
|
|
1794
|
-
adminUi = $permission({
|
|
1795
|
-
group: "admin",
|
|
1796
|
-
name: "ui",
|
|
1797
|
-
description: "Access to the admin UI shell",
|
|
1798
|
-
});
|
|
1799
|
-
|
|
1800
|
-
/**
|
|
1801
|
-
* Admin emails — set \`ADMIN_EMAILS\` in \`.env\` (comma-separated for
|
|
1802
|
-
* several). Keep emails out of source: they are config, not code.
|
|
1803
|
-
*/
|
|
1804
|
-
protected readonly env = $env(
|
|
1805
|
-
t.object({
|
|
1806
|
-
ADMIN_EMAILS: t.text({ default: "" }),
|
|
1807
|
-
}),
|
|
1808
|
-
);
|
|
1809
|
-
|
|
1810
|
-
realm = $realm({
|
|
1811
|
-
settings: {
|
|
1812
|
-
adminEmails: this.env.ADMIN_EMAILS.split(",")
|
|
1813
|
-
.map((email) => email.trim())
|
|
1814
|
-
.filter(Boolean),
|
|
1815
|
-
},
|
|
1816
|
-
identities: {
|
|
1817
|
-
credentials: true,
|
|
1818
|
-
},
|
|
1819
|
-
});
|
|
1820
|
-
}
|
|
1821
|
-
`;
|
|
1822
|
-
};
|
|
1823
|
-
//#endregion
|
|
1824
1525
|
//#region ../../src/cli/core/templates/tsconfigJson.ts
|
|
1825
1526
|
const tsconfigJson = () => `
|
|
1826
1527
|
{
|
|
@@ -1886,10 +1587,6 @@ const vscodeSettingsJson = () => `
|
|
|
1886
1587
|
//#endregion
|
|
1887
1588
|
//#region ../../src/cli/core/templates/webAppRouterTs.ts
|
|
1888
1589
|
const webAppRouterTs = (options) => {
|
|
1889
|
-
if (options.saas) return saasAppRouterTs();
|
|
1890
|
-
return basicAppRouterTs(options);
|
|
1891
|
-
};
|
|
1892
|
-
const basicAppRouterTs = (options) => {
|
|
1893
1590
|
const imports = ["import { $page } from \"alepha/react/router\";"];
|
|
1894
1591
|
const classMembers = [];
|
|
1895
1592
|
if (options.api) {
|
|
@@ -1911,95 +1608,6 @@ export class AppRouter {
|
|
|
1911
1608
|
${classMembers.join("\n\n")}
|
|
1912
1609
|
}`;
|
|
1913
1610
|
};
|
|
1914
|
-
/**
|
|
1915
|
-
* SaaS router wires three trees onto the app:
|
|
1916
|
-
* / → Home
|
|
1917
|
-
* /auth/* → AuthLayout + login / register / reset / verify
|
|
1918
|
-
* /admin/* → AdminLayout + users / sessions / api-keys / parameters / audits
|
|
1919
|
-
*
|
|
1920
|
-
* Each auth page resolves the realm config from its loader, so the registry
|
|
1921
|
-
* components render with everything they need on first paint.
|
|
1922
|
-
*/
|
|
1923
|
-
const saasAppRouterTs = () => `import type { RealmController } from "alepha/api/users";
|
|
1924
|
-
import { $page, NotFound } from "alepha/react/router";
|
|
1925
|
-
import { $secure } from "alepha/security";
|
|
1926
|
-
import { $client } from "alepha/server/links";
|
|
1927
|
-
import type { HelloController } from "../api/controllers/HelloController.ts";
|
|
1928
|
-
|
|
1929
|
-
export class AppRouter {
|
|
1930
|
-
protected readonly api = $client<HelloController>();
|
|
1931
|
-
protected readonly realmApi = $client<RealmController>();
|
|
1932
|
-
|
|
1933
|
-
home = $page({
|
|
1934
|
-
path: "/",
|
|
1935
|
-
lazy: () => import("./components/Home.tsx"),
|
|
1936
|
-
loader: () => this.api.hello(),
|
|
1937
|
-
});
|
|
1938
|
-
|
|
1939
|
-
// ── /auth — login, register, reset, verify ─────────────────────────────
|
|
1940
|
-
authLayout = $page({
|
|
1941
|
-
path: "/auth",
|
|
1942
|
-
lazy: () => import("./components/auth/AuthLayout.tsx"),
|
|
1943
|
-
});
|
|
1944
|
-
|
|
1945
|
-
login = $page({
|
|
1946
|
-
parent: this.authLayout,
|
|
1947
|
-
path: "/login",
|
|
1948
|
-
name: "login",
|
|
1949
|
-
head: { title: "Sign in" },
|
|
1950
|
-
lazy: () => import("./components/auth/Login.tsx"),
|
|
1951
|
-
loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
|
|
1952
|
-
});
|
|
1953
|
-
|
|
1954
|
-
register = $page({
|
|
1955
|
-
parent: this.authLayout,
|
|
1956
|
-
path: "/register",
|
|
1957
|
-
name: "register",
|
|
1958
|
-
head: { title: "Sign up" },
|
|
1959
|
-
lazy: () => import("./components/auth/Register.tsx"),
|
|
1960
|
-
loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
|
|
1961
|
-
});
|
|
1962
|
-
|
|
1963
|
-
resetPassword = $page({
|
|
1964
|
-
parent: this.authLayout,
|
|
1965
|
-
path: "/reset-password",
|
|
1966
|
-
head: { title: "Reset password" },
|
|
1967
|
-
lazy: () => import("./components/auth/ResetPassword.tsx"),
|
|
1968
|
-
loader: async () => ({ realmConfig: await this.realmApi.getRealmConfig() }),
|
|
1969
|
-
});
|
|
1970
|
-
|
|
1971
|
-
verifyEmail = $page({
|
|
1972
|
-
parent: this.authLayout,
|
|
1973
|
-
path: "/verify-email",
|
|
1974
|
-
head: { title: "Verify email" },
|
|
1975
|
-
lazy: () => import("./components/auth/VerifyEmail.tsx"),
|
|
1976
|
-
});
|
|
1977
|
-
|
|
1978
|
-
// ── /admin — gated by 'admin:ui' permission, declared in RealmProvider.
|
|
1979
|
-
// Children inherit the gate via the parent chain.
|
|
1980
|
-
adminLayout = $page({
|
|
1981
|
-
path: "/admin",
|
|
1982
|
-
use: [$secure({ permissions: ["admin:ui"] })],
|
|
1983
|
-
lazy: () => import("./components/admin/AdminLayout.tsx"),
|
|
1984
|
-
});
|
|
1985
|
-
|
|
1986
|
-
adminUsers = $page({
|
|
1987
|
-
parent: this.adminLayout,
|
|
1988
|
-
path: "/users",
|
|
1989
|
-
head: { title: "Users" },
|
|
1990
|
-
lazy: () => import("./components/admin/Users.tsx"),
|
|
1991
|
-
});
|
|
1992
|
-
|
|
1993
|
-
adminSessions = $page({
|
|
1994
|
-
parent: this.adminLayout,
|
|
1995
|
-
path: "/sessions",
|
|
1996
|
-
head: { title: "Sessions" },
|
|
1997
|
-
lazy: () => import("./components/admin/Sessions.tsx"),
|
|
1998
|
-
});
|
|
1999
|
-
|
|
2000
|
-
notFound = $page({ path: "/*", component: NotFound });
|
|
2001
|
-
}
|
|
2002
|
-
`;
|
|
2003
1611
|
//#endregion
|
|
2004
1612
|
//#region ../../src/cli/core/templates/webHomeComponentTsx.ts
|
|
2005
1613
|
const webHomeComponentTsx = (options = {}) => {
|
|
@@ -2028,19 +1636,7 @@ export default Home;
|
|
|
2028
1636
|
//#endregion
|
|
2029
1637
|
//#region ../../src/cli/core/templates/webIndexTs.ts
|
|
2030
1638
|
const webIndexTs = (options = {}) => {
|
|
2031
|
-
const { appName = "app"
|
|
2032
|
-
if (saas) return `
|
|
2033
|
-
import { $module } from "alepha";
|
|
2034
|
-
import { AlephaReactAuth } from "alepha/react/auth";
|
|
2035
|
-
import { AlephaReactI18n } from "alepha/react/i18n";
|
|
2036
|
-
import { AppRouter } from "./AppRouter.ts";
|
|
2037
|
-
|
|
2038
|
-
export const WebModule = $module({
|
|
2039
|
-
name: "${appName}.web",
|
|
2040
|
-
services: [AppRouter],
|
|
2041
|
-
imports: [AlephaReactAuth, AlephaReactI18n],
|
|
2042
|
-
});
|
|
2043
|
-
`.trim();
|
|
1639
|
+
const { appName = "app" } = options;
|
|
2044
1640
|
return `
|
|
2045
1641
|
import { $module } from "alepha";
|
|
2046
1642
|
import { AppRouter } from "./AppRouter.ts";
|
|
@@ -2066,7 +1662,6 @@ var ProjectScaffolder = class {
|
|
|
2066
1662
|
log = $logger();
|
|
2067
1663
|
colors = $inject(ConsoleColorProvider);
|
|
2068
1664
|
fs = $inject(FileSystemProvider);
|
|
2069
|
-
shell = $inject(ShellProvider);
|
|
2070
1665
|
pm = $inject(PackageManagerUtils);
|
|
2071
1666
|
utils = $inject(AlephaCliUtils);
|
|
2072
1667
|
/**
|
|
@@ -2088,10 +1683,7 @@ var ProjectScaffolder = class {
|
|
|
2088
1683
|
const force = opts.force ?? false;
|
|
2089
1684
|
const checkWorkspace = opts.checkWorkspace ?? false;
|
|
2090
1685
|
if (opts.packageJson) tasks.push(this.pm.ensurePackageJson(root, typeof opts.packageJson === "boolean" ? {} : opts.packageJson).then(() => {}));
|
|
2091
|
-
if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root, {
|
|
2092
|
-
force,
|
|
2093
|
-
localOnly: opts.tsconfigJson === "local"
|
|
2094
|
-
}));
|
|
1686
|
+
if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root, { force }));
|
|
2095
1687
|
if (opts.biomeJson) tasks.push(this.ensureBiomeConfig(root, {
|
|
2096
1688
|
force,
|
|
2097
1689
|
checkWorkspace
|
|
@@ -2108,7 +1700,7 @@ var ProjectScaffolder = class {
|
|
|
2108
1700
|
await Promise.all(tasks);
|
|
2109
1701
|
}
|
|
2110
1702
|
async ensureTsConfig(root, opts = {}) {
|
|
2111
|
-
const exists =
|
|
1703
|
+
const exists = await this.existsInParents(root, "tsconfig.json");
|
|
2112
1704
|
if (!opts.force && exists) return;
|
|
2113
1705
|
await this.fs.writeFile(this.fs.join(root, "tsconfig.json"), tsconfigJson());
|
|
2114
1706
|
}
|
|
@@ -2185,33 +1777,9 @@ var ProjectScaffolder = class {
|
|
|
2185
1777
|
const appName = this.getAppName(root);
|
|
2186
1778
|
await this.fs.mkdir(this.fs.join(root, "src/api/controllers"), { recursive: true });
|
|
2187
1779
|
await this.fs.mkdir(this.fs.join(root, "src/api/schemas"), { recursive: true });
|
|
2188
|
-
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({
|
|
2189
|
-
appName,
|
|
2190
|
-
saas: opts.saas
|
|
2191
|
-
}), opts.force);
|
|
1780
|
+
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({ appName }), opts.force);
|
|
2192
1781
|
await this.ensureFile(root, "src/api/controllers/HelloController.ts", apiHelloControllerTs({ appName }), opts.force);
|
|
2193
1782
|
await this.ensureFile(root, "src/api/schemas/helloResponseSchema.ts", apiHelloResponseSchemaTs(), opts.force);
|
|
2194
|
-
if (opts.saas) {
|
|
2195
|
-
await this.fs.mkdir(this.fs.join(root, "src/api/providers"), { recursive: true });
|
|
2196
|
-
await this.ensureFile(root, "src/api/providers/RealmProvider.ts", saasRealmProviderTs(), opts.force);
|
|
2197
|
-
const adminEmail = await this.detectGitEmail() ?? "admin@alepha.dev";
|
|
2198
|
-
await this.ensureFile(root, ".env", `ADMIN_EMAILS=${adminEmail}\n`, opts.force);
|
|
2199
|
-
}
|
|
2200
|
-
}
|
|
2201
|
-
/**
|
|
2202
|
-
* Best-effort lookup for the developer's git email — seeded as
|
|
2203
|
-
* `ADMIN_EMAILS` in the SaaS project's `.env`. Returns undefined if git
|
|
2204
|
-
* isn't available or `user.email` isn't configured; the caller then falls
|
|
2205
|
-
* back to the neutral `admin@alepha.dev`.
|
|
2206
|
-
*/
|
|
2207
|
-
async detectGitEmail() {
|
|
2208
|
-
try {
|
|
2209
|
-
const email = (await this.shell.run("git config --get user.email", { capture: true }) ?? "").trim();
|
|
2210
|
-
if (!email || !email.includes("@")) return void 0;
|
|
2211
|
-
return email;
|
|
2212
|
-
} catch {
|
|
2213
|
-
return;
|
|
2214
|
-
}
|
|
2215
1783
|
}
|
|
2216
1784
|
/**
|
|
2217
1785
|
* Ensure web/React project structure exists.
|
|
@@ -2224,35 +1792,14 @@ var ProjectScaffolder = class {
|
|
|
2224
1792
|
async ensureWebProject(root, opts = {}) {
|
|
2225
1793
|
const appName = this.getAppName(root);
|
|
2226
1794
|
await this.fs.mkdir(this.fs.join(root, "src/web/components"), { recursive: true });
|
|
2227
|
-
if (opts.saas) {
|
|
2228
|
-
await this.fs.mkdir(this.fs.join(root, "src/web/components/auth"), { recursive: true });
|
|
2229
|
-
await this.fs.mkdir(this.fs.join(root, "src/web/components/admin"), { recursive: true });
|
|
2230
|
-
}
|
|
2231
1795
|
await this.fs.mkdir(this.fs.join(root, "public"), { recursive: true });
|
|
2232
1796
|
await this.ensureFile(root, "public/favicon.svg", logoSvg, opts.force);
|
|
2233
1797
|
await this.ensureFile(root, "src/main.css", mainCss({ tailwind: opts.tailwind }), opts.force);
|
|
2234
1798
|
if (opts.tailwind) await this.ensureFile(root, "vite.config.ts", viteConfigTs(), opts.force);
|
|
2235
|
-
|
|
2236
|
-
await this.ensureFile(root, "src/web/
|
|
2237
|
-
appName,
|
|
2238
|
-
saas: opts.saas
|
|
2239
|
-
}), opts.force);
|
|
2240
|
-
await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({
|
|
2241
|
-
api: opts.api,
|
|
2242
|
-
saas: opts.saas
|
|
2243
|
-
}), opts.force);
|
|
1799
|
+
await this.ensureFile(root, "src/web/index.ts", webIndexTs({ appName }), opts.force);
|
|
1800
|
+
await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({ api: opts.api }), opts.force);
|
|
2244
1801
|
await this.ensureFile(root, "src/web/components/Home.tsx", webHomeComponentTsx({ api: opts.api }), opts.force);
|
|
2245
1802
|
await this.ensureFile(root, "src/main.browser.ts", mainBrowserTs(), opts.force);
|
|
2246
|
-
if (opts.saas) {
|
|
2247
|
-
await this.ensureFile(root, "src/web/components/auth/AuthLayout.tsx", saasAuthLayoutTsx(), opts.force);
|
|
2248
|
-
await this.ensureFile(root, "src/web/components/auth/Login.tsx", saasAuthLoginTsx(), opts.force);
|
|
2249
|
-
await this.ensureFile(root, "src/web/components/auth/Register.tsx", saasAuthRegisterTsx(), opts.force);
|
|
2250
|
-
await this.ensureFile(root, "src/web/components/auth/ResetPassword.tsx", saasAuthResetPasswordTsx(), opts.force);
|
|
2251
|
-
await this.ensureFile(root, "src/web/components/auth/VerifyEmail.tsx", saasAuthVerifyEmailTsx(), opts.force);
|
|
2252
|
-
await this.ensureFile(root, "src/web/components/admin/AdminLayout.tsx", saasAdminLayoutTsx(), opts.force);
|
|
2253
|
-
await this.ensureFile(root, "src/web/components/admin/Users.tsx", saasAdminUsersTsx(), opts.force);
|
|
2254
|
-
await this.ensureFile(root, "src/web/components/admin/Sessions.tsx", saasAdminSessionsTsx(), opts.force);
|
|
2255
|
-
}
|
|
2256
1803
|
}
|
|
2257
1804
|
/**
|
|
2258
1805
|
* Ensure test directory exists with a dummy test file + a self-contained
|
|
@@ -2275,21 +1822,16 @@ var ProjectScaffolder = class {
|
|
|
2275
1822
|
* Full project init — scaffolds files, installs deps, sets up PM and git.
|
|
2276
1823
|
*/
|
|
2277
1824
|
async init({ run, root, flags, args }) {
|
|
1825
|
+
if (!args) {
|
|
1826
|
+
if (!await this.fs.exists(this.fs.join(root, "package.json"))) args = "my-app";
|
|
1827
|
+
}
|
|
2278
1828
|
if (args) {
|
|
2279
1829
|
root = this.fs.join(root, args);
|
|
2280
1830
|
await this.fs.mkdir(root, { force: true });
|
|
2281
1831
|
}
|
|
2282
|
-
const shadcnPreset = typeof flags.saas === "string" && flags.saas || typeof flags.shadcn === "string" && flags.shadcn || "b0";
|
|
2283
|
-
const f = flags;
|
|
2284
|
-
f.shadcn = !!flags.shadcn;
|
|
2285
|
-
f.saas = !!flags.saas;
|
|
2286
|
-
if (f.saas) {
|
|
2287
|
-
f.shadcn = true;
|
|
2288
|
-
f.api = true;
|
|
2289
|
-
}
|
|
2290
|
-
if (f.shadcn) f.tailwind = true;
|
|
2291
1832
|
if (flags.tailwind) flags.react = true;
|
|
2292
|
-
|
|
1833
|
+
const f = flags;
|
|
1834
|
+
if ((flags.api || flags.react || flags.tailwind) && !flags.force) {
|
|
2293
1835
|
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.`);
|
|
2294
1836
|
}
|
|
2295
1837
|
const workspace = await this.pm.getWorkspaceContext(root);
|
|
@@ -2305,7 +1847,7 @@ var ProjectScaffolder = class {
|
|
|
2305
1847
|
...f,
|
|
2306
1848
|
isPackage: workspace.isPackage
|
|
2307
1849
|
},
|
|
2308
|
-
tsconfigJson:
|
|
1850
|
+
tsconfigJson: !workspace.config.tsconfigJson,
|
|
2309
1851
|
biomeJson: true,
|
|
2310
1852
|
editorconfig: !workspace.config.editorconfig,
|
|
2311
1853
|
agentMd: writeAgentMd,
|
|
@@ -2317,15 +1859,10 @@ var ProjectScaffolder = class {
|
|
|
2317
1859
|
react: !!flags.react && !isExpo,
|
|
2318
1860
|
force
|
|
2319
1861
|
});
|
|
2320
|
-
if (flags.api) await this.ensureApiProject(root, {
|
|
2321
|
-
saas: !!flags.saas,
|
|
2322
|
-
force
|
|
2323
|
-
});
|
|
1862
|
+
if (flags.api) await this.ensureApiProject(root, { force });
|
|
2324
1863
|
if (flags.react && !isExpo) await this.ensureWebProject(root, {
|
|
2325
1864
|
api: !!flags.api,
|
|
2326
1865
|
tailwind: !!flags.tailwind,
|
|
2327
|
-
shadcn: !!flags.shadcn,
|
|
2328
|
-
saas: !!flags.saas,
|
|
2329
1866
|
force
|
|
2330
1867
|
});
|
|
2331
1868
|
}
|
|
@@ -2343,18 +1880,6 @@ var ProjectScaffolder = class {
|
|
|
2343
1880
|
root: installRoot
|
|
2344
1881
|
});
|
|
2345
1882
|
await this.ensureTestDir(root);
|
|
2346
|
-
const exec = pmExecPrefix(pmName);
|
|
2347
|
-
if (flags.shadcn) {
|
|
2348
|
-
await run(`${exec} shadcn init --no-monorepo --base radix -t vite --yes --force --reinstall --preset ${escapeShellArg(shadcnPreset)}`, {
|
|
2349
|
-
alias: `running shadcn init (preset ${shadcnPreset})`,
|
|
2350
|
-
root
|
|
2351
|
-
});
|
|
2352
|
-
await this.fs.writeFile(this.fs.join(root, "components.json"), componentsJsonTs());
|
|
2353
|
-
}
|
|
2354
|
-
if (flags.saas) await run(`${exec} shadcn add @alepha/saas --yes --overwrite`, {
|
|
2355
|
-
alias: "adding alepha saas registry bundle",
|
|
2356
|
-
root
|
|
2357
|
-
});
|
|
2358
1883
|
try {
|
|
2359
1884
|
await run(`${pmName} run lint`, {
|
|
2360
1885
|
alias: "running linter",
|
|
@@ -2401,30 +1926,6 @@ var ProjectScaffolder = class {
|
|
|
2401
1926
|
}
|
|
2402
1927
|
}
|
|
2403
1928
|
};
|
|
2404
|
-
/**
|
|
2405
|
-
* Map a package manager name to the command that runs a project-local binary.
|
|
2406
|
-
*
|
|
2407
|
-
* - npm: `npx`
|
|
2408
|
-
* - yarn: `yarn` (yarn auto-resolves binary names; `yarn shadcn ...` works)
|
|
2409
|
-
* - pnpm: `pnpm exec`
|
|
2410
|
-
* - bun: `bunx`
|
|
2411
|
-
*
|
|
2412
|
-
* Used to invoke `shadcn init` / `shadcn add` regardless of the user's PM —
|
|
2413
|
-
* `npm shadcn ...` is invalid (it tries to run a script named `shadcn`).
|
|
2414
|
-
*/
|
|
2415
|
-
/** Quote a value so it survives shell parsing. */
|
|
2416
|
-
const escapeShellArg = (value) => {
|
|
2417
|
-
if (/^[A-Za-z0-9_./@:-]+$/.test(value)) return value;
|
|
2418
|
-
return `'${value.replace(/'/g, "'\\''")}'`;
|
|
2419
|
-
};
|
|
2420
|
-
const pmExecPrefix = (pmName) => {
|
|
2421
|
-
switch (pmName) {
|
|
2422
|
-
case "npm": return "npx";
|
|
2423
|
-
case "pnpm": return "pnpm exec";
|
|
2424
|
-
case "bun": return "bunx";
|
|
2425
|
-
default: return "yarn";
|
|
2426
|
-
}
|
|
2427
|
-
};
|
|
2428
1929
|
//#endregion
|
|
2429
1930
|
//#region ../../src/cli/core/tasks/BuildTask.ts
|
|
2430
1931
|
/**
|
|
@@ -2563,6 +2064,7 @@ var BuildClientTask = class extends BuildTask {
|
|
|
2563
2064
|
};
|
|
2564
2065
|
//#endregion
|
|
2565
2066
|
//#region ../../src/cli/core/tasks/BuildCloudflareTask.ts
|
|
2067
|
+
const CLOUDFLARE_EMAIL_PROVIDER_NAME = "CloudflareEmailProvider";
|
|
2566
2068
|
/**
|
|
2567
2069
|
* Generate Cloudflare Workers deployment configuration.
|
|
2568
2070
|
*
|
|
@@ -2586,7 +2088,7 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2586
2088
|
}
|
|
2587
2089
|
async generateCloudflare(ctx, distDir) {
|
|
2588
2090
|
const root = ctx.root;
|
|
2589
|
-
const name = basename(root);
|
|
2091
|
+
const name = basename(root).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
|
|
2590
2092
|
const hasAssets = await this.fs.exists(this.fs.join(root, distDir, "public"));
|
|
2591
2093
|
const wrangler = {
|
|
2592
2094
|
name,
|
|
@@ -2617,8 +2119,77 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2617
2119
|
this.enhanceEmail(ctx, wrangler);
|
|
2618
2120
|
const containers = this.enhanceContainers(ctx, wrangler);
|
|
2619
2121
|
await this.fs.writeFile(this.fs.join(root, distDir, "wrangler.jsonc"), JSON.stringify(wrangler, null, 2));
|
|
2122
|
+
if (!ctx.manifest) await this.writeManifest(ctx, root, distDir, name, containers);
|
|
2620
2123
|
await this.writeWorkerEntryPoint(root, distDir, containers);
|
|
2621
2124
|
}
|
|
2125
|
+
/**
|
|
2126
|
+
* Write `dist/manifest.json` — a build-time snapshot of everything
|
|
2127
|
+
* downstream tooling needs to know about the app without re-booting
|
|
2128
|
+
* it. Used by `alepha platform up --prebuilt` (and Alepha Rocket) so
|
|
2129
|
+
* the deploy path can skip the Vite-based introspection step and the
|
|
2130
|
+
* workspace's runtime npm install.
|
|
2131
|
+
*/
|
|
2132
|
+
async writeManifest(ctx, root, distDir, name, containers) {
|
|
2133
|
+
let hasDatabase = false;
|
|
2134
|
+
let hasBucket = false;
|
|
2135
|
+
let hasKV = false;
|
|
2136
|
+
let hasQueue = false;
|
|
2137
|
+
let crons = [];
|
|
2138
|
+
try {
|
|
2139
|
+
hasDatabase = (ctx.alepha.inject("RepositoryProvider").getRepositories?.() ?? []).length > 0;
|
|
2140
|
+
} catch {}
|
|
2141
|
+
try {
|
|
2142
|
+
hasBucket = ctx.alepha.primitives("$bucket").length > 0;
|
|
2143
|
+
} catch {}
|
|
2144
|
+
try {
|
|
2145
|
+
hasKV = ctx.alepha.primitives("cache").filter((p) => p.options?.provider == null).length > 0;
|
|
2146
|
+
} catch {}
|
|
2147
|
+
try {
|
|
2148
|
+
hasQueue = ctx.alepha.primitives("$queue").length > 0;
|
|
2149
|
+
} catch {}
|
|
2150
|
+
try {
|
|
2151
|
+
const cronProvider = ctx.alepha.inject("CronProvider");
|
|
2152
|
+
crons = [...new Set((cronProvider.getCronJobs?.() ?? []).map((c) => c.expression))];
|
|
2153
|
+
} catch {}
|
|
2154
|
+
const defaultEnv = ctx.platformOptions?.default ?? "production";
|
|
2155
|
+
const environments = ctx.platformOptions?.environments ?? {};
|
|
2156
|
+
let env = [];
|
|
2157
|
+
try {
|
|
2158
|
+
env = Object.keys(ctx.alepha.dump().env).sort();
|
|
2159
|
+
} catch {}
|
|
2160
|
+
let email;
|
|
2161
|
+
try {
|
|
2162
|
+
ctx.alepha.inject(CLOUDFLARE_EMAIL_PROVIDER_NAME);
|
|
2163
|
+
email = { binding: SEND_EMAIL_DEFAULT_BINDING };
|
|
2164
|
+
} catch {}
|
|
2165
|
+
const manifest = {
|
|
2166
|
+
version: 1,
|
|
2167
|
+
project: name,
|
|
2168
|
+
defaultEnv,
|
|
2169
|
+
tenancy: ctx.platformOptions?.tenancy,
|
|
2170
|
+
environments,
|
|
2171
|
+
resources: {
|
|
2172
|
+
hasDatabase,
|
|
2173
|
+
hasBucket,
|
|
2174
|
+
hasKV,
|
|
2175
|
+
hasQueue,
|
|
2176
|
+
hasCron: crons.length > 0
|
|
2177
|
+
},
|
|
2178
|
+
crons,
|
|
2179
|
+
containers: containers.map((c) => ({
|
|
2180
|
+
name: c.name,
|
|
2181
|
+
className: c.className,
|
|
2182
|
+
image: c.image,
|
|
2183
|
+
port: c.port,
|
|
2184
|
+
sleepAfter: c.sleepAfter,
|
|
2185
|
+
instanceType: c.instanceType,
|
|
2186
|
+
maxInstances: c.maxInstances
|
|
2187
|
+
})),
|
|
2188
|
+
email,
|
|
2189
|
+
env
|
|
2190
|
+
};
|
|
2191
|
+
await this.fs.writeFile(this.fs.join(root, distDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
2192
|
+
}
|
|
2622
2193
|
enhanceDomain(wrangler) {
|
|
2623
2194
|
const domain = process.env.CLOUDFLARE_DOMAIN;
|
|
2624
2195
|
if (!domain) return;
|
|
@@ -2637,16 +2208,20 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2637
2208
|
}];
|
|
2638
2209
|
}
|
|
2639
2210
|
enhanceCron(ctx, wrangler) {
|
|
2640
|
-
|
|
2211
|
+
const cronExpressions = ctx.manifest ? ctx.manifest.crons : this.discoverCrons(ctx);
|
|
2212
|
+
if (cronExpressions.length === 0) return;
|
|
2213
|
+
wrangler.triggers ??= {};
|
|
2214
|
+
wrangler.triggers.crons = cronExpressions;
|
|
2215
|
+
}
|
|
2216
|
+
discoverCrons(ctx) {
|
|
2217
|
+
if (ctx.alepha.primitives("scheduler").length === 0) return [];
|
|
2641
2218
|
let cronProvider;
|
|
2642
2219
|
try {
|
|
2643
2220
|
cronProvider = ctx.alepha.inject("CronProvider");
|
|
2644
2221
|
} catch {}
|
|
2645
2222
|
const crons = cronProvider?.getCronJobs();
|
|
2646
|
-
if (!crons || crons.length === 0) return;
|
|
2647
|
-
|
|
2648
|
-
wrangler.triggers ??= {};
|
|
2649
|
-
wrangler.triggers.crons = cronExpressions;
|
|
2223
|
+
if (!crons || crons.length === 0) return [];
|
|
2224
|
+
return [...new Set(crons.map((c) => c.expression))];
|
|
2650
2225
|
}
|
|
2651
2226
|
enhanceDatabase(wrangler) {
|
|
2652
2227
|
if (process.env.HYPERDRIVE_ID) {
|
|
@@ -2720,19 +2295,16 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2720
2295
|
wrangler.queues.consumers.push({ queue: queueName });
|
|
2721
2296
|
}
|
|
2722
2297
|
enhanceEmail(ctx, wrangler) {
|
|
2723
|
-
let
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
}
|
|
2729
|
-
if (!
|
|
2298
|
+
let binding;
|
|
2299
|
+
if (ctx.manifest) binding = ctx.manifest.email?.binding;
|
|
2300
|
+
else if (ctx.alepha) try {
|
|
2301
|
+
ctx.alepha.inject(CLOUDFLARE_EMAIL_PROVIDER_NAME);
|
|
2302
|
+
binding = SEND_EMAIL_DEFAULT_BINDING;
|
|
2303
|
+
} catch {}
|
|
2304
|
+
if (!binding) return;
|
|
2730
2305
|
wrangler.send_email = wrangler.send_email || [];
|
|
2731
|
-
if (wrangler.send_email.some((b) => b.name ===
|
|
2732
|
-
|
|
2733
|
-
const destination = process.env.EMAIL_FROM;
|
|
2734
|
-
if (destination) entry.destination_address = destination;
|
|
2735
|
-
wrangler.send_email.push(entry);
|
|
2306
|
+
if (wrangler.send_email.some((b) => b.name === binding)) return;
|
|
2307
|
+
wrangler.send_email.push({ name: binding });
|
|
2736
2308
|
}
|
|
2737
2309
|
/**
|
|
2738
2310
|
* Discover `$container` primitives and emit the matching Cloudflare
|
|
@@ -2744,19 +2316,45 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2744
2316
|
* `writeWorkerEntryPoint` can emit `export class <NAME> extends
|
|
2745
2317
|
* Container` declarations referencing them.
|
|
2746
2318
|
*/
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
if (primitives.length === 0) return [];
|
|
2750
|
-
const descriptors = primitives.map((p) => ({
|
|
2319
|
+
discoverContainers(ctx) {
|
|
2320
|
+
return ctx.alepha.primitives("container").map((p) => ({
|
|
2751
2321
|
name: p.name.toUpperCase(),
|
|
2752
2322
|
className: p.name.split(/[^a-zA-Z0-9]/).filter(Boolean).map((s) => s[0].toUpperCase() + s.slice(1)).join(""),
|
|
2753
2323
|
image: p.options.image,
|
|
2754
2324
|
port: p.options.port ?? 3e3,
|
|
2755
2325
|
sleepAfter: typeof p.options.sleepAfter === "string" ? p.options.sleepAfter : "15m",
|
|
2756
|
-
instanceType: p.options.instanceType
|
|
2326
|
+
instanceType: p.options.instanceType === "dev" ? "lite" : p.options.instanceType ?? "lite",
|
|
2757
2327
|
maxInstances: p.options.maxInstances ?? 5,
|
|
2758
2328
|
envVars: p.options.envVars
|
|
2759
2329
|
}));
|
|
2330
|
+
}
|
|
2331
|
+
/**
|
|
2332
|
+
* Expand a short image ref (e.g. `alepha-rocket:0.1.0`) into the
|
|
2333
|
+
* fully-qualified `registry.cloudflare.com/<account>/<image>:<tag>`
|
|
2334
|
+
* URL that wrangler validates at deploy time.
|
|
2335
|
+
*
|
|
2336
|
+
* Cloudflare Containers only pulls from `registry.cloudflare.com`;
|
|
2337
|
+
* wrangler accepts either a Dockerfile path or a fully-qualified
|
|
2338
|
+
* registry URL in the `image` field — not a bare DockerHub-style
|
|
2339
|
+
* name. We let `$container({ image })` callers write the short
|
|
2340
|
+
* form (it matches what `wrangler containers push <local>` accepts
|
|
2341
|
+
* + matches the local docker tag) and rewrite to the CF registry
|
|
2342
|
+
* URL here.
|
|
2343
|
+
*
|
|
2344
|
+
* Pass-through cases:
|
|
2345
|
+
* - already a full URL: starts with `registry.cloudflare.com/`
|
|
2346
|
+
* or contains a scheme/`://`
|
|
2347
|
+
* - looks like a Dockerfile path: starts with `./` or `/`
|
|
2348
|
+
*/
|
|
2349
|
+
resolveContainerImage(image) {
|
|
2350
|
+
if (image.startsWith("./") || image.startsWith("/") || image.startsWith("registry.cloudflare.com/") || image.includes("://")) return image;
|
|
2351
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
2352
|
+
if (!accountId) return image;
|
|
2353
|
+
return `registry.cloudflare.com/${accountId}/${image}`;
|
|
2354
|
+
}
|
|
2355
|
+
enhanceContainers(ctx, wrangler) {
|
|
2356
|
+
const descriptors = ctx.manifest ? ctx.manifest.containers : this.discoverContainers(ctx);
|
|
2357
|
+
if (descriptors.length === 0) return [];
|
|
2760
2358
|
wrangler.containers = wrangler.containers || [];
|
|
2761
2359
|
wrangler.durable_objects = wrangler.durable_objects || {};
|
|
2762
2360
|
wrangler.durable_objects.bindings = wrangler.durable_objects.bindings || [];
|
|
@@ -2765,7 +2363,7 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2765
2363
|
for (const d of descriptors) {
|
|
2766
2364
|
wrangler.containers.push({
|
|
2767
2365
|
class_name: d.className,
|
|
2768
|
-
image: d.image,
|
|
2366
|
+
image: this.resolveContainerImage(d.image),
|
|
2769
2367
|
instance_type: d.instanceType,
|
|
2770
2368
|
max_instances: d.maxInstances
|
|
2771
2369
|
});
|
|
@@ -2784,9 +2382,8 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2784
2382
|
async writeWorkerEntryPoint(root, distDir, containers = []) {
|
|
2785
2383
|
const containerDeclarations = containers.map((c) => {
|
|
2786
2384
|
const envVars = c.envVars ? ` envVars = ${JSON.stringify(c.envVars)};\n` : "";
|
|
2787
|
-
return `export class ${c.className} extends
|
|
2385
|
+
return `export class ${c.className} extends globalThis.__alepha_CloudflareContainer {\n defaultPort = ${c.port};\n sleepAfter = "${c.sleepAfter}";\n${envVars}}`;
|
|
2788
2386
|
}).join("\n\n");
|
|
2789
|
-
const containerImport = containers.length > 0 ? `import { Container } from "@cloudflare/containers";\n\n${containerDeclarations}\n\n` : "";
|
|
2790
2387
|
const workerCode = `
|
|
2791
2388
|
import "./index.js";
|
|
2792
2389
|
|
|
@@ -2801,11 +2398,19 @@ const setWaitUntil = (executionCtx) => {
|
|
|
2801
2398
|
}
|
|
2802
2399
|
};
|
|
2803
2400
|
|
|
2401
|
+
// Bind the per-invocation Worker \`env\`: keep the full binding (D1, R2, KV, …)
|
|
2402
|
+
// in the store for providers, and lift its string values (secrets/vars like
|
|
2403
|
+
// PUBLIC_URL) into \`alepha.env\` so \`$env\` resolves them at runtime.
|
|
2404
|
+
const bindEnv = (env) => {
|
|
2405
|
+
__alepha.set("cloudflare.env", env);
|
|
2406
|
+
__alepha.loadEnv(env);
|
|
2407
|
+
};
|
|
2408
|
+
|
|
2804
2409
|
export default {
|
|
2805
2410
|
fetch: async (request, env, executionCtx) => {
|
|
2806
2411
|
const ctx = { req: request, res: undefined };
|
|
2807
2412
|
|
|
2808
|
-
|
|
2413
|
+
bindEnv(env);
|
|
2809
2414
|
setWaitUntil(executionCtx);
|
|
2810
2415
|
|
|
2811
2416
|
try {
|
|
@@ -2821,7 +2426,7 @@ export default {
|
|
|
2821
2426
|
},
|
|
2822
2427
|
|
|
2823
2428
|
scheduled: async (event, env, executionCtx) => {
|
|
2824
|
-
|
|
2429
|
+
bindEnv(env);
|
|
2825
2430
|
setWaitUntil(executionCtx);
|
|
2826
2431
|
|
|
2827
2432
|
try {
|
|
@@ -2838,7 +2443,7 @@ export default {
|
|
|
2838
2443
|
},
|
|
2839
2444
|
|
|
2840
2445
|
queue: async (batch, env, executionCtx) => {
|
|
2841
|
-
|
|
2446
|
+
bindEnv(env);
|
|
2842
2447
|
setWaitUntil(executionCtx);
|
|
2843
2448
|
|
|
2844
2449
|
try {
|
|
@@ -2859,7 +2464,8 @@ export default {
|
|
|
2859
2464
|
},
|
|
2860
2465
|
};
|
|
2861
2466
|
`.trim();
|
|
2862
|
-
|
|
2467
|
+
const containerBlock = containers.length > 0 ? `${containerDeclarations}\n\n` : "";
|
|
2468
|
+
await this.fs.writeFile(this.fs.join(root, distDir, "main.cloudflare.js"), `${this.warningComment}\n${containerBlock}${workerCode}`.trim());
|
|
2863
2469
|
}
|
|
2864
2470
|
};
|
|
2865
2471
|
//#endregion
|
|
@@ -2979,6 +2585,7 @@ var BuildDockerTask = class extends BuildTask {
|
|
|
2979
2585
|
name: "generate deploy config (docker)",
|
|
2980
2586
|
handler: async () => {
|
|
2981
2587
|
const migrationsCopied = await this.copyMigrations(ctx.root, distDir);
|
|
2588
|
+
const hasDeps = await this.hasRuntimeDeps(ctx.root, distDir);
|
|
2982
2589
|
await this.writeDockerfile(ctx.root, distDir, {
|
|
2983
2590
|
compile,
|
|
2984
2591
|
standard: {
|
|
@@ -2986,6 +2593,7 @@ var BuildDockerTask = class extends BuildTask {
|
|
|
2986
2593
|
command: dockerCommand
|
|
2987
2594
|
},
|
|
2988
2595
|
hasMigrations: migrationsCopied,
|
|
2596
|
+
hasDeps,
|
|
2989
2597
|
install: ctx.options.docker?.install ?? []
|
|
2990
2598
|
});
|
|
2991
2599
|
}
|
|
@@ -3071,6 +2679,21 @@ var BuildDockerTask = class extends BuildTask {
|
|
|
3071
2679
|
}
|
|
3072
2680
|
return false;
|
|
3073
2681
|
}
|
|
2682
|
+
/**
|
|
2683
|
+
* Whether the produced `dist/package.json` declares any runtime
|
|
2684
|
+
* dependencies. Alepha apps normally bundle everything into the
|
|
2685
|
+
* server entry via Vite, leaving `dependencies: {}` — in which case
|
|
2686
|
+
* the generated Dockerfile's `RUN npm install` is wasted work
|
|
2687
|
+
* (and emits deprecation noise). Skip the line when empty.
|
|
2688
|
+
*/
|
|
2689
|
+
async hasRuntimeDeps(root, distDir) {
|
|
2690
|
+
try {
|
|
2691
|
+
const pkg = await this.fs.readJsonFile(this.fs.join(root, distDir, "package.json"));
|
|
2692
|
+
return Object.keys(pkg.dependencies ?? {}).length > 0;
|
|
2693
|
+
} catch {
|
|
2694
|
+
return false;
|
|
2695
|
+
}
|
|
2696
|
+
}
|
|
3074
2697
|
async writeDockerfile(root, distDir, opts) {
|
|
3075
2698
|
const header = "# This file was automatically generated. DO NOT MODIFY.\n# Changes to this file will be lost when the code is regenerated.\n";
|
|
3076
2699
|
const migrationsLine = opts.hasMigrations ? "COPY migrations ./migrations\n" : "";
|
|
@@ -3086,14 +2709,12 @@ ENTRYPOINT ["/app/app"]
|
|
|
3086
2709
|
`;
|
|
3087
2710
|
else {
|
|
3088
2711
|
const { image, command } = opts.standard;
|
|
3089
|
-
const installLine = opts.install.length ? `RUN npm install --no-save --no-fund --no-audit ${opts.install.join(" ")}\n` : "";
|
|
3090
2712
|
dockerfile = `${header}FROM ${image}
|
|
3091
2713
|
WORKDIR /app
|
|
3092
2714
|
|
|
3093
2715
|
COPY . .
|
|
3094
2716
|
|
|
3095
|
-
RUN ${command === "bun" ? "bun" : "npm"} install
|
|
3096
|
-
${installLine}
|
|
2717
|
+
${opts.hasDeps ? `RUN ${command === "bun" ? "bun" : "npm"} install\n` : ""}${opts.install.length ? `RUN npm install --no-save --no-fund --no-audit ${opts.install.join(" ")}\n` : ""}
|
|
3097
2718
|
ENV SERVER_HOST=0.0.0.0
|
|
3098
2719
|
|
|
3099
2720
|
CMD ["${command}", "index.js"]
|
|
@@ -3137,11 +2758,18 @@ CMD ["${command}", "index.js"]
|
|
|
3137
2758
|
//#endregion
|
|
3138
2759
|
//#region ../../src/cli/core/tasks/BuildPrerenderTask.ts
|
|
3139
2760
|
/**
|
|
3140
|
-
* Pre-render static pages defined in the Alepha application.
|
|
2761
|
+
* Pre-render static pages and routes defined in the Alepha application.
|
|
3141
2762
|
*
|
|
3142
|
-
*
|
|
3143
|
-
*
|
|
3144
|
-
* routes via `static.entries`
|
|
2763
|
+
* Two passes, both writing into `dist/public`:
|
|
2764
|
+
* - **pages** — every `$page` with `static: true` is rendered to an HTML file
|
|
2765
|
+
* (supports parameterized routes via `static.entries`).
|
|
2766
|
+
* - **routes** — every `static` route primitive (a `$route({ static: true })`
|
|
2767
|
+
* or a `$sitemap`) is invoked in-process and its body written verbatim to
|
|
2768
|
+
* `{path}` (e.g. `sitemap.xml`, `robots.txt`).
|
|
2769
|
+
*
|
|
2770
|
+
* Both passes read the primitive registry and call a method on the already
|
|
2771
|
+
* created primitive instances — no provider is re-injected, so this works in
|
|
2772
|
+
* the build's configured-but-not-started container.
|
|
3145
2773
|
*/
|
|
3146
2774
|
var BuildPrerenderTask = class extends BuildTask {
|
|
3147
2775
|
fs = $inject(FileSystemProvider);
|
|
@@ -3149,15 +2777,17 @@ var BuildPrerenderTask = class extends BuildTask {
|
|
|
3149
2777
|
if (ctx.flags?.prebuilt) return;
|
|
3150
2778
|
if (!ctx.hasClient) return;
|
|
3151
2779
|
const pages = this.getStaticPages(ctx);
|
|
3152
|
-
|
|
2780
|
+
const routes = this.getStaticRoutePrimitives(ctx);
|
|
2781
|
+
if (pages.length === 0 && routes.length === 0) return;
|
|
3153
2782
|
const distDir = ctx.options.output?.dist ?? "dist";
|
|
3154
2783
|
const publicDir = ctx.options.output?.public ?? "public";
|
|
3155
2784
|
const dist = this.fs.join(ctx.root, distDir, publicDir);
|
|
3156
2785
|
await ctx.run({
|
|
3157
|
-
name: "pre-render
|
|
2786
|
+
name: "pre-render",
|
|
3158
2787
|
handler: async () => {
|
|
3159
2788
|
if (!ctx.alepha.isConfigured()) await ctx.alepha.events.emit("configure", ctx.alepha);
|
|
3160
|
-
await this.prerenderFromAlepha(pages, dist);
|
|
2789
|
+
if (pages.length > 0) await this.prerenderFromAlepha(pages, dist);
|
|
2790
|
+
if (routes.length > 0) await this.prerenderRoutes(routes, dist);
|
|
3161
2791
|
}
|
|
3162
2792
|
});
|
|
3163
2793
|
}
|
|
@@ -3167,6 +2797,15 @@ var BuildPrerenderTask = class extends BuildTask {
|
|
|
3167
2797
|
return options.static && !options.children;
|
|
3168
2798
|
});
|
|
3169
2799
|
}
|
|
2800
|
+
/**
|
|
2801
|
+
* Static route primitives to snapshot: `$route({ static: true })` and every
|
|
2802
|
+
* `$sitemap`. Both expose an async `prerender(): { path, body }`.
|
|
2803
|
+
*/
|
|
2804
|
+
getStaticRoutePrimitives(ctx) {
|
|
2805
|
+
const routes = ctx.alepha.primitives("route").filter((route) => route.options?.static === true);
|
|
2806
|
+
const sitemaps = ctx.alepha.primitives("sitemap");
|
|
2807
|
+
return [...routes, ...sitemaps];
|
|
2808
|
+
}
|
|
3170
2809
|
async prerenderFromAlepha(pages, dist) {
|
|
3171
2810
|
let count = 0;
|
|
3172
2811
|
for (const page of pages) {
|
|
@@ -3184,6 +2823,14 @@ var BuildPrerenderTask = class extends BuildTask {
|
|
|
3184
2823
|
}
|
|
3185
2824
|
return count;
|
|
3186
2825
|
}
|
|
2826
|
+
async prerenderRoutes(primitives, dist) {
|
|
2827
|
+
for (const primitive of primitives) {
|
|
2828
|
+
const { path, body } = await primitive.prerender();
|
|
2829
|
+
const filepath = this.fs.join(dist, path);
|
|
2830
|
+
await this.fs.mkdir(dirname(filepath));
|
|
2831
|
+
await this.fs.writeFile(filepath, body);
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
3187
2834
|
async renderFile(page, options, dist) {
|
|
3188
2835
|
const { html, state } = await page.render({
|
|
3189
2836
|
html: true,
|
|
@@ -3457,76 +3104,6 @@ var BuildServerTask = class extends BuildTask {
|
|
|
3457
3104
|
}
|
|
3458
3105
|
};
|
|
3459
3106
|
//#endregion
|
|
3460
|
-
//#region ../../src/cli/core/tasks/BuildSitemapTask.ts
|
|
3461
|
-
/**
|
|
3462
|
-
* Generate sitemap.xml from Alepha page primitives.
|
|
3463
|
-
*
|
|
3464
|
-
* Queries all page primitives and generates a sitemap.xml
|
|
3465
|
-
* containing URLs for all accessible pages.
|
|
3466
|
-
*/
|
|
3467
|
-
var BuildSitemapTask = class extends BuildTask {
|
|
3468
|
-
fs = $inject(FileSystemProvider);
|
|
3469
|
-
async run(ctx) {
|
|
3470
|
-
const hostname = ctx.options.sitemap?.hostname;
|
|
3471
|
-
if (!hostname) return;
|
|
3472
|
-
const pages = this.getSitemapPages(ctx);
|
|
3473
|
-
if (pages.length === 0) return;
|
|
3474
|
-
const distDir = ctx.options.output?.dist ?? "dist";
|
|
3475
|
-
const publicDir = ctx.options.output?.public ?? "public";
|
|
3476
|
-
const output = this.fs.join(ctx.root, distDir, publicDir, "sitemap.xml");
|
|
3477
|
-
await ctx.run({
|
|
3478
|
-
name: "generate sitemap",
|
|
3479
|
-
handler: async () => {
|
|
3480
|
-
const xml = this.generateSitemapFromPages(pages, hostname);
|
|
3481
|
-
await this.fs.writeFile(output, xml);
|
|
3482
|
-
}
|
|
3483
|
-
});
|
|
3484
|
-
}
|
|
3485
|
-
getSitemapPages(ctx) {
|
|
3486
|
-
return ctx.alepha.primitives("page").filter((page) => {
|
|
3487
|
-
const options = page.options;
|
|
3488
|
-
const path = options.path ?? "";
|
|
3489
|
-
if (options.children) return false;
|
|
3490
|
-
if (path.includes("*")) return false;
|
|
3491
|
-
if (path === "/404") return false;
|
|
3492
|
-
if (!options.schema?.params) return true;
|
|
3493
|
-
if (options.static && typeof options.static === "object" && options.static.entries) return true;
|
|
3494
|
-
return false;
|
|
3495
|
-
});
|
|
3496
|
-
}
|
|
3497
|
-
generateSitemapFromPages(pages, baseUrl) {
|
|
3498
|
-
const urls = [];
|
|
3499
|
-
const normalizedBaseUrl = baseUrl.replace(/\/$/, "");
|
|
3500
|
-
for (const page of pages) {
|
|
3501
|
-
const options = page.options;
|
|
3502
|
-
if (!options.schema?.params) {
|
|
3503
|
-
const path = options.path || "";
|
|
3504
|
-
const url = `${normalizedBaseUrl}${path === "" ? "/" : path}`;
|
|
3505
|
-
urls.push(url);
|
|
3506
|
-
} else if (options.static && typeof options.static === "object" && options.static.entries) for (const entry of options.static.entries) {
|
|
3507
|
-
const url = `${normalizedBaseUrl}${this.buildPathFromParams(options.path || "", entry.params || {})}`;
|
|
3508
|
-
urls.push(url);
|
|
3509
|
-
}
|
|
3510
|
-
}
|
|
3511
|
-
return this.buildSitemapXml(urls);
|
|
3512
|
-
}
|
|
3513
|
-
buildPathFromParams(pathPattern, params) {
|
|
3514
|
-
let path = pathPattern;
|
|
3515
|
-
for (const [key, value] of Object.entries(params)) path = path.replace(`:${key}`, String(value));
|
|
3516
|
-
return path || "/";
|
|
3517
|
-
}
|
|
3518
|
-
buildSitemapXml(urls) {
|
|
3519
|
-
const lastMod = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
|
|
3520
|
-
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
3521
|
-
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
|
3522
|
-
${urls.map((url) => ` <url>\n <loc>${this.escapeXml(url)}</loc>\n <lastmod>${lastMod}</lastmod>\n </url>`).join("\n")}
|
|
3523
|
-
</urlset>`;
|
|
3524
|
-
}
|
|
3525
|
-
escapeXml(str) {
|
|
3526
|
-
return str.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3527
|
-
}
|
|
3528
|
-
};
|
|
3529
|
-
//#endregion
|
|
3530
3107
|
//#region ../../src/cli/core/tasks/BuildStaticTask.ts
|
|
3531
3108
|
/**
|
|
3532
3109
|
* Generate a static site output.
|
|
@@ -3791,7 +3368,6 @@ var BuildCommand = class {
|
|
|
3791
3368
|
$inject(BuildClientTask),
|
|
3792
3369
|
$inject(BuildServerTask),
|
|
3793
3370
|
$inject(BuildAssetsTask),
|
|
3794
|
-
$inject(BuildSitemapTask),
|
|
3795
3371
|
$inject(BuildPwaTask),
|
|
3796
3372
|
$inject(BuildPrerenderTask),
|
|
3797
3373
|
$inject(BuildVercelTask),
|
|
@@ -3801,6 +3377,23 @@ var BuildCommand = class {
|
|
|
3801
3377
|
$inject(BuildCompressTask)
|
|
3802
3378
|
];
|
|
3803
3379
|
/**
|
|
3380
|
+
* Value aliases accepted for `--target`.
|
|
3381
|
+
*
|
|
3382
|
+
* These let the CLI accept short forms (e.g. `--target cf`) that are
|
|
3383
|
+
* canonicalized to a real {@link BuildTarget} before they flow into the
|
|
3384
|
+
* pipeline. The enum in `flags.target` must also list the alias so it
|
|
3385
|
+
* passes schema validation.
|
|
3386
|
+
*/
|
|
3387
|
+
targetAliases = { cf: "cloudflare" };
|
|
3388
|
+
/**
|
|
3389
|
+
* Canonicalize a raw `--target` value, mapping any known alias
|
|
3390
|
+
* (e.g. `cf` → `cloudflare`) to its real {@link BuildTarget}.
|
|
3391
|
+
*/
|
|
3392
|
+
resolveTarget(target) {
|
|
3393
|
+
if (!target) return;
|
|
3394
|
+
return this.targetAliases[target] ?? target;
|
|
3395
|
+
}
|
|
3396
|
+
/**
|
|
3804
3397
|
* Resolve the effective runtime based on target and explicit runtime flag.
|
|
3805
3398
|
*
|
|
3806
3399
|
* Some targets force a specific runtime:
|
|
@@ -3832,10 +3425,11 @@ var BuildCommand = class {
|
|
|
3832
3425
|
"docker",
|
|
3833
3426
|
"vercel",
|
|
3834
3427
|
"cloudflare",
|
|
3428
|
+
"cf",
|
|
3835
3429
|
"static"
|
|
3836
3430
|
], {
|
|
3837
3431
|
aliases: ["t"],
|
|
3838
|
-
description: "Deployment target"
|
|
3432
|
+
description: "Deployment target (cf = cloudflare)"
|
|
3839
3433
|
})),
|
|
3840
3434
|
runtime: t.optional(t.enum([
|
|
3841
3435
|
"node",
|
|
@@ -3853,8 +3447,7 @@ var BuildCommand = class {
|
|
|
3853
3447
|
aliases: ["c"],
|
|
3854
3448
|
description: "Compile server to a single static binary (requires --target=docker --runtime=bun)"
|
|
3855
3449
|
})),
|
|
3856
|
-
prebuilt: t.optional(t.boolean({ description: "Skip the bundle steps (Vite client/server + asset compression). Only regenerates target-specific deploy config (e.g. wrangler.jsonc). Use when `dist/` is already built and you just need the config refreshed." }))
|
|
3857
|
-
sitemap: t.optional(t.text({ description: "Generate sitemap.xml with base URL" }))
|
|
3450
|
+
prebuilt: t.optional(t.boolean({ description: "Skip the bundle steps (Vite client/server + asset compression). Only regenerates target-specific deploy config (e.g. wrangler.jsonc). Use when `dist/` is already built and you just need the config refreshed." }))
|
|
3858
3451
|
}),
|
|
3859
3452
|
handler: async ({ flags, run, root }) => {
|
|
3860
3453
|
process.env.NODE_ENV = "production";
|
|
@@ -3862,17 +3455,19 @@ var BuildCommand = class {
|
|
|
3862
3455
|
await this.scaffolder.ensureConfig(root, { tsconfigJson: true });
|
|
3863
3456
|
const entry = await this.boot.getAppEntry(root);
|
|
3864
3457
|
this.log.trace("Entry file found", { entry });
|
|
3865
|
-
this.alepha.store.mut(buildOptions, (current) =>
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3458
|
+
this.alepha.store.mut(buildOptions, (current) => {
|
|
3459
|
+
const target = this.resolveTarget(flags.target) ?? current.target;
|
|
3460
|
+
return {
|
|
3461
|
+
...current,
|
|
3462
|
+
stats: flags.stats ?? current.stats ?? false,
|
|
3463
|
+
target,
|
|
3464
|
+
runtime: this.resolveRuntime(target, flags.runtime ?? current.runtime),
|
|
3465
|
+
...flags.compile !== void 0 && { docker: {
|
|
3466
|
+
...current.docker,
|
|
3467
|
+
compile: flags.compile ? current.docker?.compile ?? true : false
|
|
3468
|
+
} }
|
|
3469
|
+
};
|
|
3470
|
+
});
|
|
3876
3471
|
const options = this.options;
|
|
3877
3472
|
const distDir = options.output?.dist ?? "dist";
|
|
3878
3473
|
if (!flags.prebuilt) await run.rm(distDir, { alias: "clean dist" });
|
|
@@ -3886,23 +3481,30 @@ var BuildCommand = class {
|
|
|
3886
3481
|
target,
|
|
3887
3482
|
runtime: options.runtime
|
|
3888
3483
|
});
|
|
3484
|
+
let manifest = null;
|
|
3485
|
+
if (flags.prebuilt) manifest = await this.loadManifest(root);
|
|
3889
3486
|
let appAlepha;
|
|
3890
3487
|
let hasClient = false;
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3488
|
+
if (!manifest) {
|
|
3489
|
+
await run({
|
|
3490
|
+
name: "analyze app",
|
|
3491
|
+
handler: async () => {
|
|
3492
|
+
appAlepha = await this.viteBuildProvider.init({ entry });
|
|
3493
|
+
hasClient = this.viteBuildProvider.hasClient();
|
|
3494
|
+
}
|
|
3495
|
+
});
|
|
3496
|
+
if (!appAlepha) throw new AlephaError("Alepha instance not found");
|
|
3497
|
+
}
|
|
3498
|
+
const platformOptions = this.alepha.store.get("alepha.cli.platform.options") ?? null;
|
|
3899
3499
|
const ctx = {
|
|
3900
|
-
alepha: appAlepha,
|
|
3500
|
+
alepha: appAlepha ?? null,
|
|
3901
3501
|
options,
|
|
3902
3502
|
root,
|
|
3903
3503
|
run,
|
|
3904
3504
|
entry,
|
|
3905
3505
|
hasClient,
|
|
3506
|
+
manifest,
|
|
3507
|
+
platformOptions,
|
|
3906
3508
|
flags: {
|
|
3907
3509
|
image: flags.image,
|
|
3908
3510
|
prebuilt: flags.prebuilt
|
|
@@ -3911,6 +3513,21 @@ var BuildCommand = class {
|
|
|
3911
3513
|
for (const task of this.pipeline) await task.run(ctx);
|
|
3912
3514
|
}
|
|
3913
3515
|
});
|
|
3516
|
+
/**
|
|
3517
|
+
* Read `dist/manifest.json` produced by a previous `alepha build`.
|
|
3518
|
+
* Returns null when absent or unparseable — caller falls back to the
|
|
3519
|
+
* Vite-introspection path.
|
|
3520
|
+
*/
|
|
3521
|
+
async loadManifest(root) {
|
|
3522
|
+
try {
|
|
3523
|
+
const fs = await import("node:fs/promises");
|
|
3524
|
+
const path = await import("node:path");
|
|
3525
|
+
const raw = await fs.readFile(path.join(root, "dist", "manifest.json"), "utf-8");
|
|
3526
|
+
return JSON.parse(raw);
|
|
3527
|
+
} catch {
|
|
3528
|
+
return null;
|
|
3529
|
+
}
|
|
3530
|
+
}
|
|
3914
3531
|
};
|
|
3915
3532
|
//#endregion
|
|
3916
3533
|
//#region ../../src/cli/core/commands/clean.ts
|
|
@@ -4506,8 +4123,10 @@ var ViteDevServerProvider = class {
|
|
|
4506
4123
|
handleHotUpdate: async (ctx) => {
|
|
4507
4124
|
if (/[/\\]\.idea[/\\]/.test(ctx.file)) return [];
|
|
4508
4125
|
if (this.waitingForRetry) return [];
|
|
4509
|
-
|
|
4510
|
-
|
|
4126
|
+
if (!/\.(tsx|jsx)$/.test(ctx.file)) {
|
|
4127
|
+
const firstModule = ctx.modules[0];
|
|
4128
|
+
if (firstModule && !firstModule._ssrModule) return;
|
|
4129
|
+
}
|
|
4511
4130
|
this.changedFiles.add(ctx.file);
|
|
4512
4131
|
if (/\.(tsx|jsx)$/.test(ctx.file)) {
|
|
4513
4132
|
if (this.reloadDebounceTimer) {
|
|
@@ -4702,7 +4321,17 @@ if (import.meta.hot) {
|
|
|
4702
4321
|
process.env.SERVER_PORT ??= `${port}`;
|
|
4703
4322
|
}
|
|
4704
4323
|
/**
|
|
4705
|
-
* Invalidate modules and all their importers
|
|
4324
|
+
* Invalidate modules and all their importers, across both client and
|
|
4325
|
+
* SSR module graphs.
|
|
4326
|
+
*
|
|
4327
|
+
* Vite registers a file under multiple module ids (one per query
|
|
4328
|
+
* variant — e.g. `?v=…`, `?import` and the bare path), and `getModuleById`
|
|
4329
|
+
* only matches one. For workspace-linked source files (`@alepha/ui/...`)
|
|
4330
|
+
* the SSR-graph entry is keyed by the absolute path while the client
|
|
4331
|
+
* may use the package-qualified id. `getModulesByFile` returns every
|
|
4332
|
+
* variant Vite knows about for a given absolute path — invalidating
|
|
4333
|
+
* each catches both halves of the dual graph and prevents stale SSR
|
|
4334
|
+
* compiled exports from surviving across edits.
|
|
4706
4335
|
*/
|
|
4707
4336
|
invalidateModulesWithImporters(changedFiles) {
|
|
4708
4337
|
const graph = this.server.moduleGraph;
|
|
@@ -4711,11 +4340,16 @@ if (import.meta.hot) {
|
|
|
4711
4340
|
while (queue.length > 0) {
|
|
4712
4341
|
const file = queue.pop();
|
|
4713
4342
|
if (invalidated.has(file)) continue;
|
|
4714
|
-
const mod = this.server.moduleGraph.getModuleById(file);
|
|
4715
|
-
if (!mod) continue;
|
|
4716
|
-
graph.invalidateModule(mod);
|
|
4717
4343
|
invalidated.add(file);
|
|
4718
|
-
|
|
4344
|
+
const mods = new Set([...graph.getModulesByFile(file) ?? [], ...graph.getModuleById(file) ? [graph.getModuleById(file)] : []]);
|
|
4345
|
+
if (mods.size === 0) continue;
|
|
4346
|
+
for (const mod of mods) {
|
|
4347
|
+
graph.invalidateModule(mod);
|
|
4348
|
+
for (const importer of mod.importers) {
|
|
4349
|
+
const key = importer.file ?? importer.id;
|
|
4350
|
+
if (key && !invalidated.has(key)) queue.push(key);
|
|
4351
|
+
}
|
|
4352
|
+
}
|
|
4719
4353
|
}
|
|
4720
4354
|
const entryPath = this.options.entry.server;
|
|
4721
4355
|
const absoluteEntryPath = join(this.options.root, entryPath);
|
|
@@ -5299,8 +4933,6 @@ var InitCommand = class {
|
|
|
5299
4933
|
description: "Include React dependencies and web module (src/web/)"
|
|
5300
4934
|
})),
|
|
5301
4935
|
tailwind: t.optional(t.boolean({ description: "Include Tailwind CSS with Vite plugin. Implies --react" })),
|
|
5302
|
-
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" })),
|
|
5303
|
-
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" })),
|
|
5304
4936
|
force: t.optional(t.boolean({
|
|
5305
4937
|
aliases: ["f"],
|
|
5306
4938
|
description: "Override existing files"
|
|
@@ -5334,6 +4966,86 @@ var LintCommand = class {
|
|
|
5334
4966
|
});
|
|
5335
4967
|
};
|
|
5336
4968
|
//#endregion
|
|
4969
|
+
//#region ../../src/cli/core/commands/pack.ts
|
|
4970
|
+
/**
|
|
4971
|
+
* Pack the workspace into a deployable `tar.gz`.
|
|
4972
|
+
*
|
|
4973
|
+
* The tar contains everything a remote runner (Alepha Rocket, or any
|
|
4974
|
+
* `alepha platform <op> --prebuilt` consumer) needs to deploy the app:
|
|
4975
|
+
*
|
|
4976
|
+
* dist/ pre-built output (incl. manifest.json)
|
|
4977
|
+
* migrations/ SQL files (if present)
|
|
4978
|
+
*
|
|
4979
|
+
* No source, no `alepha.config.ts`, no `package.json` — the deploy
|
|
4980
|
+
* side reads everything from `dist/manifest.json` and never touches
|
|
4981
|
+
* source. Excludes: `node_modules`, `.DS_Store`, macOS AppleDouble
|
|
4982
|
+
* (`._*`), `.alepha` build cache, `e2e`, `playwright-report`,
|
|
4983
|
+
* `coverage`.
|
|
4984
|
+
*
|
|
4985
|
+
* Output name: `<project-name>-<tag>.tar.gz` (default tag
|
|
4986
|
+
* "latest"). Project name comes from `package.json.name`. Naming
|
|
4987
|
+
* mirrors Docker tags — same artifact, different tag = different
|
|
4988
|
+
* file.
|
|
4989
|
+
*/
|
|
4990
|
+
var PackCommand = class {
|
|
4991
|
+
log = $logger();
|
|
4992
|
+
fs = $inject(FileSystemProvider);
|
|
4993
|
+
shell = $inject(ShellProvider);
|
|
4994
|
+
pack = $command({
|
|
4995
|
+
name: "pack",
|
|
4996
|
+
description: "Pack the workspace into a deployable tar.gz (for `alepha platform --prebuilt` consumers like Alepha Rocket).",
|
|
4997
|
+
flags: t.object({
|
|
4998
|
+
tag: t.optional(t.text({
|
|
4999
|
+
aliases: ["t"],
|
|
5000
|
+
description: "Tag suffix for the artifact name (Docker-style). Defaults to `latest` → `<project>-latest.tar.gz`. Pass a real version like `0.0.2` for a pinned artifact."
|
|
5001
|
+
})),
|
|
5002
|
+
output: t.optional(t.text({
|
|
5003
|
+
aliases: ["o"],
|
|
5004
|
+
description: "Output directory for the tar.gz (default: current dir)."
|
|
5005
|
+
}))
|
|
5006
|
+
}),
|
|
5007
|
+
handler: async ({ flags, root, run }) => {
|
|
5008
|
+
const pkgPath = this.fs.join(root, "package.json");
|
|
5009
|
+
let project;
|
|
5010
|
+
try {
|
|
5011
|
+
const pkg = await this.fs.readJsonFile(pkgPath);
|
|
5012
|
+
if (!pkg.name) throw new AlephaError("Missing \"name\" in package.json — `alepha pack` needs it for the artifact filename.");
|
|
5013
|
+
project = pkg.name;
|
|
5014
|
+
} catch (err) {
|
|
5015
|
+
if (err instanceof AlephaError) throw err;
|
|
5016
|
+
throw new AlephaError(`Could not read package.json at ${pkgPath}. Run \`alepha pack\` from a workspace directory.`);
|
|
5017
|
+
}
|
|
5018
|
+
const tag = flags.tag ?? "latest";
|
|
5019
|
+
const outputDir = flags.output ?? root;
|
|
5020
|
+
const filename = `${project}-${tag}.tar.gz`;
|
|
5021
|
+
const outputPath = this.fs.join(outputDir, filename);
|
|
5022
|
+
const candidates = ["dist", "migrations"];
|
|
5023
|
+
const includes = [];
|
|
5024
|
+
for (const candidate of candidates) if (await this.fs.exists(this.fs.join(root, candidate))) includes.push(candidate);
|
|
5025
|
+
if (!includes.includes("dist")) throw new AlephaError("dist/ missing — run `alepha build --target=cloudflare` before `alepha pack`.");
|
|
5026
|
+
const manifestPath = this.fs.join(root, "dist", "manifest.json");
|
|
5027
|
+
if (!await this.fs.exists(manifestPath)) throw new AlephaError(`dist/manifest.json missing — required for prebuilt deploys. Rebuild with the current alepha version (\`alepha build --target=cloudflare\`).`);
|
|
5028
|
+
const cmd = `sh -c "COPYFILE_DISABLE=1 ${`tar -czf '${outputPath}' ${[
|
|
5029
|
+
"node_modules",
|
|
5030
|
+
".DS_Store",
|
|
5031
|
+
"._*",
|
|
5032
|
+
".alepha",
|
|
5033
|
+
"e2e",
|
|
5034
|
+
"playwright-report",
|
|
5035
|
+
"test-results",
|
|
5036
|
+
"coverage"
|
|
5037
|
+
].map((p) => `--exclude='${p}'`).join(" ")} ${includes.map((p) => `'${p}'`).join(" ")}`}"`;
|
|
5038
|
+
await run({
|
|
5039
|
+
name: `pack → ${filename}`,
|
|
5040
|
+
handler: async () => {
|
|
5041
|
+
await this.shell.run(cmd, { root });
|
|
5042
|
+
}
|
|
5043
|
+
});
|
|
5044
|
+
this.log.info(`Packed ${filename} → ${outputPath}`);
|
|
5045
|
+
}
|
|
5046
|
+
});
|
|
5047
|
+
};
|
|
5048
|
+
//#endregion
|
|
5337
5049
|
//#region ../../src/cli/core/commands/root.ts
|
|
5338
5050
|
var RootCommand = class {
|
|
5339
5051
|
log = $logger();
|
|
@@ -5497,6 +5209,7 @@ const AlephaCli = $module({
|
|
|
5497
5209
|
DevCommand,
|
|
5498
5210
|
InitCommand,
|
|
5499
5211
|
LintCommand,
|
|
5212
|
+
PackCommand,
|
|
5500
5213
|
RootCommand,
|
|
5501
5214
|
TestCommand,
|
|
5502
5215
|
TypecheckCommand,
|
|
@@ -5509,12 +5222,11 @@ const AlephaCli = $module({
|
|
|
5509
5222
|
BuildDockerTask,
|
|
5510
5223
|
BuildPrerenderTask,
|
|
5511
5224
|
BuildServerTask,
|
|
5512
|
-
BuildSitemapTask,
|
|
5513
5225
|
BuildStaticTask,
|
|
5514
5226
|
BuildVercelTask
|
|
5515
5227
|
]
|
|
5516
5228
|
});
|
|
5517
5229
|
//#endregion
|
|
5518
|
-
export { AlephaCli, AlephaCliExtensionProvider, AlephaCliServices, AlephaCliUtils, AppEntryProvider, BuildAssetsTask, BuildClientTask, BuildCloudflareTask, BuildCommand, BuildCompressTask, BuildDockerTask, BuildPrerenderTask, BuildServerTask,
|
|
5230
|
+
export { AlephaCli, AlephaCliExtensionProvider, AlephaCliServices, AlephaCliUtils, AppEntryProvider, BuildAssetsTask, BuildClientTask, BuildCloudflareTask, BuildCommand, BuildCompressTask, BuildDockerTask, BuildPrerenderTask, BuildServerTask, BuildStaticTask, BuildTask, BuildVercelTask, ChangelogCommand, CleanCommand, DEFAULT_IGNORE, DbCommand, DevCommand, GitMessageParser, GitProvider, InitCommand, LintCommand, OpenApiCommand, PackCommand, PackageManagerUtils, ProjectScaffolder, RootCommand, TestCommand, TypecheckCommand, VerifyCommand, ViteBuildProvider, ViteDevServerProvider, ViteUtils, alephaPackageJson, appEntryOptions, buildOptions, changelogOptions, devOptions, version };
|
|
5519
5231
|
|
|
5520
5232
|
//# sourceMappingURL=index.js.map
|