alepha 0.21.2 → 0.22.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 +289 -292
- 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 +211 -216
- 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 +1073 -1006
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +283 -61
- 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 +134 -140
- 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 +417 -214
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +325 -563
- 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 +8 -12
- package/dist/cli/i18n/index.d.ts.map +1 -1
- 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 +1446 -0
- package/dist/cli/platform-lib/index.d.ts.map +1 -0
- package/dist/cli/platform-lib/index.js +2597 -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 +21 -20
- 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 +16 -20
- package/dist/mcp/index.d.ts.map +1 -1
- 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 -4
- package/dist/react/form/index.d.ts.map +1 -1
- 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 +47 -11
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/i18n/index.js +33 -1
- 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 +65 -19
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +327 -222
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +65 -29
- package/dist/react/router/index.js.map +1 -1
- 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 +167 -172
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +4 -8
- 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 +5 -7
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +88 -73
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +19 -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 +45 -22
- 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/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 +3 -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/commands/__tests__/BuildCommand.spec.ts +43 -0
- package/src/cli/core/commands/build.ts +108 -30
- 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 -0
- 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 +353 -47
- package/src/cli/core/tasks/BuildDockerTask.ts +33 -3
- 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/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 +402 -165
- 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/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/i18n/components/Translate.tsx +47 -0
- package/src/react/i18n/index.ts +2 -0
- package/src/react/intro/components/GettingStartedAdminSlide.tsx +2 -2
- package/src/react/router/__tests__/$page.spec.tsx +3 -2
- package/src/react/router/__tests__/page-can.spec.ts +18 -13
- package/src/react/router/hooks/useQueryParams.ts +114 -14
- package/src/react/router/primitives/$page.ts +85 -4
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +3 -7
- package/src/react/router/providers/ReactServerProvider.ts +4 -13
- package/src/react/ui/services/SchemaControl.ts +3 -4
- 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/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";
|
|
@@ -1109,7 +1107,6 @@ var PackageManagerUtils = class {
|
|
|
1109
1107
|
devDependencies.tailwindcss = alephaDeps.tailwindcss;
|
|
1110
1108
|
devDependencies["@tailwindcss/vite"] = alephaDeps["@tailwindcss/vite"];
|
|
1111
1109
|
}
|
|
1112
|
-
if (modes.shadcn) devDependencies.shadcn = alephaDeps.shadcn;
|
|
1113
1110
|
if (modes.react) {
|
|
1114
1111
|
dependencies.react = alephaDeps.react;
|
|
1115
1112
|
dependencies["react-dom"] = alephaDeps["react-dom"];
|
|
@@ -1279,19 +1276,7 @@ export type HelloResponse = Static<typeof helloResponseSchema>;
|
|
|
1279
1276
|
//#endregion
|
|
1280
1277
|
//#region ../../src/cli/core/templates/apiIndexTs.ts
|
|
1281
1278
|
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();
|
|
1279
|
+
const { appName = "app" } = options;
|
|
1295
1280
|
return `
|
|
1296
1281
|
import { $module } from "alepha";
|
|
1297
1282
|
import { HelloController } from "./controllers/HelloController.ts";
|
|
@@ -1362,46 +1347,6 @@ const biomeJson = () => `
|
|
|
1362
1347
|
}
|
|
1363
1348
|
`.trim();
|
|
1364
1349
|
//#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
1350
|
//#region ../../src/cli/core/templates/dummySpecTs.ts
|
|
1406
1351
|
/**
|
|
1407
1352
|
* Starter spec written by `alepha init`. It doubles as a worked example:
|
|
@@ -1555,7 +1500,6 @@ const mainCss = (opts = {}) => {
|
|
|
1555
1500
|
*
|
|
1556
1501
|
* Options:
|
|
1557
1502
|
* - Tailwind CSS: Use \`alepha init --tailwind\` to add Tailwind CSS
|
|
1558
|
-
* - shadcn/ui: Use \`alepha init --shadcn\` to add shadcn/ui setup
|
|
1559
1503
|
* - Raw CSS: Write your own styles below
|
|
1560
1504
|
*/
|
|
1561
1505
|
|
|
@@ -1586,241 +1530,6 @@ run(alepha);
|
|
|
1586
1530
|
`.trim();
|
|
1587
1531
|
};
|
|
1588
1532
|
//#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
1533
|
//#region ../../src/cli/core/templates/tsconfigJson.ts
|
|
1825
1534
|
const tsconfigJson = () => `
|
|
1826
1535
|
{
|
|
@@ -1886,10 +1595,6 @@ const vscodeSettingsJson = () => `
|
|
|
1886
1595
|
//#endregion
|
|
1887
1596
|
//#region ../../src/cli/core/templates/webAppRouterTs.ts
|
|
1888
1597
|
const webAppRouterTs = (options) => {
|
|
1889
|
-
if (options.saas) return saasAppRouterTs();
|
|
1890
|
-
return basicAppRouterTs(options);
|
|
1891
|
-
};
|
|
1892
|
-
const basicAppRouterTs = (options) => {
|
|
1893
1598
|
const imports = ["import { $page } from \"alepha/react/router\";"];
|
|
1894
1599
|
const classMembers = [];
|
|
1895
1600
|
if (options.api) {
|
|
@@ -1911,95 +1616,6 @@ export class AppRouter {
|
|
|
1911
1616
|
${classMembers.join("\n\n")}
|
|
1912
1617
|
}`;
|
|
1913
1618
|
};
|
|
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
1619
|
//#endregion
|
|
2004
1620
|
//#region ../../src/cli/core/templates/webHomeComponentTsx.ts
|
|
2005
1621
|
const webHomeComponentTsx = (options = {}) => {
|
|
@@ -2028,19 +1644,7 @@ export default Home;
|
|
|
2028
1644
|
//#endregion
|
|
2029
1645
|
//#region ../../src/cli/core/templates/webIndexTs.ts
|
|
2030
1646
|
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();
|
|
1647
|
+
const { appName = "app" } = options;
|
|
2044
1648
|
return `
|
|
2045
1649
|
import { $module } from "alepha";
|
|
2046
1650
|
import { AppRouter } from "./AppRouter.ts";
|
|
@@ -2066,7 +1670,6 @@ var ProjectScaffolder = class {
|
|
|
2066
1670
|
log = $logger();
|
|
2067
1671
|
colors = $inject(ConsoleColorProvider);
|
|
2068
1672
|
fs = $inject(FileSystemProvider);
|
|
2069
|
-
shell = $inject(ShellProvider);
|
|
2070
1673
|
pm = $inject(PackageManagerUtils);
|
|
2071
1674
|
utils = $inject(AlephaCliUtils);
|
|
2072
1675
|
/**
|
|
@@ -2088,10 +1691,7 @@ var ProjectScaffolder = class {
|
|
|
2088
1691
|
const force = opts.force ?? false;
|
|
2089
1692
|
const checkWorkspace = opts.checkWorkspace ?? false;
|
|
2090
1693
|
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
|
-
}));
|
|
1694
|
+
if (opts.tsconfigJson) tasks.push(this.ensureTsConfig(root, { force }));
|
|
2095
1695
|
if (opts.biomeJson) tasks.push(this.ensureBiomeConfig(root, {
|
|
2096
1696
|
force,
|
|
2097
1697
|
checkWorkspace
|
|
@@ -2108,7 +1708,7 @@ var ProjectScaffolder = class {
|
|
|
2108
1708
|
await Promise.all(tasks);
|
|
2109
1709
|
}
|
|
2110
1710
|
async ensureTsConfig(root, opts = {}) {
|
|
2111
|
-
const exists =
|
|
1711
|
+
const exists = await this.existsInParents(root, "tsconfig.json");
|
|
2112
1712
|
if (!opts.force && exists) return;
|
|
2113
1713
|
await this.fs.writeFile(this.fs.join(root, "tsconfig.json"), tsconfigJson());
|
|
2114
1714
|
}
|
|
@@ -2185,33 +1785,9 @@ var ProjectScaffolder = class {
|
|
|
2185
1785
|
const appName = this.getAppName(root);
|
|
2186
1786
|
await this.fs.mkdir(this.fs.join(root, "src/api/controllers"), { recursive: true });
|
|
2187
1787
|
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);
|
|
1788
|
+
await this.ensureFile(root, "src/api/index.ts", apiIndexTs({ appName }), opts.force);
|
|
2192
1789
|
await this.ensureFile(root, "src/api/controllers/HelloController.ts", apiHelloControllerTs({ appName }), opts.force);
|
|
2193
1790
|
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
1791
|
}
|
|
2216
1792
|
/**
|
|
2217
1793
|
* Ensure web/React project structure exists.
|
|
@@ -2224,35 +1800,14 @@ var ProjectScaffolder = class {
|
|
|
2224
1800
|
async ensureWebProject(root, opts = {}) {
|
|
2225
1801
|
const appName = this.getAppName(root);
|
|
2226
1802
|
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
1803
|
await this.fs.mkdir(this.fs.join(root, "public"), { recursive: true });
|
|
2232
1804
|
await this.ensureFile(root, "public/favicon.svg", logoSvg, opts.force);
|
|
2233
1805
|
await this.ensureFile(root, "src/main.css", mainCss({ tailwind: opts.tailwind }), opts.force);
|
|
2234
1806
|
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);
|
|
1807
|
+
await this.ensureFile(root, "src/web/index.ts", webIndexTs({ appName }), opts.force);
|
|
1808
|
+
await this.ensureFile(root, "src/web/AppRouter.ts", webAppRouterTs({ api: opts.api }), opts.force);
|
|
2244
1809
|
await this.ensureFile(root, "src/web/components/Home.tsx", webHomeComponentTsx({ api: opts.api }), opts.force);
|
|
2245
1810
|
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
1811
|
}
|
|
2257
1812
|
/**
|
|
2258
1813
|
* Ensure test directory exists with a dummy test file + a self-contained
|
|
@@ -2275,21 +1830,16 @@ var ProjectScaffolder = class {
|
|
|
2275
1830
|
* Full project init — scaffolds files, installs deps, sets up PM and git.
|
|
2276
1831
|
*/
|
|
2277
1832
|
async init({ run, root, flags, args }) {
|
|
1833
|
+
if (!args) {
|
|
1834
|
+
if (!await this.fs.exists(this.fs.join(root, "package.json"))) args = "my-app";
|
|
1835
|
+
}
|
|
2278
1836
|
if (args) {
|
|
2279
1837
|
root = this.fs.join(root, args);
|
|
2280
1838
|
await this.fs.mkdir(root, { force: true });
|
|
2281
1839
|
}
|
|
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
1840
|
if (flags.tailwind) flags.react = true;
|
|
2292
|
-
|
|
1841
|
+
const f = flags;
|
|
1842
|
+
if ((flags.api || flags.react || flags.tailwind) && !flags.force) {
|
|
2293
1843
|
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
1844
|
}
|
|
2295
1845
|
const workspace = await this.pm.getWorkspaceContext(root);
|
|
@@ -2305,7 +1855,7 @@ var ProjectScaffolder = class {
|
|
|
2305
1855
|
...f,
|
|
2306
1856
|
isPackage: workspace.isPackage
|
|
2307
1857
|
},
|
|
2308
|
-
tsconfigJson:
|
|
1858
|
+
tsconfigJson: !workspace.config.tsconfigJson,
|
|
2309
1859
|
biomeJson: true,
|
|
2310
1860
|
editorconfig: !workspace.config.editorconfig,
|
|
2311
1861
|
agentMd: writeAgentMd,
|
|
@@ -2317,15 +1867,10 @@ var ProjectScaffolder = class {
|
|
|
2317
1867
|
react: !!flags.react && !isExpo,
|
|
2318
1868
|
force
|
|
2319
1869
|
});
|
|
2320
|
-
if (flags.api) await this.ensureApiProject(root, {
|
|
2321
|
-
saas: !!flags.saas,
|
|
2322
|
-
force
|
|
2323
|
-
});
|
|
1870
|
+
if (flags.api) await this.ensureApiProject(root, { force });
|
|
2324
1871
|
if (flags.react && !isExpo) await this.ensureWebProject(root, {
|
|
2325
1872
|
api: !!flags.api,
|
|
2326
1873
|
tailwind: !!flags.tailwind,
|
|
2327
|
-
shadcn: !!flags.shadcn,
|
|
2328
|
-
saas: !!flags.saas,
|
|
2329
1874
|
force
|
|
2330
1875
|
});
|
|
2331
1876
|
}
|
|
@@ -2343,18 +1888,6 @@ var ProjectScaffolder = class {
|
|
|
2343
1888
|
root: installRoot
|
|
2344
1889
|
});
|
|
2345
1890
|
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
1891
|
try {
|
|
2359
1892
|
await run(`${pmName} run lint`, {
|
|
2360
1893
|
alias: "running linter",
|
|
@@ -2401,30 +1934,6 @@ var ProjectScaffolder = class {
|
|
|
2401
1934
|
}
|
|
2402
1935
|
}
|
|
2403
1936
|
};
|
|
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
1937
|
//#endregion
|
|
2429
1938
|
//#region ../../src/cli/core/tasks/BuildTask.ts
|
|
2430
1939
|
/**
|
|
@@ -2563,6 +2072,7 @@ var BuildClientTask = class extends BuildTask {
|
|
|
2563
2072
|
};
|
|
2564
2073
|
//#endregion
|
|
2565
2074
|
//#region ../../src/cli/core/tasks/BuildCloudflareTask.ts
|
|
2075
|
+
const CLOUDFLARE_EMAIL_PROVIDER_NAME = "CloudflareEmailProvider";
|
|
2566
2076
|
/**
|
|
2567
2077
|
* Generate Cloudflare Workers deployment configuration.
|
|
2568
2078
|
*
|
|
@@ -2586,7 +2096,7 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2586
2096
|
}
|
|
2587
2097
|
async generateCloudflare(ctx, distDir) {
|
|
2588
2098
|
const root = ctx.root;
|
|
2589
|
-
const name = basename(root);
|
|
2099
|
+
const name = basename(root).toLowerCase().replace(/[^a-z0-9-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 63);
|
|
2590
2100
|
const hasAssets = await this.fs.exists(this.fs.join(root, distDir, "public"));
|
|
2591
2101
|
const wrangler = {
|
|
2592
2102
|
name,
|
|
@@ -2617,8 +2127,71 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2617
2127
|
this.enhanceEmail(ctx, wrangler);
|
|
2618
2128
|
const containers = this.enhanceContainers(ctx, wrangler);
|
|
2619
2129
|
await this.fs.writeFile(this.fs.join(root, distDir, "wrangler.jsonc"), JSON.stringify(wrangler, null, 2));
|
|
2130
|
+
if (!ctx.manifest) await this.writeManifest(ctx, root, distDir, name, containers);
|
|
2620
2131
|
await this.writeWorkerEntryPoint(root, distDir, containers);
|
|
2621
2132
|
}
|
|
2133
|
+
/**
|
|
2134
|
+
* Write `dist/manifest.json` — a build-time snapshot of everything
|
|
2135
|
+
* downstream tooling needs to know about the app without re-booting
|
|
2136
|
+
* it. Used by `alepha platform up --prebuilt` (and Alepha Rocket) so
|
|
2137
|
+
* the deploy path can skip the Vite-based introspection step and the
|
|
2138
|
+
* workspace's runtime npm install.
|
|
2139
|
+
*/
|
|
2140
|
+
async writeManifest(ctx, root, distDir, name, containers) {
|
|
2141
|
+
let hasDatabase = false;
|
|
2142
|
+
let hasBucket = false;
|
|
2143
|
+
let hasKV = false;
|
|
2144
|
+
let hasQueue = false;
|
|
2145
|
+
let crons = [];
|
|
2146
|
+
try {
|
|
2147
|
+
hasDatabase = (ctx.alepha.inject("RepositoryProvider").getRepositories?.() ?? []).length > 0;
|
|
2148
|
+
} catch {}
|
|
2149
|
+
try {
|
|
2150
|
+
hasBucket = ctx.alepha.primitives("$bucket").length > 0;
|
|
2151
|
+
} catch {}
|
|
2152
|
+
try {
|
|
2153
|
+
hasKV = ctx.alepha.primitives("cache").filter((p) => p.options?.provider == null).length > 0;
|
|
2154
|
+
} catch {}
|
|
2155
|
+
try {
|
|
2156
|
+
hasQueue = ctx.alepha.primitives("$queue").length > 0;
|
|
2157
|
+
} catch {}
|
|
2158
|
+
try {
|
|
2159
|
+
const cronProvider = ctx.alepha.inject("CronProvider");
|
|
2160
|
+
crons = [...new Set((cronProvider.getCronJobs?.() ?? []).map((c) => c.expression))];
|
|
2161
|
+
} catch {}
|
|
2162
|
+
const defaultEnv = ctx.platformOptions?.default ?? "production";
|
|
2163
|
+
const environments = ctx.platformOptions?.environments ?? {};
|
|
2164
|
+
let env = [];
|
|
2165
|
+
try {
|
|
2166
|
+
env = Object.keys(ctx.alepha.dump().env).sort();
|
|
2167
|
+
} catch {}
|
|
2168
|
+
const manifest = {
|
|
2169
|
+
version: 1,
|
|
2170
|
+
project: name,
|
|
2171
|
+
defaultEnv,
|
|
2172
|
+
tenancy: ctx.platformOptions?.tenancy,
|
|
2173
|
+
environments,
|
|
2174
|
+
resources: {
|
|
2175
|
+
hasDatabase,
|
|
2176
|
+
hasBucket,
|
|
2177
|
+
hasKV,
|
|
2178
|
+
hasQueue,
|
|
2179
|
+
hasCron: crons.length > 0
|
|
2180
|
+
},
|
|
2181
|
+
crons,
|
|
2182
|
+
containers: containers.map((c) => ({
|
|
2183
|
+
name: c.name,
|
|
2184
|
+
className: c.className,
|
|
2185
|
+
image: c.image,
|
|
2186
|
+
port: c.port,
|
|
2187
|
+
sleepAfter: c.sleepAfter,
|
|
2188
|
+
instanceType: c.instanceType,
|
|
2189
|
+
maxInstances: c.maxInstances
|
|
2190
|
+
})),
|
|
2191
|
+
env
|
|
2192
|
+
};
|
|
2193
|
+
await this.fs.writeFile(this.fs.join(root, distDir, "manifest.json"), JSON.stringify(manifest, null, 2));
|
|
2194
|
+
}
|
|
2622
2195
|
enhanceDomain(wrangler) {
|
|
2623
2196
|
const domain = process.env.CLOUDFLARE_DOMAIN;
|
|
2624
2197
|
if (!domain) return;
|
|
@@ -2637,16 +2210,20 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2637
2210
|
}];
|
|
2638
2211
|
}
|
|
2639
2212
|
enhanceCron(ctx, wrangler) {
|
|
2640
|
-
|
|
2213
|
+
const cronExpressions = ctx.manifest ? ctx.manifest.crons : this.discoverCrons(ctx);
|
|
2214
|
+
if (cronExpressions.length === 0) return;
|
|
2215
|
+
wrangler.triggers ??= {};
|
|
2216
|
+
wrangler.triggers.crons = cronExpressions;
|
|
2217
|
+
}
|
|
2218
|
+
discoverCrons(ctx) {
|
|
2219
|
+
if (ctx.alepha.primitives("scheduler").length === 0) return [];
|
|
2641
2220
|
let cronProvider;
|
|
2642
2221
|
try {
|
|
2643
2222
|
cronProvider = ctx.alepha.inject("CronProvider");
|
|
2644
2223
|
} catch {}
|
|
2645
2224
|
const crons = cronProvider?.getCronJobs();
|
|
2646
|
-
if (!crons || crons.length === 0) return;
|
|
2647
|
-
|
|
2648
|
-
wrangler.triggers ??= {};
|
|
2649
|
-
wrangler.triggers.crons = cronExpressions;
|
|
2225
|
+
if (!crons || crons.length === 0) return [];
|
|
2226
|
+
return [...new Set(crons.map((c) => c.expression))];
|
|
2650
2227
|
}
|
|
2651
2228
|
enhanceDatabase(wrangler) {
|
|
2652
2229
|
if (process.env.HYPERDRIVE_ID) {
|
|
@@ -2720,18 +2297,15 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2720
2297
|
wrangler.queues.consumers.push({ queue: queueName });
|
|
2721
2298
|
}
|
|
2722
2299
|
enhanceEmail(ctx, wrangler) {
|
|
2723
|
-
|
|
2300
|
+
if (ctx.manifest || !ctx.alepha) return;
|
|
2724
2301
|
try {
|
|
2725
|
-
|
|
2302
|
+
ctx.alepha.inject(CLOUDFLARE_EMAIL_PROVIDER_NAME);
|
|
2726
2303
|
} catch {
|
|
2727
2304
|
return;
|
|
2728
2305
|
}
|
|
2729
|
-
if (!(provider instanceof CloudflareEmailProvider)) return;
|
|
2730
2306
|
wrangler.send_email = wrangler.send_email || [];
|
|
2731
2307
|
if (wrangler.send_email.some((b) => b.name === SEND_EMAIL_DEFAULT_BINDING)) return;
|
|
2732
2308
|
const entry = { name: SEND_EMAIL_DEFAULT_BINDING };
|
|
2733
|
-
const destination = process.env.EMAIL_FROM;
|
|
2734
|
-
if (destination) entry.destination_address = destination;
|
|
2735
2309
|
wrangler.send_email.push(entry);
|
|
2736
2310
|
}
|
|
2737
2311
|
/**
|
|
@@ -2744,19 +2318,45 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2744
2318
|
* `writeWorkerEntryPoint` can emit `export class <NAME> extends
|
|
2745
2319
|
* Container` declarations referencing them.
|
|
2746
2320
|
*/
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
if (primitives.length === 0) return [];
|
|
2750
|
-
const descriptors = primitives.map((p) => ({
|
|
2321
|
+
discoverContainers(ctx) {
|
|
2322
|
+
return ctx.alepha.primitives("container").map((p) => ({
|
|
2751
2323
|
name: p.name.toUpperCase(),
|
|
2752
2324
|
className: p.name.split(/[^a-zA-Z0-9]/).filter(Boolean).map((s) => s[0].toUpperCase() + s.slice(1)).join(""),
|
|
2753
2325
|
image: p.options.image,
|
|
2754
2326
|
port: p.options.port ?? 3e3,
|
|
2755
2327
|
sleepAfter: typeof p.options.sleepAfter === "string" ? p.options.sleepAfter : "15m",
|
|
2756
|
-
instanceType: p.options.instanceType
|
|
2328
|
+
instanceType: p.options.instanceType === "dev" ? "lite" : p.options.instanceType ?? "lite",
|
|
2757
2329
|
maxInstances: p.options.maxInstances ?? 5,
|
|
2758
2330
|
envVars: p.options.envVars
|
|
2759
2331
|
}));
|
|
2332
|
+
}
|
|
2333
|
+
/**
|
|
2334
|
+
* Expand a short image ref (e.g. `alepha-rocket:0.1.0`) into the
|
|
2335
|
+
* fully-qualified `registry.cloudflare.com/<account>/<image>:<tag>`
|
|
2336
|
+
* URL that wrangler validates at deploy time.
|
|
2337
|
+
*
|
|
2338
|
+
* Cloudflare Containers only pulls from `registry.cloudflare.com`;
|
|
2339
|
+
* wrangler accepts either a Dockerfile path or a fully-qualified
|
|
2340
|
+
* registry URL in the `image` field — not a bare DockerHub-style
|
|
2341
|
+
* name. We let `$container({ image })` callers write the short
|
|
2342
|
+
* form (it matches what `wrangler containers push <local>` accepts
|
|
2343
|
+
* + matches the local docker tag) and rewrite to the CF registry
|
|
2344
|
+
* URL here.
|
|
2345
|
+
*
|
|
2346
|
+
* Pass-through cases:
|
|
2347
|
+
* - already a full URL: starts with `registry.cloudflare.com/`
|
|
2348
|
+
* or contains a scheme/`://`
|
|
2349
|
+
* - looks like a Dockerfile path: starts with `./` or `/`
|
|
2350
|
+
*/
|
|
2351
|
+
resolveContainerImage(image) {
|
|
2352
|
+
if (image.startsWith("./") || image.startsWith("/") || image.startsWith("registry.cloudflare.com/") || image.includes("://")) return image;
|
|
2353
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
2354
|
+
if (!accountId) return image;
|
|
2355
|
+
return `registry.cloudflare.com/${accountId}/${image}`;
|
|
2356
|
+
}
|
|
2357
|
+
enhanceContainers(ctx, wrangler) {
|
|
2358
|
+
const descriptors = ctx.manifest ? ctx.manifest.containers : this.discoverContainers(ctx);
|
|
2359
|
+
if (descriptors.length === 0) return [];
|
|
2760
2360
|
wrangler.containers = wrangler.containers || [];
|
|
2761
2361
|
wrangler.durable_objects = wrangler.durable_objects || {};
|
|
2762
2362
|
wrangler.durable_objects.bindings = wrangler.durable_objects.bindings || [];
|
|
@@ -2765,7 +2365,7 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2765
2365
|
for (const d of descriptors) {
|
|
2766
2366
|
wrangler.containers.push({
|
|
2767
2367
|
class_name: d.className,
|
|
2768
|
-
image: d.image,
|
|
2368
|
+
image: this.resolveContainerImage(d.image),
|
|
2769
2369
|
instance_type: d.instanceType,
|
|
2770
2370
|
max_instances: d.maxInstances
|
|
2771
2371
|
});
|
|
@@ -2784,9 +2384,8 @@ var BuildCloudflareTask = class BuildCloudflareTask extends BuildTask {
|
|
|
2784
2384
|
async writeWorkerEntryPoint(root, distDir, containers = []) {
|
|
2785
2385
|
const containerDeclarations = containers.map((c) => {
|
|
2786
2386
|
const envVars = c.envVars ? ` envVars = ${JSON.stringify(c.envVars)};\n` : "";
|
|
2787
|
-
return `export class ${c.className} extends
|
|
2387
|
+
return `export class ${c.className} extends globalThis.__alepha_CloudflareContainer {\n defaultPort = ${c.port};\n sleepAfter = "${c.sleepAfter}";\n${envVars}}`;
|
|
2788
2388
|
}).join("\n\n");
|
|
2789
|
-
const containerImport = containers.length > 0 ? `import { Container } from "@cloudflare/containers";\n\n${containerDeclarations}\n\n` : "";
|
|
2790
2389
|
const workerCode = `
|
|
2791
2390
|
import "./index.js";
|
|
2792
2391
|
|
|
@@ -2801,11 +2400,19 @@ const setWaitUntil = (executionCtx) => {
|
|
|
2801
2400
|
}
|
|
2802
2401
|
};
|
|
2803
2402
|
|
|
2403
|
+
// Bind the per-invocation Worker \`env\`: keep the full binding (D1, R2, KV, …)
|
|
2404
|
+
// in the store for providers, and lift its string values (secrets/vars like
|
|
2405
|
+
// PUBLIC_URL) into \`alepha.env\` so \`$env\` resolves them at runtime.
|
|
2406
|
+
const bindEnv = (env) => {
|
|
2407
|
+
__alepha.set("cloudflare.env", env);
|
|
2408
|
+
__alepha.loadEnv(env);
|
|
2409
|
+
};
|
|
2410
|
+
|
|
2804
2411
|
export default {
|
|
2805
2412
|
fetch: async (request, env, executionCtx) => {
|
|
2806
2413
|
const ctx = { req: request, res: undefined };
|
|
2807
2414
|
|
|
2808
|
-
|
|
2415
|
+
bindEnv(env);
|
|
2809
2416
|
setWaitUntil(executionCtx);
|
|
2810
2417
|
|
|
2811
2418
|
try {
|
|
@@ -2821,7 +2428,7 @@ export default {
|
|
|
2821
2428
|
},
|
|
2822
2429
|
|
|
2823
2430
|
scheduled: async (event, env, executionCtx) => {
|
|
2824
|
-
|
|
2431
|
+
bindEnv(env);
|
|
2825
2432
|
setWaitUntil(executionCtx);
|
|
2826
2433
|
|
|
2827
2434
|
try {
|
|
@@ -2838,7 +2445,7 @@ export default {
|
|
|
2838
2445
|
},
|
|
2839
2446
|
|
|
2840
2447
|
queue: async (batch, env, executionCtx) => {
|
|
2841
|
-
|
|
2448
|
+
bindEnv(env);
|
|
2842
2449
|
setWaitUntil(executionCtx);
|
|
2843
2450
|
|
|
2844
2451
|
try {
|
|
@@ -2859,7 +2466,8 @@ export default {
|
|
|
2859
2466
|
},
|
|
2860
2467
|
};
|
|
2861
2468
|
`.trim();
|
|
2862
|
-
|
|
2469
|
+
const containerBlock = containers.length > 0 ? `${containerDeclarations}\n\n` : "";
|
|
2470
|
+
await this.fs.writeFile(this.fs.join(root, distDir, "main.cloudflare.js"), `${this.warningComment}\n${containerBlock}${workerCode}`.trim());
|
|
2863
2471
|
}
|
|
2864
2472
|
};
|
|
2865
2473
|
//#endregion
|
|
@@ -2979,6 +2587,7 @@ var BuildDockerTask = class extends BuildTask {
|
|
|
2979
2587
|
name: "generate deploy config (docker)",
|
|
2980
2588
|
handler: async () => {
|
|
2981
2589
|
const migrationsCopied = await this.copyMigrations(ctx.root, distDir);
|
|
2590
|
+
const hasDeps = await this.hasRuntimeDeps(ctx.root, distDir);
|
|
2982
2591
|
await this.writeDockerfile(ctx.root, distDir, {
|
|
2983
2592
|
compile,
|
|
2984
2593
|
standard: {
|
|
@@ -2986,6 +2595,7 @@ var BuildDockerTask = class extends BuildTask {
|
|
|
2986
2595
|
command: dockerCommand
|
|
2987
2596
|
},
|
|
2988
2597
|
hasMigrations: migrationsCopied,
|
|
2598
|
+
hasDeps,
|
|
2989
2599
|
install: ctx.options.docker?.install ?? []
|
|
2990
2600
|
});
|
|
2991
2601
|
}
|
|
@@ -3071,6 +2681,21 @@ var BuildDockerTask = class extends BuildTask {
|
|
|
3071
2681
|
}
|
|
3072
2682
|
return false;
|
|
3073
2683
|
}
|
|
2684
|
+
/**
|
|
2685
|
+
* Whether the produced `dist/package.json` declares any runtime
|
|
2686
|
+
* dependencies. Alepha apps normally bundle everything into the
|
|
2687
|
+
* server entry via Vite, leaving `dependencies: {}` — in which case
|
|
2688
|
+
* the generated Dockerfile's `RUN npm install` is wasted work
|
|
2689
|
+
* (and emits deprecation noise). Skip the line when empty.
|
|
2690
|
+
*/
|
|
2691
|
+
async hasRuntimeDeps(root, distDir) {
|
|
2692
|
+
try {
|
|
2693
|
+
const pkg = await this.fs.readJsonFile(this.fs.join(root, distDir, "package.json"));
|
|
2694
|
+
return Object.keys(pkg.dependencies ?? {}).length > 0;
|
|
2695
|
+
} catch {
|
|
2696
|
+
return false;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
3074
2699
|
async writeDockerfile(root, distDir, opts) {
|
|
3075
2700
|
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
2701
|
const migrationsLine = opts.hasMigrations ? "COPY migrations ./migrations\n" : "";
|
|
@@ -3086,14 +2711,12 @@ ENTRYPOINT ["/app/app"]
|
|
|
3086
2711
|
`;
|
|
3087
2712
|
else {
|
|
3088
2713
|
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
2714
|
dockerfile = `${header}FROM ${image}
|
|
3091
2715
|
WORKDIR /app
|
|
3092
2716
|
|
|
3093
2717
|
COPY . .
|
|
3094
2718
|
|
|
3095
|
-
RUN ${command === "bun" ? "bun" : "npm"} install
|
|
3096
|
-
${installLine}
|
|
2719
|
+
${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
2720
|
ENV SERVER_HOST=0.0.0.0
|
|
3098
2721
|
|
|
3099
2722
|
CMD ["${command}", "index.js"]
|
|
@@ -3801,6 +3424,23 @@ var BuildCommand = class {
|
|
|
3801
3424
|
$inject(BuildCompressTask)
|
|
3802
3425
|
];
|
|
3803
3426
|
/**
|
|
3427
|
+
* Value aliases accepted for `--target`.
|
|
3428
|
+
*
|
|
3429
|
+
* These let the CLI accept short forms (e.g. `--target cf`) that are
|
|
3430
|
+
* canonicalized to a real {@link BuildTarget} before they flow into the
|
|
3431
|
+
* pipeline. The enum in `flags.target` must also list the alias so it
|
|
3432
|
+
* passes schema validation.
|
|
3433
|
+
*/
|
|
3434
|
+
targetAliases = { cf: "cloudflare" };
|
|
3435
|
+
/**
|
|
3436
|
+
* Canonicalize a raw `--target` value, mapping any known alias
|
|
3437
|
+
* (e.g. `cf` → `cloudflare`) to its real {@link BuildTarget}.
|
|
3438
|
+
*/
|
|
3439
|
+
resolveTarget(target) {
|
|
3440
|
+
if (!target) return;
|
|
3441
|
+
return this.targetAliases[target] ?? target;
|
|
3442
|
+
}
|
|
3443
|
+
/**
|
|
3804
3444
|
* Resolve the effective runtime based on target and explicit runtime flag.
|
|
3805
3445
|
*
|
|
3806
3446
|
* Some targets force a specific runtime:
|
|
@@ -3832,10 +3472,11 @@ var BuildCommand = class {
|
|
|
3832
3472
|
"docker",
|
|
3833
3473
|
"vercel",
|
|
3834
3474
|
"cloudflare",
|
|
3475
|
+
"cf",
|
|
3835
3476
|
"static"
|
|
3836
3477
|
], {
|
|
3837
3478
|
aliases: ["t"],
|
|
3838
|
-
description: "Deployment target"
|
|
3479
|
+
description: "Deployment target (cf = cloudflare)"
|
|
3839
3480
|
})),
|
|
3840
3481
|
runtime: t.optional(t.enum([
|
|
3841
3482
|
"node",
|
|
@@ -3862,17 +3503,20 @@ var BuildCommand = class {
|
|
|
3862
3503
|
await this.scaffolder.ensureConfig(root, { tsconfigJson: true });
|
|
3863
3504
|
const entry = await this.boot.getAppEntry(root);
|
|
3864
3505
|
this.log.trace("Entry file found", { entry });
|
|
3865
|
-
this.alepha.store.mut(buildOptions, (current) =>
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
|
|
3872
|
-
|
|
3873
|
-
|
|
3874
|
-
|
|
3875
|
-
|
|
3506
|
+
this.alepha.store.mut(buildOptions, (current) => {
|
|
3507
|
+
const target = this.resolveTarget(flags.target) ?? current.target;
|
|
3508
|
+
return {
|
|
3509
|
+
...current,
|
|
3510
|
+
stats: flags.stats ?? current.stats ?? false,
|
|
3511
|
+
target,
|
|
3512
|
+
runtime: this.resolveRuntime(target, flags.runtime ?? current.runtime),
|
|
3513
|
+
...flags.compile !== void 0 && { docker: {
|
|
3514
|
+
...current.docker,
|
|
3515
|
+
compile: flags.compile ? current.docker?.compile ?? true : false
|
|
3516
|
+
} },
|
|
3517
|
+
...flags.sitemap && { sitemap: { hostname: flags.sitemap } }
|
|
3518
|
+
};
|
|
3519
|
+
});
|
|
3876
3520
|
const options = this.options;
|
|
3877
3521
|
const distDir = options.output?.dist ?? "dist";
|
|
3878
3522
|
if (!flags.prebuilt) await run.rm(distDir, { alias: "clean dist" });
|
|
@@ -3886,23 +3530,30 @@ var BuildCommand = class {
|
|
|
3886
3530
|
target,
|
|
3887
3531
|
runtime: options.runtime
|
|
3888
3532
|
});
|
|
3533
|
+
let manifest = null;
|
|
3534
|
+
if (flags.prebuilt) manifest = await this.loadManifest(root);
|
|
3889
3535
|
let appAlepha;
|
|
3890
3536
|
let hasClient = false;
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3896
|
-
|
|
3897
|
-
|
|
3898
|
-
|
|
3537
|
+
if (!manifest) {
|
|
3538
|
+
await run({
|
|
3539
|
+
name: "analyze app",
|
|
3540
|
+
handler: async () => {
|
|
3541
|
+
appAlepha = await this.viteBuildProvider.init({ entry });
|
|
3542
|
+
hasClient = this.viteBuildProvider.hasClient();
|
|
3543
|
+
}
|
|
3544
|
+
});
|
|
3545
|
+
if (!appAlepha) throw new AlephaError("Alepha instance not found");
|
|
3546
|
+
}
|
|
3547
|
+
const platformOptions = this.alepha.store.get("alepha.cli.platform.options") ?? null;
|
|
3899
3548
|
const ctx = {
|
|
3900
|
-
alepha: appAlepha,
|
|
3549
|
+
alepha: appAlepha ?? null,
|
|
3901
3550
|
options,
|
|
3902
3551
|
root,
|
|
3903
3552
|
run,
|
|
3904
3553
|
entry,
|
|
3905
3554
|
hasClient,
|
|
3555
|
+
manifest,
|
|
3556
|
+
platformOptions,
|
|
3906
3557
|
flags: {
|
|
3907
3558
|
image: flags.image,
|
|
3908
3559
|
prebuilt: flags.prebuilt
|
|
@@ -3911,6 +3562,21 @@ var BuildCommand = class {
|
|
|
3911
3562
|
for (const task of this.pipeline) await task.run(ctx);
|
|
3912
3563
|
}
|
|
3913
3564
|
});
|
|
3565
|
+
/**
|
|
3566
|
+
* Read `dist/manifest.json` produced by a previous `alepha build`.
|
|
3567
|
+
* Returns null when absent or unparseable — caller falls back to the
|
|
3568
|
+
* Vite-introspection path.
|
|
3569
|
+
*/
|
|
3570
|
+
async loadManifest(root) {
|
|
3571
|
+
try {
|
|
3572
|
+
const fs = await import("node:fs/promises");
|
|
3573
|
+
const path = await import("node:path");
|
|
3574
|
+
const raw = await fs.readFile(path.join(root, "dist", "manifest.json"), "utf-8");
|
|
3575
|
+
return JSON.parse(raw);
|
|
3576
|
+
} catch {
|
|
3577
|
+
return null;
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3914
3580
|
};
|
|
3915
3581
|
//#endregion
|
|
3916
3582
|
//#region ../../src/cli/core/commands/clean.ts
|
|
@@ -4506,8 +4172,10 @@ var ViteDevServerProvider = class {
|
|
|
4506
4172
|
handleHotUpdate: async (ctx) => {
|
|
4507
4173
|
if (/[/\\]\.idea[/\\]/.test(ctx.file)) return [];
|
|
4508
4174
|
if (this.waitingForRetry) return [];
|
|
4509
|
-
|
|
4510
|
-
|
|
4175
|
+
if (!/\.(tsx|jsx)$/.test(ctx.file)) {
|
|
4176
|
+
const firstModule = ctx.modules[0];
|
|
4177
|
+
if (firstModule && !firstModule._ssrModule) return;
|
|
4178
|
+
}
|
|
4511
4179
|
this.changedFiles.add(ctx.file);
|
|
4512
4180
|
if (/\.(tsx|jsx)$/.test(ctx.file)) {
|
|
4513
4181
|
if (this.reloadDebounceTimer) {
|
|
@@ -4702,7 +4370,17 @@ if (import.meta.hot) {
|
|
|
4702
4370
|
process.env.SERVER_PORT ??= `${port}`;
|
|
4703
4371
|
}
|
|
4704
4372
|
/**
|
|
4705
|
-
* Invalidate modules and all their importers
|
|
4373
|
+
* Invalidate modules and all their importers, across both client and
|
|
4374
|
+
* SSR module graphs.
|
|
4375
|
+
*
|
|
4376
|
+
* Vite registers a file under multiple module ids (one per query
|
|
4377
|
+
* variant — e.g. `?v=…`, `?import` and the bare path), and `getModuleById`
|
|
4378
|
+
* only matches one. For workspace-linked source files (`@alepha/ui/...`)
|
|
4379
|
+
* the SSR-graph entry is keyed by the absolute path while the client
|
|
4380
|
+
* may use the package-qualified id. `getModulesByFile` returns every
|
|
4381
|
+
* variant Vite knows about for a given absolute path — invalidating
|
|
4382
|
+
* each catches both halves of the dual graph and prevents stale SSR
|
|
4383
|
+
* compiled exports from surviving across edits.
|
|
4706
4384
|
*/
|
|
4707
4385
|
invalidateModulesWithImporters(changedFiles) {
|
|
4708
4386
|
const graph = this.server.moduleGraph;
|
|
@@ -4711,11 +4389,16 @@ if (import.meta.hot) {
|
|
|
4711
4389
|
while (queue.length > 0) {
|
|
4712
4390
|
const file = queue.pop();
|
|
4713
4391
|
if (invalidated.has(file)) continue;
|
|
4714
|
-
const mod = this.server.moduleGraph.getModuleById(file);
|
|
4715
|
-
if (!mod) continue;
|
|
4716
|
-
graph.invalidateModule(mod);
|
|
4717
4392
|
invalidated.add(file);
|
|
4718
|
-
|
|
4393
|
+
const mods = new Set([...graph.getModulesByFile(file) ?? [], ...graph.getModuleById(file) ? [graph.getModuleById(file)] : []]);
|
|
4394
|
+
if (mods.size === 0) continue;
|
|
4395
|
+
for (const mod of mods) {
|
|
4396
|
+
graph.invalidateModule(mod);
|
|
4397
|
+
for (const importer of mod.importers) {
|
|
4398
|
+
const key = importer.file ?? importer.id;
|
|
4399
|
+
if (key && !invalidated.has(key)) queue.push(key);
|
|
4400
|
+
}
|
|
4401
|
+
}
|
|
4719
4402
|
}
|
|
4720
4403
|
const entryPath = this.options.entry.server;
|
|
4721
4404
|
const absoluteEntryPath = join(this.options.root, entryPath);
|
|
@@ -5299,8 +4982,6 @@ var InitCommand = class {
|
|
|
5299
4982
|
description: "Include React dependencies and web module (src/web/)"
|
|
5300
4983
|
})),
|
|
5301
4984
|
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
4985
|
force: t.optional(t.boolean({
|
|
5305
4986
|
aliases: ["f"],
|
|
5306
4987
|
description: "Override existing files"
|
|
@@ -5334,6 +5015,86 @@ var LintCommand = class {
|
|
|
5334
5015
|
});
|
|
5335
5016
|
};
|
|
5336
5017
|
//#endregion
|
|
5018
|
+
//#region ../../src/cli/core/commands/pack.ts
|
|
5019
|
+
/**
|
|
5020
|
+
* Pack the workspace into a deployable `tar.gz`.
|
|
5021
|
+
*
|
|
5022
|
+
* The tar contains everything a remote runner (Alepha Rocket, or any
|
|
5023
|
+
* `alepha platform <op> --prebuilt` consumer) needs to deploy the app:
|
|
5024
|
+
*
|
|
5025
|
+
* dist/ pre-built output (incl. manifest.json)
|
|
5026
|
+
* migrations/ SQL files (if present)
|
|
5027
|
+
*
|
|
5028
|
+
* No source, no `alepha.config.ts`, no `package.json` — the deploy
|
|
5029
|
+
* side reads everything from `dist/manifest.json` and never touches
|
|
5030
|
+
* source. Excludes: `node_modules`, `.DS_Store`, macOS AppleDouble
|
|
5031
|
+
* (`._*`), `.alepha` build cache, `e2e`, `playwright-report`,
|
|
5032
|
+
* `coverage`.
|
|
5033
|
+
*
|
|
5034
|
+
* Output name: `<project-name>-<tag>.tar.gz` (default tag
|
|
5035
|
+
* "latest"). Project name comes from `package.json.name`. Naming
|
|
5036
|
+
* mirrors Docker tags — same artifact, different tag = different
|
|
5037
|
+
* file.
|
|
5038
|
+
*/
|
|
5039
|
+
var PackCommand = class {
|
|
5040
|
+
log = $logger();
|
|
5041
|
+
fs = $inject(FileSystemProvider);
|
|
5042
|
+
shell = $inject(ShellProvider);
|
|
5043
|
+
pack = $command({
|
|
5044
|
+
name: "pack",
|
|
5045
|
+
description: "Pack the workspace into a deployable tar.gz (for `alepha platform --prebuilt` consumers like Alepha Rocket).",
|
|
5046
|
+
flags: t.object({
|
|
5047
|
+
tag: t.optional(t.text({
|
|
5048
|
+
aliases: ["t"],
|
|
5049
|
+
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."
|
|
5050
|
+
})),
|
|
5051
|
+
output: t.optional(t.text({
|
|
5052
|
+
aliases: ["o"],
|
|
5053
|
+
description: "Output directory for the tar.gz (default: current dir)."
|
|
5054
|
+
}))
|
|
5055
|
+
}),
|
|
5056
|
+
handler: async ({ flags, root, run }) => {
|
|
5057
|
+
const pkgPath = this.fs.join(root, "package.json");
|
|
5058
|
+
let project;
|
|
5059
|
+
try {
|
|
5060
|
+
const pkg = await this.fs.readJsonFile(pkgPath);
|
|
5061
|
+
if (!pkg.name) throw new AlephaError("Missing \"name\" in package.json — `alepha pack` needs it for the artifact filename.");
|
|
5062
|
+
project = pkg.name;
|
|
5063
|
+
} catch (err) {
|
|
5064
|
+
if (err instanceof AlephaError) throw err;
|
|
5065
|
+
throw new AlephaError(`Could not read package.json at ${pkgPath}. Run \`alepha pack\` from a workspace directory.`);
|
|
5066
|
+
}
|
|
5067
|
+
const tag = flags.tag ?? "latest";
|
|
5068
|
+
const outputDir = flags.output ?? root;
|
|
5069
|
+
const filename = `${project}-${tag}.tar.gz`;
|
|
5070
|
+
const outputPath = this.fs.join(outputDir, filename);
|
|
5071
|
+
const candidates = ["dist", "migrations"];
|
|
5072
|
+
const includes = [];
|
|
5073
|
+
for (const candidate of candidates) if (await this.fs.exists(this.fs.join(root, candidate))) includes.push(candidate);
|
|
5074
|
+
if (!includes.includes("dist")) throw new AlephaError("dist/ missing — run `alepha build --target=cloudflare` before `alepha pack`.");
|
|
5075
|
+
const manifestPath = this.fs.join(root, "dist", "manifest.json");
|
|
5076
|
+
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\`).`);
|
|
5077
|
+
const cmd = `sh -c "COPYFILE_DISABLE=1 ${`tar -czf '${outputPath}' ${[
|
|
5078
|
+
"node_modules",
|
|
5079
|
+
".DS_Store",
|
|
5080
|
+
"._*",
|
|
5081
|
+
".alepha",
|
|
5082
|
+
"e2e",
|
|
5083
|
+
"playwright-report",
|
|
5084
|
+
"test-results",
|
|
5085
|
+
"coverage"
|
|
5086
|
+
].map((p) => `--exclude='${p}'`).join(" ")} ${includes.map((p) => `'${p}'`).join(" ")}`}"`;
|
|
5087
|
+
await run({
|
|
5088
|
+
name: `pack → ${filename}`,
|
|
5089
|
+
handler: async () => {
|
|
5090
|
+
await this.shell.run(cmd, { root });
|
|
5091
|
+
}
|
|
5092
|
+
});
|
|
5093
|
+
this.log.info(`Packed ${filename} → ${outputPath}`);
|
|
5094
|
+
}
|
|
5095
|
+
});
|
|
5096
|
+
};
|
|
5097
|
+
//#endregion
|
|
5337
5098
|
//#region ../../src/cli/core/commands/root.ts
|
|
5338
5099
|
var RootCommand = class {
|
|
5339
5100
|
log = $logger();
|
|
@@ -5497,6 +5258,7 @@ const AlephaCli = $module({
|
|
|
5497
5258
|
DevCommand,
|
|
5498
5259
|
InitCommand,
|
|
5499
5260
|
LintCommand,
|
|
5261
|
+
PackCommand,
|
|
5500
5262
|
RootCommand,
|
|
5501
5263
|
TestCommand,
|
|
5502
5264
|
TypecheckCommand,
|
|
@@ -5515,6 +5277,6 @@ const AlephaCli = $module({
|
|
|
5515
5277
|
]
|
|
5516
5278
|
});
|
|
5517
5279
|
//#endregion
|
|
5518
|
-
export { AlephaCli, AlephaCliExtensionProvider, AlephaCliServices, AlephaCliUtils, AppEntryProvider, BuildAssetsTask, BuildClientTask, BuildCloudflareTask, BuildCommand, BuildCompressTask, BuildDockerTask, BuildPrerenderTask, BuildServerTask, BuildSitemapTask, BuildStaticTask, BuildTask, BuildVercelTask, ChangelogCommand, CleanCommand, DEFAULT_IGNORE, DbCommand, DevCommand, GitMessageParser, GitProvider, InitCommand, LintCommand, OpenApiCommand, PackageManagerUtils, ProjectScaffolder, RootCommand, TestCommand, TypecheckCommand, VerifyCommand, ViteBuildProvider, ViteDevServerProvider, ViteUtils, alephaPackageJson, appEntryOptions, buildOptions, changelogOptions, devOptions, version };
|
|
5280
|
+
export { AlephaCli, AlephaCliExtensionProvider, AlephaCliServices, AlephaCliUtils, AppEntryProvider, BuildAssetsTask, BuildClientTask, BuildCloudflareTask, BuildCommand, BuildCompressTask, BuildDockerTask, BuildPrerenderTask, BuildServerTask, BuildSitemapTask, 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
5281
|
|
|
5520
5282
|
//# sourceMappingURL=index.js.map
|