alepha 0.14.1 → 0.14.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/api/audits/index.browser.js +5 -5
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts +784 -784
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +13 -13
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.browser.js +5 -5
- package/dist/api/files/index.browser.js.map +1 -1
- package/dist/api/files/index.d.ts +57 -57
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +71 -71
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +5 -5
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +165 -165
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +10 -10
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +10 -10
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +583 -171
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +12 -12
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +163 -10
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +281 -276
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +196 -91
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.browser.js +19 -19
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +778 -764
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +831 -596
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.browser.js +6 -6
- package/dist/api/verifications/index.browser.js.map +1 -1
- package/dist/api/verifications/index.d.ts +125 -125
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +6 -6
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/bin/index.d.ts +1 -2
- package/dist/bin/index.js +0 -1
- package/dist/bin/index.js.map +1 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cli/index.d.ts +249 -218
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +951 -821
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +40 -0
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +97 -17
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +14 -18
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +29 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +21 -24
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +21 -24
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/fake/index.js +195 -168
- package/dist/fake/index.js.map +1 -1
- package/dist/file/index.d.ts +8 -0
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +3 -0
- package/dist/file/index.js.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.browser.js +26 -5
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.d.ts +146 -121
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +49 -24
- package/dist/orm/index.js.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.js.map +1 -1
- package/dist/router/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +6 -6
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +29 -29
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +171 -155
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +0 -1
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +2 -0
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/cookies/index.browser.js.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +1 -1
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/health/index.d.ts +17 -17
- package/dist/server/helmet/index.js.map +1 -1
- package/dist/server/links/index.browser.js +22 -6
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +46 -44
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +24 -41
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/multipart/index.js.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/security/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +2 -1
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +8 -3
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +12 -4
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.js.map +1 -1
- package/package.json +7 -7
- package/src/api/audits/controllers/{AuditController.ts → AdminAuditController.ts} +5 -6
- package/src/api/audits/entities/audits.ts +5 -5
- package/src/api/audits/index.browser.ts +1 -1
- package/src/api/audits/index.ts +3 -3
- package/src/api/audits/primitives/$audit.spec.ts +276 -0
- package/src/api/audits/services/AuditService.spec.ts +495 -0
- package/src/api/files/__tests__/$bucket.spec.ts +91 -0
- package/src/api/files/controllers/AdminFileStatsController.spec.ts +166 -0
- package/src/api/files/controllers/{StorageStatsController.ts → AdminFileStatsController.ts} +2 -2
- package/src/api/files/controllers/FileController.spec.ts +558 -0
- package/src/api/files/controllers/FileController.ts +4 -5
- package/src/api/files/entities/files.ts +5 -5
- package/src/api/files/index.browser.ts +1 -1
- package/src/api/files/index.ts +4 -4
- package/src/api/files/jobs/FileJobs.spec.ts +52 -0
- package/src/api/files/services/FileService.spec.ts +109 -0
- package/src/api/jobs/__tests__/JobController.spec.ts +343 -0
- package/src/api/jobs/controllers/{JobController.ts → AdminJobController.ts} +2 -2
- package/src/api/jobs/entities/jobExecutions.ts +5 -5
- package/src/api/jobs/index.ts +3 -3
- package/src/api/jobs/primitives/$job.spec.ts +476 -0
- package/src/api/notifications/controllers/{NotificationController.ts → AdminNotificationController.ts} +4 -5
- package/src/api/notifications/entities/notifications.ts +5 -5
- package/src/api/notifications/index.browser.ts +1 -1
- package/src/api/notifications/index.ts +4 -4
- package/src/api/parameters/controllers/{ConfigController.ts → AdminConfigController.ts} +46 -107
- package/src/api/parameters/entities/parameters.ts +7 -17
- package/src/api/parameters/index.ts +3 -3
- package/src/api/parameters/primitives/$config.spec.ts +356 -0
- package/src/api/parameters/schemas/activateConfigBodySchema.ts +12 -0
- package/src/api/parameters/schemas/checkScheduledResponseSchema.ts +8 -0
- package/src/api/parameters/schemas/configCurrentResponseSchema.ts +13 -0
- package/src/api/parameters/schemas/configHistoryResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/configNameParamSchema.ts +10 -0
- package/src/api/parameters/schemas/configNamesResponseSchema.ts +8 -0
- package/src/api/parameters/schemas/configTreeNodeSchema.ts +13 -0
- package/src/api/parameters/schemas/configVersionParamSchema.ts +9 -0
- package/src/api/parameters/schemas/configVersionResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/configsByStatusResponseSchema.ts +9 -0
- package/src/api/parameters/schemas/createConfigVersionBodySchema.ts +24 -0
- package/src/api/parameters/schemas/index.ts +15 -0
- package/src/api/parameters/schemas/parameterResponseSchema.ts +26 -0
- package/src/api/parameters/schemas/parameterStatusSchema.ts +13 -0
- package/src/api/parameters/schemas/rollbackConfigBodySchema.ts +15 -0
- package/src/api/parameters/schemas/statusParamSchema.ts +9 -0
- package/src/api/users/__tests__/EmailVerification.spec.ts +369 -0
- package/src/api/users/__tests__/PasswordReset.spec.ts +550 -0
- package/src/api/users/controllers/AdminIdentityController.spec.ts +365 -0
- package/src/api/users/controllers/{IdentityController.ts → AdminIdentityController.ts} +3 -4
- package/src/api/users/controllers/AdminSessionController.spec.ts +274 -0
- package/src/api/users/controllers/{SessionController.ts → AdminSessionController.ts} +3 -4
- package/src/api/users/controllers/AdminUserController.spec.ts +372 -0
- package/src/api/users/controllers/AdminUserController.ts +116 -0
- package/src/api/users/controllers/UserController.ts +4 -107
- package/src/api/users/controllers/UserRealmController.ts +3 -0
- package/src/api/users/entities/identities.ts +6 -6
- package/src/api/users/entities/sessions.ts +6 -6
- package/src/api/users/entities/users.ts +9 -9
- package/src/api/users/index.ts +13 -6
- package/src/api/users/primitives/$userRealm.ts +13 -8
- package/src/api/users/services/CredentialService.spec.ts +509 -0
- package/src/api/users/services/CredentialService.ts +46 -0
- package/src/api/users/services/IdentityService.ts +15 -0
- package/src/api/users/services/RegistrationService.spec.ts +630 -0
- package/src/api/users/services/RegistrationService.ts +18 -0
- package/src/api/users/services/SessionService.spec.ts +301 -0
- package/src/api/users/services/SessionService.ts +110 -1
- package/src/api/users/services/UserService.ts +67 -2
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +318 -0
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +279 -0
- package/src/api/verifications/entities/verifications.ts +6 -6
- package/src/api/verifications/jobs/VerificationJobs.spec.ts +50 -0
- package/src/batch/__tests__/startup-buffering.spec.ts +458 -0
- package/src/batch/primitives/$batch.spec.ts +766 -0
- package/src/batch/providers/BatchProvider.spec.ts +786 -0
- package/src/bin/index.ts +0 -1
- package/src/bucket/__tests__/shared.ts +194 -0
- package/src/bucket/primitives/$bucket.spec.ts +104 -0
- package/src/bucket/providers/FileStorageProvider.spec.ts +13 -0
- package/src/bucket/providers/LocalFileStorageProvider.spec.ts +77 -0
- package/src/bucket/providers/MemoryFileStorageProvider.spec.ts +82 -0
- package/src/cache/core/__tests__/shared.ts +377 -0
- package/src/cache/core/primitives/$cache.spec.ts +111 -0
- package/src/cache/redis/__tests__/cache-redis.spec.ts +70 -0
- package/src/cli/apps/AlephaCli.ts +54 -16
- package/src/cli/apps/AlephaPackageBuilderCli.ts +2 -1
- package/src/cli/assets/appRouterTs.ts +1 -1
- package/src/cli/commands/{ViteCommands.ts → build.ts} +2 -105
- package/src/cli/commands/clean.ts +14 -0
- package/src/cli/commands/{DrizzleCommands.ts → db.ts} +10 -117
- package/src/cli/commands/{DeployCommands.ts → deploy.ts} +1 -1
- package/src/cli/commands/dev.ts +69 -0
- package/src/cli/commands/format.ts +17 -0
- package/src/cli/commands/gen/changelog.spec.ts +315 -0
- package/src/cli/commands/{ChangelogCommands.ts → gen/changelog.ts} +16 -31
- package/src/cli/commands/gen/openapi.ts +71 -0
- package/src/cli/commands/gen.ts +18 -0
- package/src/cli/commands/{CoreCommands.ts → init.ts} +4 -40
- package/src/cli/commands/lint.ts +17 -0
- package/src/cli/commands/root.ts +41 -0
- package/src/cli/commands/run.ts +24 -0
- package/src/cli/commands/test.ts +42 -0
- package/src/cli/commands/typecheck.ts +24 -0
- package/src/cli/commands/{VerifyCommands.ts → verify.ts} +1 -13
- package/src/cli/defineConfig.ts +10 -1
- package/src/cli/index.ts +17 -7
- package/src/cli/services/AlephaCliUtils.ts +71 -32
- package/src/cli/services/GitMessageParser.ts +1 -1
- package/src/command/helpers/Asker.spec.ts +127 -0
- package/src/command/helpers/Runner.spec.ts +126 -0
- package/src/command/primitives/$command.spec.ts +1588 -0
- package/src/command/providers/CliProvider.ts +74 -24
- package/src/core/Alepha.ts +52 -4
- package/src/core/__tests__/Alepha-emit.spec.ts +22 -0
- package/src/core/__tests__/Alepha-graph.spec.ts +93 -0
- package/src/core/__tests__/Alepha-has.spec.ts +41 -0
- package/src/core/__tests__/Alepha-inject.spec.ts +93 -0
- package/src/core/__tests__/Alepha-register.spec.ts +81 -0
- package/src/core/__tests__/Alepha-start.spec.ts +176 -0
- package/src/core/__tests__/Alepha-with.spec.ts +14 -0
- package/src/core/__tests__/TypeBox-usecases.spec.ts +35 -0
- package/src/core/__tests__/TypeBoxLocale.spec.ts +15 -0
- package/src/core/__tests__/descriptor.spec.ts +34 -0
- package/src/core/__tests__/fixtures/A.ts +5 -0
- package/src/core/__tests__/pagination.spec.ts +77 -0
- package/src/core/helpers/jsonSchemaToTypeBox.ts +2 -2
- package/src/core/primitives/$atom.spec.ts +43 -0
- package/src/core/primitives/$hook.spec.ts +130 -0
- package/src/core/primitives/$inject.spec.ts +175 -0
- package/src/core/primitives/$module.spec.ts +115 -0
- package/src/core/providers/CodecManager.spec.ts +740 -0
- package/src/core/providers/EventManager.spec.ts +762 -0
- package/src/core/providers/EventManager.ts +4 -0
- package/src/core/providers/StateManager.spec.ts +365 -0
- package/src/core/providers/TypeProvider.spec.ts +1607 -0
- package/src/core/providers/TypeProvider.ts +20 -26
- package/src/datetime/primitives/$interval.spec.ts +103 -0
- package/src/datetime/providers/DateTimeProvider.spec.ts +86 -0
- package/src/email/primitives/$email.spec.ts +175 -0
- package/src/email/providers/LocalEmailProvider.spec.ts +341 -0
- package/src/fake/__tests__/keyName.example.ts +40 -0
- package/src/fake/__tests__/keyName.spec.ts +152 -0
- package/src/fake/__tests__/module.example.ts +32 -0
- package/src/fake/providers/FakeProvider.spec.ts +438 -0
- package/src/file/providers/FileSystemProvider.ts +8 -0
- package/src/file/providers/NodeFileSystemProvider.spec.ts +418 -0
- package/src/file/providers/NodeFileSystemProvider.ts +5 -0
- package/src/file/services/FileDetector.spec.ts +591 -0
- package/src/lock/core/__tests__/shared.ts +190 -0
- package/src/lock/core/providers/MemoryLockProvider.spec.ts +25 -0
- package/src/lock/redis/providers/RedisLockProvider.spec.ts +25 -0
- package/src/logger/__tests__/SimpleFormatterProvider.spec.ts +109 -0
- package/src/logger/primitives/$logger.spec.ts +108 -0
- package/src/logger/services/Logger.spec.ts +295 -0
- package/src/mcp/__tests__/errors.spec.ts +175 -0
- package/src/mcp/__tests__/integration.spec.ts +450 -0
- package/src/mcp/helpers/jsonrpc.spec.ts +380 -0
- package/src/mcp/primitives/$prompt.spec.ts +468 -0
- package/src/mcp/primitives/$resource.spec.ts +390 -0
- package/src/mcp/primitives/$tool.spec.ts +406 -0
- package/src/mcp/providers/McpServerProvider.spec.ts +797 -0
- package/src/orm/__tests__/$repository-crud.spec.ts +276 -0
- package/src/orm/__tests__/$repository-hooks.spec.ts +325 -0
- package/src/orm/__tests__/$repository-orderBy.spec.ts +128 -0
- package/src/orm/__tests__/$repository-pagination-sort.spec.ts +149 -0
- package/src/orm/__tests__/$repository-save.spec.ts +37 -0
- package/src/orm/__tests__/ModelBuilder-integration.spec.ts +490 -0
- package/src/orm/__tests__/ModelBuilder-types.spec.ts +186 -0
- package/src/orm/__tests__/PostgresProvider.spec.ts +46 -0
- package/src/orm/__tests__/delete-returning.spec.ts +256 -0
- package/src/orm/__tests__/deletedAt.spec.ts +80 -0
- package/src/orm/__tests__/enums.spec.ts +315 -0
- package/src/orm/__tests__/execute.spec.ts +72 -0
- package/src/orm/__tests__/fixtures/bigEntitySchema.ts +65 -0
- package/src/orm/__tests__/fixtures/userEntitySchema.ts +27 -0
- package/src/orm/__tests__/joins.spec.ts +1114 -0
- package/src/orm/__tests__/page.spec.ts +287 -0
- package/src/orm/__tests__/primaryKey.spec.ts +87 -0
- package/src/orm/__tests__/query-date-encoding.spec.ts +402 -0
- package/src/orm/__tests__/ref-auto-onDelete.spec.ts +156 -0
- package/src/orm/__tests__/references.spec.ts +102 -0
- package/src/orm/__tests__/security.spec.ts +710 -0
- package/src/orm/__tests__/sqlite.spec.ts +111 -0
- package/src/orm/__tests__/string-operators.spec.ts +429 -0
- package/src/orm/__tests__/timestamps.spec.ts +388 -0
- package/src/orm/__tests__/validation.spec.ts +183 -0
- package/src/orm/__tests__/version.spec.ts +64 -0
- package/src/orm/helpers/parseQueryString.spec.ts +196 -0
- package/src/orm/index.browser.ts +1 -1
- package/src/orm/index.ts +10 -6
- package/src/orm/primitives/$repository.spec.ts +137 -0
- package/src/orm/primitives/$sequence.spec.ts +29 -0
- package/src/orm/primitives/$transaction.spec.ts +82 -0
- package/src/orm/providers/{PostgresTypeProvider.ts → DatabaseTypeProvider.ts} +25 -3
- package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -3
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +1 -1
- package/src/orm/providers/drivers/DatabaseProvider.ts +1 -1
- package/src/orm/providers/drivers/NodePostgresProvider.ts +3 -3
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/PglitePostgresProvider.ts +2 -2
- package/src/orm/services/ModelBuilder.spec.ts +575 -0
- package/src/orm/services/Repository.spec.ts +137 -0
- package/src/queue/core/__tests__/shared.ts +143 -0
- package/src/queue/core/providers/MemoryQueueProvider.spec.ts +23 -0
- package/src/queue/core/providers/WorkerProvider.spec.ts +378 -0
- package/src/queue/redis/providers/RedisQueueProvider.spec.ts +23 -0
- package/src/redis/__tests__/redis.spec.ts +58 -0
- package/src/retry/primitives/$retry.spec.ts +234 -0
- package/src/retry/providers/RetryProvider.spec.ts +438 -0
- package/src/router/__tests__/match.spec.ts +252 -0
- package/src/router/providers/RouterProvider.spec.ts +197 -0
- package/src/scheduler/__tests__/$scheduler-cron.spec.ts +25 -0
- package/src/scheduler/__tests__/$scheduler-interval.spec.ts +25 -0
- package/src/scheduler/__tests__/shared.ts +77 -0
- package/src/security/__tests__/bug-1-wildcard-after-start.spec.ts +229 -0
- package/src/security/__tests__/bug-2-password-validation.spec.ts +245 -0
- package/src/security/__tests__/bug-3-regex-vulnerability.spec.ts +407 -0
- package/src/security/__tests__/bug-4-oauth2-validation.spec.ts +439 -0
- package/src/security/__tests__/multi-layer-permissions.spec.ts +522 -0
- package/src/security/primitives/$permission.spec.ts +30 -0
- package/src/security/primitives/$permission.ts +2 -2
- package/src/security/primitives/$realm.spec.ts +101 -0
- package/src/security/primitives/$role.spec.ts +52 -0
- package/src/security/primitives/$serviceAccount.spec.ts +61 -0
- package/src/security/providers/SecurityProvider.spec.ts +350 -0
- package/src/server/auth/providers/ServerAuthProvider.ts +0 -2
- package/src/server/cache/providers/ServerCacheProvider.spec.ts +942 -0
- package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
- package/src/server/compress/providers/ServerCompressProvider.ts +2 -0
- package/src/server/cookies/providers/ServerCookiesProvider.spec.ts +253 -0
- package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +334 -0
- package/src/server/core/__tests__/ServerRouterProvider-requestId.spec.ts +129 -0
- package/src/server/core/primitives/$action.spec.ts +191 -0
- package/src/server/core/primitives/$route.spec.ts +65 -0
- package/src/server/core/providers/ServerBodyParserProvider.spec.ts +93 -0
- package/src/server/core/providers/ServerLoggerProvider.spec.ts +100 -0
- package/src/server/core/providers/ServerProvider.ts +3 -1
- package/src/server/core/services/HttpClient.spec.ts +123 -0
- package/src/server/core/services/UserAgentParser.spec.ts +111 -0
- package/src/server/cors/providers/ServerCorsProvider.spec.ts +481 -0
- package/src/server/health/providers/ServerHealthProvider.spec.ts +22 -0
- package/src/server/helmet/providers/ServerHelmetProvider.spec.ts +105 -0
- package/src/server/links/__tests__/$action.spec.ts +238 -0
- package/src/server/links/__tests__/fixtures/CrudApp.ts +122 -0
- package/src/server/links/__tests__/requestId.spec.ts +120 -0
- package/src/server/links/primitives/$remote.spec.ts +228 -0
- package/src/server/links/providers/LinkProvider.spec.ts +54 -0
- package/src/server/links/providers/LinkProvider.ts +49 -3
- package/src/server/links/providers/ServerLinksProvider.ts +1 -53
- package/src/server/links/schemas/apiLinksResponseSchema.ts +7 -0
- package/src/server/metrics/providers/ServerMetricsProvider.spec.ts +25 -0
- package/src/server/multipart/providers/ServerMultipartProvider.spec.ts +528 -0
- package/src/server/proxy/primitives/$proxy.spec.ts +87 -0
- package/src/server/rate-limit/__tests__/ActionRateLimit.spec.ts +211 -0
- package/src/server/rate-limit/providers/ServerRateLimitProvider.spec.ts +344 -0
- package/src/server/security/__tests__/BasicAuth.spec.ts +684 -0
- package/src/server/security/__tests__/ServerSecurityProvider-realm.spec.ts +388 -0
- package/src/server/security/providers/ServerSecurityProvider.spec.ts +123 -0
- package/src/server/static/primitives/$serve.spec.ts +193 -0
- package/src/server/swagger/__tests__/ui.spec.ts +52 -0
- package/src/server/swagger/primitives/$swagger.spec.ts +193 -0
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +18 -8
- package/src/sms/primitives/$sms.spec.ts +165 -0
- package/src/sms/providers/LocalSmsProvider.spec.ts +224 -0
- package/src/sms/providers/MemorySmsProvider.spec.ts +193 -0
- package/src/thread/primitives/$thread.spec.ts +186 -0
- package/src/topic/core/__tests__/shared.ts +144 -0
- package/src/topic/core/providers/MemoryTopicProvider.spec.ts +23 -0
- package/src/topic/redis/providers/RedisTopicProvider.spec.ts +23 -0
- package/src/vite/plugins/viteAlephaDev.ts +16 -4
- package/src/vite/tasks/runAlepha.ts +7 -1
- package/src/websocket/__tests__/$websocket-new.spec.ts +195 -0
- package/src/websocket/primitives/$channel.spec.ts +30 -0
- package/src/cli/commands/BiomeCommands.ts +0 -29
package/dist/cli/index.js
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
|
-
import {
|
|
3
|
-
import { $atom, $env, $hook, $inject, $module, $use, Alepha, AlephaError, OPTIONS, t } from "alepha";
|
|
2
|
+
import { $atom, $hook, $inject, $module, $use, Alepha, AlephaError, OPTIONS, t } from "alepha";
|
|
4
3
|
import { FileSystemProvider } from "alepha/file";
|
|
5
|
-
import { $command, CliProvider, EnvUtils } from "alepha/command";
|
|
6
|
-
import { $logger } from "alepha/logger";
|
|
7
|
-
import { exec, spawn } from "node:child_process";
|
|
8
4
|
import { access, mkdir, readFile, readdir, unlink, writeFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
import { $command, CliProvider, EnvUtils } from "alepha/command";
|
|
7
|
+
import { $logger, ConsoleColorProvider } from "alepha/logger";
|
|
9
8
|
import { boot, buildClient, buildServer, copyAssets, generateCloudflare, generateDocker, generateSitemap, generateVercel, prerenderPages } from "alepha/vite";
|
|
10
|
-
import {
|
|
9
|
+
import { exec, spawn } from "node:child_process";
|
|
11
10
|
import { readFileSync } from "node:fs";
|
|
12
11
|
import { promisify } from "node:util";
|
|
12
|
+
import { ServerSwaggerProvider } from "alepha/server/swagger";
|
|
13
13
|
import * as os from "node:os";
|
|
14
14
|
|
|
15
15
|
//#region ../../src/cli/assets/appRouterTs.ts
|
|
16
16
|
const appRouterTs = () => `
|
|
17
|
-
import { $page } from "@alepha/react";
|
|
17
|
+
import { $page } from "@alepha/react/router";
|
|
18
18
|
|
|
19
19
|
export class AppRouter {
|
|
20
20
|
home = $page({
|
|
@@ -174,6 +174,7 @@ var AlephaCliUtils = class {
|
|
|
174
174
|
log = $logger();
|
|
175
175
|
fs = $inject(FileSystemProvider);
|
|
176
176
|
envUtils = $inject(EnvUtils);
|
|
177
|
+
alepha = $inject(Alepha);
|
|
177
178
|
/**
|
|
178
179
|
* Execute a command using npx with inherited stdio.
|
|
179
180
|
*
|
|
@@ -235,6 +236,34 @@ var AlephaCliUtils = class {
|
|
|
235
236
|
this.log.debug(`Config file written: ${path}`);
|
|
236
237
|
return path;
|
|
237
238
|
}
|
|
239
|
+
async removeFiles(root, files) {
|
|
240
|
+
await Promise.all(files.map((file) => this.fs.rm(join(root, file), {
|
|
241
|
+
force: true,
|
|
242
|
+
recursive: true
|
|
243
|
+
})));
|
|
244
|
+
}
|
|
245
|
+
async removeYarn(root) {
|
|
246
|
+
await this.removeFiles(root, [
|
|
247
|
+
".yarn",
|
|
248
|
+
".yarnrc.yml",
|
|
249
|
+
".yarn"
|
|
250
|
+
]);
|
|
251
|
+
}
|
|
252
|
+
async removePnpm(root) {
|
|
253
|
+
await this.removeFiles(root, ["pnpm-lock.yaml", "pnpm-workspace.yaml"]);
|
|
254
|
+
}
|
|
255
|
+
async removeNpm(root) {
|
|
256
|
+
await this.removeFiles(root, ["package-lock.json"]);
|
|
257
|
+
}
|
|
258
|
+
async removeBun(root) {
|
|
259
|
+
await this.removeFiles(root, ["bun.lockb"]);
|
|
260
|
+
}
|
|
261
|
+
async removeAllPmFilesExcept(root, except) {
|
|
262
|
+
if (except !== "yarn") await this.removeYarn(root);
|
|
263
|
+
if (except !== "pnpm") await this.removePnpm(root);
|
|
264
|
+
if (except !== "npm") await this.removeNpm(root);
|
|
265
|
+
if (except !== "bun") await this.removeBun(root);
|
|
266
|
+
}
|
|
238
267
|
/**
|
|
239
268
|
* Ensure Yarn is configured in the project directory.
|
|
240
269
|
*
|
|
@@ -244,26 +273,16 @@ var AlephaCliUtils = class {
|
|
|
244
273
|
*/
|
|
245
274
|
async ensureYarn(root) {
|
|
246
275
|
await this.ensureFileExists(root, ".yarnrc.yml", "nodeLinker: node-modules", false);
|
|
247
|
-
await this.
|
|
248
|
-
|
|
276
|
+
await this.removeAllPmFilesExcept(root, "yarn");
|
|
277
|
+
}
|
|
278
|
+
async ensureBun(root) {
|
|
279
|
+
await this.removeAllPmFilesExcept(root, "bun");
|
|
249
280
|
}
|
|
250
281
|
async ensurePnpm(root) {
|
|
251
|
-
await this.
|
|
252
|
-
await this.fs.rm(join(root, "yarn.lock"), { force: true });
|
|
253
|
-
await this.fs.rm(join(root, ".yarn"), {
|
|
254
|
-
force: true,
|
|
255
|
-
recursive: true
|
|
256
|
-
});
|
|
257
|
-
await this.fs.rm(join(root, ".yarnrc.yml"), { force: true });
|
|
282
|
+
await this.removeAllPmFilesExcept(root, "pnpm");
|
|
258
283
|
}
|
|
259
284
|
async ensureNpm(root) {
|
|
260
|
-
await this.
|
|
261
|
-
await this.fs.rm(join(root, "yarn.lock"), { force: true });
|
|
262
|
-
await this.fs.rm(join(root, ".yarn"), {
|
|
263
|
-
force: true,
|
|
264
|
-
recursive: true
|
|
265
|
-
});
|
|
266
|
-
await this.fs.rm(join(root, ".yarnrc.yml"), { force: true });
|
|
285
|
+
await this.removeAllPmFilesExcept(root, "npm");
|
|
267
286
|
}
|
|
268
287
|
/**
|
|
269
288
|
* Generate package.json content with Alepha dependencies.
|
|
@@ -418,7 +437,8 @@ var AlephaCliUtils = class {
|
|
|
418
437
|
async loadAlephaFromServerEntryFile(rootDir, explicitEntry) {
|
|
419
438
|
process.env.ALEPHA_CLI_IMPORT = "true";
|
|
420
439
|
const entry = await boot.getServerEntry(rootDir, explicitEntry);
|
|
421
|
-
|
|
440
|
+
delete global.__alepha;
|
|
441
|
+
const mod = await import(entry);
|
|
422
442
|
this.log.debug(`Load entry: ${entry}`);
|
|
423
443
|
if (mod.default instanceof Alepha) return {
|
|
424
444
|
alepha: mod.default,
|
|
@@ -470,6 +490,7 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
|
|
|
470
490
|
if (flags?.pnpm) return "pnpm";
|
|
471
491
|
if (flags?.npm) return "npm";
|
|
472
492
|
if (flags?.bun) return "bun";
|
|
493
|
+
if (this.alepha.isBun()) return "bun";
|
|
473
494
|
if (await this.checkFileExists(root, "yarn.lock", true)) return "yarn";
|
|
474
495
|
if (await this.checkFileExists(root, "pnpm-lock.yaml", true)) return "pnpm";
|
|
475
496
|
return "npm";
|
|
@@ -554,6 +575,23 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
|
|
|
554
575
|
async hasExpo(root) {
|
|
555
576
|
return this.hasDependency(root, "expo");
|
|
556
577
|
}
|
|
578
|
+
async getInstallCommand(root, packageName, dev = true) {
|
|
579
|
+
const pm = await this.getPackageManager(root);
|
|
580
|
+
let cmd;
|
|
581
|
+
switch (pm) {
|
|
582
|
+
case "yarn":
|
|
583
|
+
cmd = `yarn add ${dev ? "-D" : ""} ${packageName}`;
|
|
584
|
+
break;
|
|
585
|
+
case "pnpm":
|
|
586
|
+
cmd = `pnpm add ${dev ? "-D" : ""} ${packageName}`;
|
|
587
|
+
break;
|
|
588
|
+
case "bun":
|
|
589
|
+
cmd = `bun add ${dev ? "-d" : ""} ${packageName}`;
|
|
590
|
+
break;
|
|
591
|
+
default: cmd = `npm install ${dev ? "--save-dev" : ""} ${packageName}`;
|
|
592
|
+
}
|
|
593
|
+
return cmd.replace(/\s+/g, " ").trim();
|
|
594
|
+
}
|
|
557
595
|
/**
|
|
558
596
|
* Install a dependency if it's missing from the project.
|
|
559
597
|
*
|
|
@@ -566,18 +604,7 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
|
|
|
566
604
|
this.log.debug(`Dependency '${packageName}' is already installed`);
|
|
567
605
|
return;
|
|
568
606
|
}
|
|
569
|
-
const
|
|
570
|
-
let cmd;
|
|
571
|
-
switch (pm) {
|
|
572
|
-
case "yarn":
|
|
573
|
-
cmd = `yarn add ${dev ? "-D" : ""} ${packageName}`;
|
|
574
|
-
break;
|
|
575
|
-
case "pnpm":
|
|
576
|
-
cmd = `pnpm add ${dev ? "-D" : ""} ${packageName}`;
|
|
577
|
-
break;
|
|
578
|
-
default: cmd = `npm install ${dev ? "--save-dev" : ""} ${packageName}`;
|
|
579
|
-
}
|
|
580
|
-
cmd = cmd.replace(/\s+/g, " ").trim();
|
|
607
|
+
const cmd = await this.getInstallCommand(root, packageName, dev);
|
|
581
608
|
if (options.run) await options.run(cmd, { alias: `installing ${packageName}` });
|
|
582
609
|
else {
|
|
583
610
|
this.log.debug(`Installing ${packageName}`);
|
|
@@ -587,337 +614,415 @@ ${models.map((it) => `export const ${it} = models["${it}"];`).join("\n")}
|
|
|
587
614
|
};
|
|
588
615
|
|
|
589
616
|
//#endregion
|
|
590
|
-
//#region ../../src/cli/commands/
|
|
591
|
-
var
|
|
617
|
+
//#region ../../src/cli/commands/build.ts
|
|
618
|
+
var BuildCommand = class {
|
|
592
619
|
log = $logger();
|
|
593
620
|
utils = $inject(AlephaCliUtils);
|
|
594
|
-
|
|
595
|
-
name: "
|
|
596
|
-
description: "
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
621
|
+
build = $command({
|
|
622
|
+
name: "build",
|
|
623
|
+
description: "Build the project for production",
|
|
624
|
+
args: t.optional(t.text({
|
|
625
|
+
title: "path",
|
|
626
|
+
description: "Filepath to build"
|
|
627
|
+
})),
|
|
628
|
+
flags: t.object({
|
|
629
|
+
stats: t.optional(t.boolean({ description: "Generate build stats report" })),
|
|
630
|
+
vercel: t.optional(t.boolean({ description: "Generate Vercel deployment configuration" })),
|
|
631
|
+
cloudflare: t.optional(t.boolean({ description: "Generate Cloudflare Workers configuration" })),
|
|
632
|
+
docker: t.optional(t.boolean({ description: "Generate Docker configuration" })),
|
|
633
|
+
sitemap: t.optional(t.text({ description: "Generate sitemap.xml with base URL" }))
|
|
634
|
+
}),
|
|
635
|
+
handler: async ({ flags, args, run, root }) => {
|
|
636
|
+
process.env.ALEPHA_BUILD_MODE = "cli";
|
|
637
|
+
process.env.NODE_ENV = "production";
|
|
638
|
+
if (await this.utils.hasExpo(root)) return;
|
|
639
|
+
await this.utils.ensureConfig(root, {
|
|
640
|
+
viteConfigTs: true,
|
|
641
|
+
tsconfigJson: true
|
|
642
|
+
});
|
|
643
|
+
const entry = await boot.getServerEntry(root, args);
|
|
644
|
+
this.log.trace("Entry file found", { entry });
|
|
645
|
+
const distDir = "dist";
|
|
646
|
+
const clientDir = "public";
|
|
647
|
+
await this.utils.ensureDependency(root, "vite", { run });
|
|
648
|
+
await run.rm("dist", { alias: "clean dist" });
|
|
649
|
+
const viteAlephaBuildOptions = (await createRequire(import.meta.url)("vite").resolveConfig({}, "build", "production")).plugins.find((it) => it.name === "alepha:build")?.[OPTIONS] || {};
|
|
650
|
+
await this.utils.loadEnv(root, [".env", ".env.production"]);
|
|
651
|
+
const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
|
|
652
|
+
const hasServer = viteAlephaBuildOptions.serverEntry !== false;
|
|
653
|
+
let hasClient = false;
|
|
654
|
+
try {
|
|
655
|
+
await access(join(root, "index.html"));
|
|
656
|
+
hasClient = true;
|
|
657
|
+
} catch {}
|
|
658
|
+
const clientOptions = typeof viteAlephaBuildOptions.client === "object" ? viteAlephaBuildOptions.client : {};
|
|
659
|
+
if (hasClient) await run({
|
|
660
|
+
name: "vite build client",
|
|
661
|
+
handler: () => buildClient({
|
|
662
|
+
silent: true,
|
|
663
|
+
dist: `${distDir}/${clientDir}`,
|
|
664
|
+
stats,
|
|
665
|
+
precompress: clientOptions.precompress
|
|
666
|
+
})
|
|
667
|
+
});
|
|
668
|
+
await run({
|
|
669
|
+
name: "vite build server",
|
|
670
|
+
handler: async () => {
|
|
671
|
+
let clientBuilt = false;
|
|
672
|
+
try {
|
|
673
|
+
await readFile(`${distDir}/${clientDir}/index.html`, "utf-8");
|
|
674
|
+
clientBuilt = true;
|
|
675
|
+
} catch {}
|
|
676
|
+
await buildServer({
|
|
677
|
+
silent: true,
|
|
678
|
+
entry,
|
|
679
|
+
distDir,
|
|
680
|
+
clientDir: clientBuilt ? clientDir : void 0,
|
|
681
|
+
stats
|
|
682
|
+
});
|
|
683
|
+
if (clientBuilt && hasServer) await unlink(`${distDir}/${clientDir}/index.html`);
|
|
684
|
+
}
|
|
685
|
+
});
|
|
686
|
+
await copyAssets({
|
|
687
|
+
root,
|
|
688
|
+
entry: `${distDir}/index.js`,
|
|
689
|
+
distDir,
|
|
690
|
+
run
|
|
691
|
+
});
|
|
692
|
+
if (hasClient) {
|
|
693
|
+
const sitemapBaseUrl = flags.sitemap ?? clientOptions.sitemap?.hostname;
|
|
694
|
+
if (sitemapBaseUrl) await run({
|
|
695
|
+
name: "add sitemap",
|
|
696
|
+
handler: async () => {
|
|
697
|
+
await writeFile(`${distDir}/${clientDir}/sitemap.xml`, await generateSitemap({
|
|
698
|
+
entry: `${distDir}/index.js`,
|
|
699
|
+
baseUrl: sitemapBaseUrl
|
|
700
|
+
}));
|
|
701
|
+
}
|
|
702
|
+
});
|
|
703
|
+
if (clientOptions.prerender) await run({
|
|
704
|
+
name: "pre-render pages",
|
|
705
|
+
handler: async () => {
|
|
706
|
+
await prerenderPages({
|
|
707
|
+
dist: `${distDir}/${clientDir}`,
|
|
708
|
+
entry: `${distDir}/index.js`,
|
|
709
|
+
compress: clientOptions.precompress
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
}
|
|
714
|
+
if (flags.vercel || viteAlephaBuildOptions.vercel) {
|
|
715
|
+
const config = typeof viteAlephaBuildOptions.vercel === "object" ? viteAlephaBuildOptions.vercel : {};
|
|
716
|
+
await run({
|
|
717
|
+
name: "add Vercel config",
|
|
718
|
+
handler: () => generateVercel({
|
|
719
|
+
distDir,
|
|
720
|
+
clientDir,
|
|
721
|
+
config
|
|
722
|
+
})
|
|
723
|
+
});
|
|
724
|
+
}
|
|
725
|
+
if (flags.cloudflare || viteAlephaBuildOptions.cloudflare) {
|
|
726
|
+
const config = typeof viteAlephaBuildOptions.cloudflare === "boolean" ? {} : viteAlephaBuildOptions.cloudflare;
|
|
727
|
+
await run({
|
|
728
|
+
name: "add Cloudflare config",
|
|
729
|
+
handler: () => generateCloudflare({
|
|
730
|
+
distDir,
|
|
731
|
+
config
|
|
732
|
+
})
|
|
733
|
+
});
|
|
734
|
+
}
|
|
735
|
+
if (flags.docker || viteAlephaBuildOptions.docker) {
|
|
736
|
+
const dockerConfig = typeof viteAlephaBuildOptions.docker === "object" ? viteAlephaBuildOptions.docker : {};
|
|
737
|
+
await run({
|
|
738
|
+
name: "add Docker config",
|
|
739
|
+
handler: () => generateDocker({
|
|
740
|
+
distDir,
|
|
741
|
+
...dockerConfig
|
|
742
|
+
})
|
|
743
|
+
});
|
|
744
|
+
}
|
|
601
745
|
}
|
|
602
746
|
});
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
747
|
+
};
|
|
748
|
+
|
|
749
|
+
//#endregion
|
|
750
|
+
//#region ../../src/cli/commands/clean.ts
|
|
751
|
+
var CleanCommand = class {
|
|
752
|
+
/**
|
|
753
|
+
* Clean the project, removing the "dist" directory
|
|
754
|
+
*/
|
|
755
|
+
clean = $command({
|
|
756
|
+
name: "clean",
|
|
757
|
+
description: "Clean the project",
|
|
758
|
+
handler: async ({ run }) => {
|
|
759
|
+
await run.rm("./dist");
|
|
610
760
|
}
|
|
611
761
|
});
|
|
612
762
|
};
|
|
613
763
|
|
|
614
764
|
//#endregion
|
|
615
|
-
//#region ../../src/cli/
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
*/
|
|
620
|
-
const DEFAULT_IGNORE = [
|
|
621
|
-
"project",
|
|
622
|
-
"release",
|
|
623
|
-
"starter",
|
|
624
|
-
"example",
|
|
625
|
-
"chore",
|
|
626
|
-
"ci",
|
|
627
|
-
"build",
|
|
628
|
-
"test",
|
|
629
|
-
"style"
|
|
630
|
-
];
|
|
631
|
-
/**
|
|
632
|
-
* Changelog configuration atom.
|
|
633
|
-
*
|
|
634
|
-
* Configure in `alepha.config.ts`:
|
|
635
|
-
* ```ts
|
|
636
|
-
* import { changelogOptions } from "alepha/cli";
|
|
637
|
-
*
|
|
638
|
-
* alepha.set(changelogOptions, {
|
|
639
|
-
* ignore: ["project", "release", "chore", "docs"],
|
|
640
|
-
* });
|
|
641
|
-
* ```
|
|
642
|
-
*/
|
|
643
|
-
const changelogOptions = $atom({
|
|
644
|
-
name: "alepha.changelog",
|
|
645
|
-
schema: t.object({ ignore: t.optional(t.array(t.string())) }),
|
|
646
|
-
default: { ignore: DEFAULT_IGNORE }
|
|
765
|
+
//#region ../../src/cli/commands/db.ts
|
|
766
|
+
const drizzleCommandFlags = t.object({
|
|
767
|
+
provider: t.optional(t.text({ description: "Database provider name to target (e.g., 'postgres', 'sqlite')" })),
|
|
768
|
+
mode: t.optional(t.text({ description: "Environment variable file(s) to load (e.g., 'production' to load .env.production) https://vite.dev/guide/env-and-mode" }))
|
|
647
769
|
});
|
|
648
|
-
|
|
649
|
-
//#endregion
|
|
650
|
-
//#region ../../src/cli/services/GitMessageParser.ts
|
|
651
|
-
/**
|
|
652
|
-
* Service for parsing git commit messages into structured format.
|
|
653
|
-
*
|
|
654
|
-
* Only parses **conventional commits with a scope**:
|
|
655
|
-
* - `feat(scope): description` → feature
|
|
656
|
-
* - `fix(scope): description` → bug fix
|
|
657
|
-
* - `feat(scope)!: description` → breaking change
|
|
658
|
-
*
|
|
659
|
-
* Commits without scope are ignored, allowing developers to commit
|
|
660
|
-
* work-in-progress changes without polluting release notes:
|
|
661
|
-
* - `cli: work in progress` → ignored (no type)
|
|
662
|
-
* - `fix: quick patch` → ignored (no scope)
|
|
663
|
-
* - `feat(cli): add command` → included
|
|
664
|
-
*/
|
|
665
|
-
var GitMessageParser = class {
|
|
770
|
+
var DbCommand = class {
|
|
666
771
|
log = $logger();
|
|
772
|
+
utils = $inject(AlephaCliUtils);
|
|
667
773
|
/**
|
|
668
|
-
*
|
|
669
|
-
*
|
|
670
|
-
* **Format:** `type(scope): description` or `type(scope)!: description`
|
|
671
|
-
*
|
|
672
|
-
* **Supported types:** feat, fix, docs, refactor, perf, revert
|
|
673
|
-
*
|
|
674
|
-
* **Breaking changes:** Use `!` before `:` (e.g., `feat(api)!: remove endpoint`)
|
|
675
|
-
*
|
|
676
|
-
* @returns Commit object or null if not matching/ignored
|
|
774
|
+
* Check if database migrations are up to date.
|
|
677
775
|
*/
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
if
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
* Format the changelog entry with sections.
|
|
735
|
-
*/
|
|
736
|
-
formatEntry(entry) {
|
|
737
|
-
const sections = [];
|
|
738
|
-
if (entry.breaking.length > 0) {
|
|
739
|
-
sections.push("### Breaking Changes\n");
|
|
740
|
-
for (const commit of entry.breaking) sections.push(this.formatCommit(commit));
|
|
741
|
-
sections.push("");
|
|
742
|
-
}
|
|
743
|
-
if (entry.features.length > 0) {
|
|
744
|
-
sections.push("### Features\n");
|
|
745
|
-
for (const commit of entry.features) sections.push(this.formatCommit(commit));
|
|
746
|
-
sections.push("");
|
|
747
|
-
}
|
|
748
|
-
if (entry.fixes.length > 0) {
|
|
749
|
-
sections.push("### Bug Fixes\n");
|
|
750
|
-
for (const commit of entry.fixes) sections.push(this.formatCommit(commit));
|
|
751
|
-
sections.push("");
|
|
776
|
+
check = $command({
|
|
777
|
+
name: "check-migrations",
|
|
778
|
+
description: "Check if database migration files are up to date",
|
|
779
|
+
args: t.optional(t.text({
|
|
780
|
+
title: "path",
|
|
781
|
+
description: "Path to the Alepha server entry file"
|
|
782
|
+
})),
|
|
783
|
+
flags: drizzleCommandFlags,
|
|
784
|
+
handler: async ({ args, root }) => {
|
|
785
|
+
const rootDir = root;
|
|
786
|
+
this.log.debug(`Using project root: ${rootDir}`);
|
|
787
|
+
const { alepha } = await this.utils.loadAlephaFromServerEntryFile(rootDir, args);
|
|
788
|
+
const repositoryProvider = alepha.inject("RepositoryProvider");
|
|
789
|
+
const drizzleKitProvider = alepha.inject("DrizzleKitProvider");
|
|
790
|
+
const accepted = /* @__PURE__ */ new Set([]);
|
|
791
|
+
for (const primitive of repositoryProvider.getRepositories()) {
|
|
792
|
+
const provider = primitive.provider;
|
|
793
|
+
const providerName = provider.name;
|
|
794
|
+
if (accepted.has(providerName)) continue;
|
|
795
|
+
accepted.add(providerName);
|
|
796
|
+
const migrationDir = join(rootDir, "migrations", providerName);
|
|
797
|
+
const journalFile = await readFile(`${migrationDir}/meta/_journal.json`, "utf-8").catch(() => null);
|
|
798
|
+
if (!journalFile) {
|
|
799
|
+
this.log.info("No migration journal found.");
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
const journal = JSON.parse(journalFile);
|
|
803
|
+
const lastMigration = journal.entries[journal.entries.length - 1];
|
|
804
|
+
const lastSnapshot = JSON.parse(await readFile(`${migrationDir}/meta/${String(lastMigration.idx).padStart(4, "0")}_snapshot.json`, "utf-8"));
|
|
805
|
+
const models = drizzleKitProvider.getModels(provider);
|
|
806
|
+
const kit = drizzleKitProvider.importDrizzleKit();
|
|
807
|
+
const now = kit.generateDrizzleJson(models, lastSnapshot.id);
|
|
808
|
+
const migrationStatements = await new Promise((resolve) => {
|
|
809
|
+
(async () => {
|
|
810
|
+
const timer = setTimeout(() => {
|
|
811
|
+
resolve([{ message: "Migration generation timed out." }]);
|
|
812
|
+
}, 5e3);
|
|
813
|
+
const statements = await kit.generateMigration(lastSnapshot, now);
|
|
814
|
+
clearTimeout(timer);
|
|
815
|
+
resolve(statements);
|
|
816
|
+
})();
|
|
817
|
+
});
|
|
818
|
+
if (migrationStatements.length === 0) {
|
|
819
|
+
this.log.info("No changes detected.");
|
|
820
|
+
return;
|
|
821
|
+
}
|
|
822
|
+
this.log.info("");
|
|
823
|
+
this.log.info("Detected migration statements:");
|
|
824
|
+
this.log.info("");
|
|
825
|
+
for (const stmt of migrationStatements) this.log.info(stmt);
|
|
826
|
+
this.log.info("");
|
|
827
|
+
this.log.info(`At least ${migrationStatements.length} change(s) detected.`);
|
|
828
|
+
this.log.info("Please, run 'alepha db:generate' to update the migration files.");
|
|
829
|
+
this.log.info("");
|
|
830
|
+
throw new AlephaError("Database migrations are not up to date.");
|
|
831
|
+
}
|
|
752
832
|
}
|
|
753
|
-
|
|
754
|
-
}
|
|
833
|
+
});
|
|
755
834
|
/**
|
|
756
|
-
*
|
|
835
|
+
* Generate database migration files
|
|
757
836
|
*/
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
837
|
+
generate = $command({
|
|
838
|
+
name: "generate",
|
|
839
|
+
description: "Generate migration files based on current database schema",
|
|
840
|
+
summary: false,
|
|
841
|
+
args: t.optional(t.text({
|
|
842
|
+
title: "path",
|
|
843
|
+
description: "Path to the Alepha server entry file"
|
|
844
|
+
})),
|
|
845
|
+
flags: t.extend(drizzleCommandFlags, { custom: t.optional(t.text({ description: "Custom migration name for drizzle-kit generate --custom" })) }),
|
|
846
|
+
handler: async ({ args, flags, root }) => {
|
|
847
|
+
const commandFlags = flags.custom ? `--custom=${flags.custom}` : void 0;
|
|
848
|
+
await this.runDrizzleKitCommand({
|
|
849
|
+
root,
|
|
850
|
+
args,
|
|
851
|
+
command: "generate",
|
|
852
|
+
commandFlags,
|
|
853
|
+
provider: flags.provider,
|
|
854
|
+
env: flags.mode,
|
|
855
|
+
logMessage: (providerName, dialect) => `Generate '${providerName}' migrations (${dialect}) ...`
|
|
856
|
+
});
|
|
775
857
|
}
|
|
776
|
-
|
|
777
|
-
}
|
|
858
|
+
});
|
|
778
859
|
/**
|
|
779
|
-
*
|
|
860
|
+
* Push database schema changes directly to the database
|
|
780
861
|
*/
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
862
|
+
push = $command({
|
|
863
|
+
name: "push",
|
|
864
|
+
description: "Push database schema changes directly to the database",
|
|
865
|
+
summary: false,
|
|
866
|
+
args: t.optional(t.text({
|
|
867
|
+
title: "path",
|
|
868
|
+
description: "Path to the Alepha server entry file"
|
|
869
|
+
})),
|
|
870
|
+
flags: drizzleCommandFlags,
|
|
871
|
+
handler: async ({ root, args, flags }) => {
|
|
872
|
+
await this.runDrizzleKitCommand({
|
|
873
|
+
root,
|
|
874
|
+
args,
|
|
875
|
+
command: "push",
|
|
876
|
+
provider: flags.provider,
|
|
877
|
+
env: flags.mode,
|
|
878
|
+
logMessage: (providerName, dialect) => `Push '${providerName}' schema (${dialect}) ...`
|
|
879
|
+
});
|
|
880
|
+
}
|
|
881
|
+
});
|
|
784
882
|
/**
|
|
785
|
-
*
|
|
883
|
+
* Apply pending database migrations
|
|
786
884
|
*/
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
let fromRef;
|
|
806
|
-
if (flags.from) {
|
|
807
|
-
fromRef = flags.from;
|
|
808
|
-
this.log.debug("Using specified from ref", { from: fromRef });
|
|
809
|
-
} else {
|
|
810
|
-
const latestTag = await this.getLatestTag(git);
|
|
811
|
-
if (!latestTag) {
|
|
812
|
-
process.stdout.write("No version tags found in repository\n");
|
|
813
|
-
return;
|
|
814
|
-
}
|
|
815
|
-
fromRef = latestTag;
|
|
816
|
-
this.log.debug("Using latest tag", { from: fromRef });
|
|
817
|
-
}
|
|
818
|
-
const toRef = flags.to || "HEAD";
|
|
819
|
-
this.log.debug("Using to ref", { to: toRef });
|
|
820
|
-
const commitsOutput = await git(`log ${fromRef}..${toRef} --oneline`);
|
|
821
|
-
if (!commitsOutput.trim()) {
|
|
822
|
-
process.stdout.write(`No changes in range ${fromRef}..${toRef}\n`);
|
|
823
|
-
return;
|
|
824
|
-
}
|
|
825
|
-
const entry = this.parseCommits(commitsOutput);
|
|
826
|
-
if (!this.hasChanges(entry)) {
|
|
827
|
-
process.stdout.write(`No public changes in range ${fromRef}..${toRef}\n`);
|
|
828
|
-
return;
|
|
829
|
-
}
|
|
830
|
-
process.stdout.write(this.formatEntry(entry));
|
|
885
|
+
migrate = $command({
|
|
886
|
+
name: "migrate",
|
|
887
|
+
description: "Apply pending database migrations",
|
|
888
|
+
summary: false,
|
|
889
|
+
args: t.optional(t.text({
|
|
890
|
+
title: "path",
|
|
891
|
+
description: "Path to the Alepha server entry file"
|
|
892
|
+
})),
|
|
893
|
+
flags: drizzleCommandFlags,
|
|
894
|
+
handler: async ({ root, args, flags }) => {
|
|
895
|
+
await this.runDrizzleKitCommand({
|
|
896
|
+
root,
|
|
897
|
+
args,
|
|
898
|
+
command: "migrate",
|
|
899
|
+
provider: flags.provider,
|
|
900
|
+
env: flags.mode,
|
|
901
|
+
logMessage: (providerName, dialect) => `Migrate '${providerName}' database (${dialect}) ...`
|
|
902
|
+
});
|
|
831
903
|
}
|
|
832
904
|
});
|
|
833
|
-
};
|
|
834
|
-
|
|
835
|
-
//#endregion
|
|
836
|
-
//#region ../../src/cli/commands/CoreCommands.ts
|
|
837
|
-
var CoreCommands = class {
|
|
838
|
-
log = $logger();
|
|
839
|
-
cli = $inject(CliProvider);
|
|
840
|
-
utils = $inject(AlephaCliUtils);
|
|
841
905
|
/**
|
|
842
|
-
*
|
|
906
|
+
* Launch Drizzle Studio database browser
|
|
843
907
|
*/
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
908
|
+
studio = $command({
|
|
909
|
+
name: "studio",
|
|
910
|
+
description: "Launch Drizzle Studio database browser",
|
|
911
|
+
summary: false,
|
|
912
|
+
args: t.optional(t.text({
|
|
913
|
+
title: "path",
|
|
914
|
+
description: "Path to the Alepha server entry file"
|
|
915
|
+
})),
|
|
916
|
+
flags: drizzleCommandFlags,
|
|
917
|
+
handler: async ({ root, args, flags }) => {
|
|
918
|
+
await this.runDrizzleKitCommand({
|
|
919
|
+
root,
|
|
920
|
+
args,
|
|
921
|
+
command: "studio",
|
|
922
|
+
provider: flags.provider,
|
|
923
|
+
env: flags.mode,
|
|
924
|
+
logMessage: (providerName, dialect) => `Launch Studio for '${providerName}' (${dialect}) ...`
|
|
925
|
+
});
|
|
856
926
|
}
|
|
857
927
|
});
|
|
858
928
|
/**
|
|
859
|
-
*
|
|
929
|
+
* Parent command for database operations.
|
|
860
930
|
*/
|
|
861
|
-
|
|
862
|
-
name: "
|
|
863
|
-
description: "
|
|
864
|
-
|
|
865
|
-
|
|
931
|
+
db = $command({
|
|
932
|
+
name: "db",
|
|
933
|
+
description: "Database management commands",
|
|
934
|
+
children: [
|
|
935
|
+
this.check,
|
|
936
|
+
this.generate,
|
|
937
|
+
this.push,
|
|
938
|
+
this.migrate,
|
|
939
|
+
this.studio
|
|
940
|
+
],
|
|
941
|
+
handler: async ({ help }) => {
|
|
942
|
+
help();
|
|
866
943
|
}
|
|
867
944
|
});
|
|
868
945
|
/**
|
|
869
|
-
*
|
|
870
|
-
* Add the correct dependencies to package.json and install them.
|
|
946
|
+
* Run a drizzle-kit command for all database providers in an Alepha instance.
|
|
871
947
|
*/
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
tsconfigJson: true,
|
|
892
|
-
packageJson: flags,
|
|
893
|
-
biomeJson: true,
|
|
894
|
-
viteConfigTs: !isExpo,
|
|
895
|
-
editorconfig: true,
|
|
896
|
-
indexHtml: !!flags.react && !isExpo
|
|
897
|
-
});
|
|
898
|
-
if (!flags.react) await this.utils.ensureSrcMain(root);
|
|
899
|
-
}
|
|
900
|
-
});
|
|
901
|
-
const pm = await this.utils.getPackageManager(root, flags);
|
|
902
|
-
if (pm === "yarn") {
|
|
903
|
-
await this.utils.ensureYarn(root);
|
|
904
|
-
await run("yarn set version stable");
|
|
905
|
-
} else if (pm === "pnpm") await this.utils.ensurePnpm(root);
|
|
906
|
-
else await this.utils.ensureNpm(root);
|
|
907
|
-
await run(`${pm} install`, { alias: `installing dependencies with ${pm}` });
|
|
908
|
-
if (!isExpo) await this.utils.ensureDependency(root, "vite", { run });
|
|
909
|
-
await this.utils.ensureDependency(root, "@biomejs/biome", { run });
|
|
910
|
-
if (flags.test) {
|
|
911
|
-
await this.utils.ensureTestDir(root);
|
|
912
|
-
await run(`${pm} ${pm === "yarn" ? "add" : "install"} -D vitest`, { alias: "setup testing with Vitest" });
|
|
948
|
+
async runDrizzleKitCommand(options) {
|
|
949
|
+
const rootDir = options.root;
|
|
950
|
+
const envFiles = [".env"];
|
|
951
|
+
if (options.env) envFiles.push(`.env.${options.env}`);
|
|
952
|
+
await this.utils.loadEnv(rootDir, envFiles);
|
|
953
|
+
this.log.debug(`Using project root: ${rootDir}`);
|
|
954
|
+
const { alepha, entry } = await this.utils.loadAlephaFromServerEntryFile(rootDir, options.args);
|
|
955
|
+
const drizzleKitProvider = alepha.inject("DrizzleKitProvider");
|
|
956
|
+
const repositoryProvider = alepha.inject("RepositoryProvider");
|
|
957
|
+
const accepted = /* @__PURE__ */ new Set([]);
|
|
958
|
+
for (const primitive of repositoryProvider.getRepositories()) {
|
|
959
|
+
const provider = primitive.provider;
|
|
960
|
+
const providerName = provider.name;
|
|
961
|
+
const dialect = provider.dialect;
|
|
962
|
+
if (accepted.has(providerName)) continue;
|
|
963
|
+
accepted.add(providerName);
|
|
964
|
+
if (options.provider && options.provider !== providerName) {
|
|
965
|
+
this.log.debug(`Skipping provider '${providerName}' (filter: ${options.provider})`);
|
|
966
|
+
continue;
|
|
913
967
|
}
|
|
968
|
+
this.log.info("");
|
|
969
|
+
this.log.info(options.logMessage(providerName, dialect));
|
|
970
|
+
const drizzleConfigJsPath = await this.prepareDrizzleConfig({
|
|
971
|
+
kit: drizzleKitProvider,
|
|
972
|
+
provider,
|
|
973
|
+
providerName,
|
|
974
|
+
providerUrl: provider.url,
|
|
975
|
+
dialect,
|
|
976
|
+
entry,
|
|
977
|
+
rootDir
|
|
978
|
+
});
|
|
979
|
+
const flags = options.commandFlags ? ` ${options.commandFlags}` : "";
|
|
980
|
+
await this.utils.exec(`drizzle-kit ${options.command} --config=${drizzleConfigJsPath}${flags}`, { env: { NODE_OPTIONS: "--import tsx" } });
|
|
914
981
|
}
|
|
915
|
-
}
|
|
982
|
+
}
|
|
983
|
+
/**
|
|
984
|
+
* Prepare Drizzle configuration files for a database provider.
|
|
985
|
+
*/
|
|
986
|
+
async prepareDrizzleConfig(options) {
|
|
987
|
+
const models = Object.keys(options.kit.getModels(options.provider));
|
|
988
|
+
const entitiesJs = this.utils.generateEntitiesJs(options.entry, options.providerName, models);
|
|
989
|
+
const config = {
|
|
990
|
+
schema: await this.utils.writeConfigFile("entities.js", entitiesJs, options.rootDir),
|
|
991
|
+
out: `./migrations/${options.providerName}`,
|
|
992
|
+
dialect: options.dialect,
|
|
993
|
+
dbCredentials: { url: options.providerUrl }
|
|
994
|
+
};
|
|
995
|
+
if (options.provider.schema) config.schemaFilter = options.provider.schema;
|
|
996
|
+
if (options.providerName === "d1") config.driver = "d1-http";
|
|
997
|
+
if (options.providerName === "pglite") config.driver = "pglite";
|
|
998
|
+
if (options.dialect === "sqlite") if (options.providerName === "d1") {
|
|
999
|
+
const token = process.env.CLOUDFLARE_API_TOKEN;
|
|
1000
|
+
if (!token) throw new AlephaError("CLOUDFLARE_API_TOKEN environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit");
|
|
1001
|
+
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
1002
|
+
if (!accountId) throw new AlephaError("CLOUDFLARE_ACCOUNT_ID environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit");
|
|
1003
|
+
const url = options.providerUrl;
|
|
1004
|
+
if (!url.startsWith("cloudflare-d1://")) throw new AlephaError("D1 provider URL must start with 'cloudflare-d1://'.");
|
|
1005
|
+
const [, databaseId] = url.replace("cloudflare-d1://", "").replace("cloudflare-d1:", "").split(":");
|
|
1006
|
+
if (!databaseId) throw new AlephaError("Database ID is missing in the D1 provider URL. Cloudflare D1 URL format: cloudflare-d1://<database_name>:<database_id>");
|
|
1007
|
+
config.dbCredentials = {
|
|
1008
|
+
accountId,
|
|
1009
|
+
databaseId,
|
|
1010
|
+
token
|
|
1011
|
+
};
|
|
1012
|
+
} else {
|
|
1013
|
+
let url = options.providerUrl;
|
|
1014
|
+
url = url.replace("sqlite://", "").replace("file://", "");
|
|
1015
|
+
url = join(options.rootDir, url);
|
|
1016
|
+
config.dbCredentials = { url };
|
|
1017
|
+
}
|
|
1018
|
+
const drizzleConfigJs = `export default ${JSON.stringify(config, null, 2)}`;
|
|
1019
|
+
return await this.utils.writeConfigFile("drizzle.config.js", drizzleConfigJs, options.rootDir);
|
|
1020
|
+
}
|
|
916
1021
|
};
|
|
917
1022
|
|
|
918
1023
|
//#endregion
|
|
919
|
-
//#region ../../src/cli/commands/
|
|
920
|
-
var
|
|
1024
|
+
//#region ../../src/cli/commands/deploy.ts
|
|
1025
|
+
var DeployCommand = class {
|
|
921
1026
|
log = $logger();
|
|
922
1027
|
utils = $inject(AlephaCliUtils);
|
|
923
1028
|
/**
|
|
@@ -974,369 +1079,470 @@ var DeployCommands = class {
|
|
|
974
1079
|
return;
|
|
975
1080
|
}
|
|
976
1081
|
if (await this.utils.exists(root, "dist/wrangler.jsonc")) {
|
|
977
|
-
if (flags.migrate) {
|
|
978
|
-
this.log.debug("Running database migrations before deployment...");
|
|
979
|
-
await this.utils.exec(`alepha db migrate --mode=${mode}`);
|
|
980
|
-
}
|
|
981
|
-
await this.utils.ensureDependency(root, "wrangler", { dev: true });
|
|
982
|
-
const command = `wrangler deploy ${mode === "production" ? "" : "--env preview"} --config=dist/wrangler.jsonc`.trim();
|
|
983
|
-
this.log.info(`Deploying to Cloudflare with command: ${command}`);
|
|
984
|
-
await this.utils.exec(command);
|
|
985
|
-
return;
|
|
986
|
-
}
|
|
987
|
-
if (await this.utils.exists(root, "dist/public/404.html")) {
|
|
988
|
-
await this.utils.ensureDependency(root, "surge", { dev: true });
|
|
989
|
-
const distPath = join(root, "dist/public");
|
|
990
|
-
this.log.debug(`Deploying to Surge from directory: ${distPath}`);
|
|
991
|
-
await this.utils.exec(`surge ${distPath}`);
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
throw new AlephaError("No deployment configuration found in the dist folder.");
|
|
995
|
-
}
|
|
996
|
-
});
|
|
997
|
-
};
|
|
998
|
-
|
|
999
|
-
//#endregion
|
|
1000
|
-
//#region ../../src/cli/commands/DrizzleCommands.ts
|
|
1001
|
-
const drizzleCommandFlags = t.object({
|
|
1002
|
-
provider: t.optional(t.text({ description: "Database provider name to target (e.g., 'postgres', 'sqlite')" })),
|
|
1003
|
-
mode: t.optional(t.text({ description: "Environment variable file(s) to load (e.g., 'production' to load .env.production) https://vite.dev/guide/env-and-mode" }))
|
|
1004
|
-
});
|
|
1005
|
-
var DrizzleCommands = class {
|
|
1006
|
-
log = $logger();
|
|
1007
|
-
utils = $inject(AlephaCliUtils);
|
|
1008
|
-
/**
|
|
1009
|
-
* Check if database migrations are up to date.
|
|
1010
|
-
*/
|
|
1011
|
-
check = $command({
|
|
1012
|
-
name: "check-migrations",
|
|
1013
|
-
description: "Check if database migration files are up to date",
|
|
1014
|
-
args: t.optional(t.text({
|
|
1015
|
-
title: "path",
|
|
1016
|
-
description: "Path to the Alepha server entry file"
|
|
1017
|
-
})),
|
|
1018
|
-
flags: drizzleCommandFlags,
|
|
1019
|
-
handler: async ({ args, root }) => {
|
|
1020
|
-
const rootDir = root;
|
|
1021
|
-
this.log.debug(`Using project root: ${rootDir}`);
|
|
1022
|
-
const { alepha } = await this.utils.loadAlephaFromServerEntryFile(rootDir, args);
|
|
1023
|
-
const repositoryProvider = alepha.inject("RepositoryProvider");
|
|
1024
|
-
const drizzleKitProvider = alepha.inject("DrizzleKitProvider");
|
|
1025
|
-
const accepted = /* @__PURE__ */ new Set([]);
|
|
1026
|
-
for (const primitive of repositoryProvider.getRepositories()) {
|
|
1027
|
-
const provider = primitive.provider;
|
|
1028
|
-
const providerName = provider.name;
|
|
1029
|
-
if (accepted.has(providerName)) continue;
|
|
1030
|
-
accepted.add(providerName);
|
|
1031
|
-
const migrationDir = join(rootDir, "migrations", providerName);
|
|
1032
|
-
const journalFile = await readFile(`${migrationDir}/meta/_journal.json`, "utf-8").catch(() => null);
|
|
1033
|
-
if (!journalFile) {
|
|
1034
|
-
this.log.info(`No migration journal found.`);
|
|
1035
|
-
return;
|
|
1036
|
-
}
|
|
1037
|
-
const journal = JSON.parse(journalFile);
|
|
1038
|
-
const lastMigration = journal.entries[journal.entries.length - 1];
|
|
1039
|
-
const lastSnapshot = JSON.parse(await readFile(`${migrationDir}/meta/${String(lastMigration.idx).padStart(4, "0")}_snapshot.json`, "utf-8"));
|
|
1040
|
-
const models = drizzleKitProvider.getModels(provider);
|
|
1041
|
-
const kit = drizzleKitProvider.importDrizzleKit();
|
|
1042
|
-
const now = kit.generateDrizzleJson(models, lastSnapshot.id);
|
|
1043
|
-
const migrationStatements = await new Promise((resolve) => {
|
|
1044
|
-
(async () => {
|
|
1045
|
-
const timer = setTimeout(() => {
|
|
1046
|
-
resolve([{ message: "Migration generation timed out." }]);
|
|
1047
|
-
}, 5e3);
|
|
1048
|
-
const statements = await kit.generateMigration(lastSnapshot, now);
|
|
1049
|
-
clearTimeout(timer);
|
|
1050
|
-
resolve(statements);
|
|
1051
|
-
})();
|
|
1052
|
-
});
|
|
1053
|
-
if (migrationStatements.length === 0) {
|
|
1054
|
-
this.log.info("No changes detected.");
|
|
1055
|
-
return;
|
|
1082
|
+
if (flags.migrate) {
|
|
1083
|
+
this.log.debug("Running database migrations before deployment...");
|
|
1084
|
+
await this.utils.exec(`alepha db migrate --mode=${mode}`);
|
|
1056
1085
|
}
|
|
1057
|
-
this.
|
|
1058
|
-
|
|
1059
|
-
this.log.info(
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
this.
|
|
1065
|
-
|
|
1086
|
+
await this.utils.ensureDependency(root, "wrangler", { dev: true });
|
|
1087
|
+
const command = `wrangler deploy ${mode === "production" ? "" : "--env preview"} --config=dist/wrangler.jsonc`.trim();
|
|
1088
|
+
this.log.info(`Deploying to Cloudflare with command: ${command}`);
|
|
1089
|
+
await this.utils.exec(command);
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
if (await this.utils.exists(root, "dist/public/404.html")) {
|
|
1093
|
+
await this.utils.ensureDependency(root, "surge", { dev: true });
|
|
1094
|
+
const distPath = join(root, "dist/public");
|
|
1095
|
+
this.log.debug(`Deploying to Surge from directory: ${distPath}`);
|
|
1096
|
+
await this.utils.exec(`surge ${distPath}`);
|
|
1097
|
+
return;
|
|
1066
1098
|
}
|
|
1099
|
+
throw new AlephaError("No deployment configuration found in the dist folder.");
|
|
1067
1100
|
}
|
|
1068
1101
|
});
|
|
1102
|
+
};
|
|
1103
|
+
|
|
1104
|
+
//#endregion
|
|
1105
|
+
//#region ../../src/cli/commands/dev.ts
|
|
1106
|
+
var DevCommand = class {
|
|
1107
|
+
log = $logger();
|
|
1108
|
+
utils = $inject(AlephaCliUtils);
|
|
1109
|
+
alepha = $inject(Alepha);
|
|
1069
1110
|
/**
|
|
1070
|
-
*
|
|
1111
|
+
* Will run the project in watch mode.
|
|
1071
1112
|
*
|
|
1072
|
-
* -
|
|
1073
|
-
* -
|
|
1074
|
-
* - Creates temporary entity definitions based on the current database schema.
|
|
1075
|
-
* - Writes these definitions to a temporary schema file. (node_modules/.db/entities.ts)
|
|
1076
|
-
* - Invokes Drizzle Kit's CLI to generate migration files based on the current schema.
|
|
1113
|
+
* - If an index.html file is found in the project root, it will run Vite in dev mode.
|
|
1114
|
+
* - Otherwise, it will look for a server entry file and run it with tsx in watch mode.
|
|
1077
1115
|
*/
|
|
1078
|
-
|
|
1079
|
-
name: "
|
|
1080
|
-
description: "
|
|
1081
|
-
summary: false,
|
|
1116
|
+
dev = $command({
|
|
1117
|
+
name: "dev",
|
|
1118
|
+
description: "Run the project in development mode",
|
|
1082
1119
|
args: t.optional(t.text({
|
|
1083
1120
|
title: "path",
|
|
1084
|
-
description: "
|
|
1121
|
+
description: "Filepath to run"
|
|
1085
1122
|
})),
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
args,
|
|
1092
|
-
command: "generate",
|
|
1093
|
-
commandFlags,
|
|
1094
|
-
provider: flags.provider,
|
|
1095
|
-
env: flags.mode,
|
|
1096
|
-
logMessage: (providerName, dialect) => `Generate '${providerName}' migrations (${dialect}) ...`
|
|
1123
|
+
handler: async ({ args, root }) => {
|
|
1124
|
+
const expo = await this.utils.hasExpo(root);
|
|
1125
|
+
await this.utils.ensureConfig(root, {
|
|
1126
|
+
viteConfigTs: !expo,
|
|
1127
|
+
tsconfigJson: true
|
|
1097
1128
|
});
|
|
1129
|
+
if (expo) {
|
|
1130
|
+
await this.utils.exec("expo start");
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1133
|
+
const entry = await boot.getServerEntry(root, args);
|
|
1134
|
+
this.log.trace("Entry file found", { entry });
|
|
1135
|
+
if (!await this.isFullstackProject(root)) {
|
|
1136
|
+
const exe = this.alepha.isBun() ? "bun" : "tsx";
|
|
1137
|
+
let cmd = `${exe} --watch`;
|
|
1138
|
+
if (await this.utils.exists(root, ".env")) cmd += " --env-file=./.env";
|
|
1139
|
+
cmd += ` ${entry}`;
|
|
1140
|
+
await this.utils.exec(cmd, { global: exe === "bun" });
|
|
1141
|
+
return;
|
|
1142
|
+
}
|
|
1143
|
+
await this.utils.ensureDependency(root, "vite");
|
|
1144
|
+
await this.utils.exec("vite");
|
|
1098
1145
|
}
|
|
1099
1146
|
});
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
* - Invokes Drizzle Kit's push command to apply schema changes directly.
|
|
1107
|
-
*/
|
|
1108
|
-
push = $command({
|
|
1109
|
-
name: "push",
|
|
1110
|
-
description: "Push database schema changes directly to the database",
|
|
1111
|
-
summary: false,
|
|
1112
|
-
args: t.optional(t.text({
|
|
1113
|
-
title: "path",
|
|
1114
|
-
description: "Path to the Alepha server entry file"
|
|
1115
|
-
})),
|
|
1116
|
-
flags: drizzleCommandFlags,
|
|
1117
|
-
handler: async ({ root, args, flags }) => {
|
|
1118
|
-
await this.runDrizzleKitCommand({
|
|
1119
|
-
root,
|
|
1120
|
-
args,
|
|
1121
|
-
command: "push",
|
|
1122
|
-
provider: flags.provider,
|
|
1123
|
-
env: flags.mode,
|
|
1124
|
-
logMessage: (providerName, dialect) => `Push '${providerName}' schema (${dialect}) ...`
|
|
1125
|
-
});
|
|
1147
|
+
async isFullstackProject(root) {
|
|
1148
|
+
try {
|
|
1149
|
+
await access(join(root, "index.html"));
|
|
1150
|
+
return true;
|
|
1151
|
+
} catch {
|
|
1152
|
+
return false;
|
|
1126
1153
|
}
|
|
1127
|
-
}
|
|
1128
|
-
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
title: "path",
|
|
1142
|
-
description: "Path to the Alepha server entry file"
|
|
1143
|
-
})),
|
|
1144
|
-
flags: drizzleCommandFlags,
|
|
1145
|
-
handler: async ({ root, args, flags }) => {
|
|
1146
|
-
await this.runDrizzleKitCommand({
|
|
1147
|
-
root,
|
|
1148
|
-
args,
|
|
1149
|
-
command: "migrate",
|
|
1150
|
-
provider: flags.provider,
|
|
1151
|
-
env: flags.mode,
|
|
1152
|
-
logMessage: (providerName, dialect) => `Migrate '${providerName}' database (${dialect}) ...`
|
|
1153
|
-
});
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
|
|
1157
|
+
//#endregion
|
|
1158
|
+
//#region ../../src/cli/commands/format.ts
|
|
1159
|
+
var FormatCommand = class {
|
|
1160
|
+
utils = $inject(AlephaCliUtils);
|
|
1161
|
+
format = $command({
|
|
1162
|
+
name: "format",
|
|
1163
|
+
description: "Format the codebase using Biome",
|
|
1164
|
+
handler: async ({ root }) => {
|
|
1165
|
+
await this.utils.ensureConfig(root, { biomeJson: true });
|
|
1166
|
+
await this.utils.ensureDependency(root, "@biomejs/biome");
|
|
1167
|
+
await this.utils.exec("biome format --fix");
|
|
1154
1168
|
}
|
|
1155
1169
|
});
|
|
1170
|
+
};
|
|
1171
|
+
|
|
1172
|
+
//#endregion
|
|
1173
|
+
//#region ../../src/cli/atoms/changelogOptions.ts
|
|
1174
|
+
/**
|
|
1175
|
+
* Default scopes to ignore in changelog generation.
|
|
1176
|
+
* Commits with these scopes won't appear in release notes.
|
|
1177
|
+
*/
|
|
1178
|
+
const DEFAULT_IGNORE = [
|
|
1179
|
+
"project",
|
|
1180
|
+
"release",
|
|
1181
|
+
"starter",
|
|
1182
|
+
"example",
|
|
1183
|
+
"chore",
|
|
1184
|
+
"ci",
|
|
1185
|
+
"build",
|
|
1186
|
+
"test",
|
|
1187
|
+
"style"
|
|
1188
|
+
];
|
|
1189
|
+
/**
|
|
1190
|
+
* Changelog configuration atom.
|
|
1191
|
+
*
|
|
1192
|
+
* Configure in `alepha.config.ts`:
|
|
1193
|
+
* ```ts
|
|
1194
|
+
* import { changelogOptions } from "alepha/cli";
|
|
1195
|
+
*
|
|
1196
|
+
* alepha.set(changelogOptions, {
|
|
1197
|
+
* ignore: ["project", "release", "chore", "docs"],
|
|
1198
|
+
* });
|
|
1199
|
+
* ```
|
|
1200
|
+
*/
|
|
1201
|
+
const changelogOptions = $atom({
|
|
1202
|
+
name: "alepha.changelog",
|
|
1203
|
+
schema: t.object({ ignore: t.optional(t.array(t.string())) }),
|
|
1204
|
+
default: { ignore: DEFAULT_IGNORE }
|
|
1205
|
+
});
|
|
1206
|
+
|
|
1207
|
+
//#endregion
|
|
1208
|
+
//#region ../../src/cli/services/GitMessageParser.ts
|
|
1209
|
+
/**
|
|
1210
|
+
* Service for parsing git commit messages into structured format.
|
|
1211
|
+
*
|
|
1212
|
+
* Only parses **conventional commits with a scope**:
|
|
1213
|
+
* - `feat(scope): description` → feature
|
|
1214
|
+
* - `fix(scope): description` → bug fix
|
|
1215
|
+
* - `feat(scope)!: description` → breaking change
|
|
1216
|
+
*
|
|
1217
|
+
* Commits without scope are ignored, allowing developers to commit
|
|
1218
|
+
* work-in-progress changes without polluting release notes:
|
|
1219
|
+
* - `cli: work in progress` → ignored (no type)
|
|
1220
|
+
* - `fix: quick patch` → ignored (no scope)
|
|
1221
|
+
* - `feat(cli): add command` → included
|
|
1222
|
+
*/
|
|
1223
|
+
var GitMessageParser = class {
|
|
1224
|
+
log = $logger();
|
|
1156
1225
|
/**
|
|
1157
|
-
*
|
|
1226
|
+
* Parse a git commit line into a structured Commit object.
|
|
1227
|
+
*
|
|
1228
|
+
* **Format:** `type(scope): description` or `type(scope)!: description`
|
|
1229
|
+
*
|
|
1230
|
+
* **Supported types:** feat, fix, docs, refactor, perf, revert
|
|
1231
|
+
*
|
|
1232
|
+
* **Breaking changes:** Use `!` before `:` (e.g., `feat(api)!: remove endpoint`)
|
|
1158
1233
|
*
|
|
1159
|
-
*
|
|
1160
|
-
* - Retrieves all repository primitives to gather database models.
|
|
1161
|
-
* - Creates temporary entity definitions and Drizzle config.
|
|
1162
|
-
* - Invokes Drizzle Kit's studio command to launch the web-based database browser.
|
|
1234
|
+
* @returns Commit object or null if not matching/ignored
|
|
1163
1235
|
*/
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1236
|
+
parseCommit(line, config) {
|
|
1237
|
+
const match = line.match(/^([a-f0-9]+)\s+(.+)$/);
|
|
1238
|
+
if (!match) return null;
|
|
1239
|
+
const [, hash, message] = match;
|
|
1240
|
+
const ignore = config.ignore ?? DEFAULT_IGNORE;
|
|
1241
|
+
const conventionalMatch = message.match(/^(feat|fix|docs|refactor|perf|revert)\(([^)]+)\)(!)?:\s*(.+)$/i);
|
|
1242
|
+
if (!conventionalMatch) return null;
|
|
1243
|
+
const [, type, scope, breakingMark, description] = conventionalMatch;
|
|
1244
|
+
const baseScope = scope.split("/")[0];
|
|
1245
|
+
if (ignore.includes(baseScope) || ignore.includes(scope)) return null;
|
|
1246
|
+
const breaking = breakingMark === "!" || description.toLowerCase().includes("breaking");
|
|
1247
|
+
return {
|
|
1248
|
+
hash: hash.substring(0, 8),
|
|
1249
|
+
type: type.toLowerCase(),
|
|
1250
|
+
scope,
|
|
1251
|
+
description: description.trim(),
|
|
1252
|
+
breaking
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
};
|
|
1256
|
+
|
|
1257
|
+
//#endregion
|
|
1258
|
+
//#region ../../src/cli/commands/gen/changelog.ts
|
|
1259
|
+
const execAsync = promisify(exec);
|
|
1260
|
+
/**
|
|
1261
|
+
* Git provider for executing git commands.
|
|
1262
|
+
* Can be substituted in tests with a mock implementation.
|
|
1263
|
+
*/
|
|
1264
|
+
var GitProvider = class {
|
|
1265
|
+
async exec(cmd, cwd) {
|
|
1266
|
+
const { stdout } = await execAsync(`git ${cmd}`, { cwd });
|
|
1267
|
+
return stdout;
|
|
1268
|
+
}
|
|
1269
|
+
};
|
|
1270
|
+
/**
|
|
1271
|
+
* Changelog command for generating release notes from git commits.
|
|
1272
|
+
*
|
|
1273
|
+
* Usage:
|
|
1274
|
+
* - `alepha gen changelog` - Show unreleased changes since latest tag to HEAD
|
|
1275
|
+
* - `alepha gen changelog --from=1.0.0` - Show changes from version to HEAD
|
|
1276
|
+
* - `alepha gen changelog --from=1.0.0 --to=1.1.0` - Show changes between two refs
|
|
1277
|
+
* - `alepha gen changelog | tee -a CHANGELOG.md` - Append to file
|
|
1278
|
+
*/
|
|
1279
|
+
var ChangelogCommand = class {
|
|
1280
|
+
log = $logger();
|
|
1281
|
+
git = $inject(GitProvider);
|
|
1282
|
+
parser = $inject(GitMessageParser);
|
|
1283
|
+
config = $use(changelogOptions);
|
|
1284
|
+
/**
|
|
1285
|
+
* Format a single commit line.
|
|
1286
|
+
* Example: `- **cli**: add new command (\`abc1234\`)`
|
|
1287
|
+
* Breaking changes are flagged: `- **cli**: add new command [BREAKING] (\`abc1234\`)`
|
|
1288
|
+
*/
|
|
1289
|
+
formatCommit(commit) {
|
|
1290
|
+
const breaking = commit.breaking ? " [BREAKING]" : "";
|
|
1291
|
+
return `- **${commit.scope}**: ${commit.description}${breaking} (\`${commit.hash}\`)`;
|
|
1292
|
+
}
|
|
1184
1293
|
/**
|
|
1185
|
-
*
|
|
1294
|
+
* Format the changelog entry with sections.
|
|
1186
1295
|
*/
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
this.
|
|
1192
|
-
|
|
1193
|
-
this.push,
|
|
1194
|
-
this.migrate,
|
|
1195
|
-
this.studio
|
|
1196
|
-
],
|
|
1197
|
-
handler: async ({ help }) => {
|
|
1198
|
-
help();
|
|
1296
|
+
formatEntry(entry) {
|
|
1297
|
+
const sections = [];
|
|
1298
|
+
if (entry.features.length > 0) {
|
|
1299
|
+
sections.push("### Features\n");
|
|
1300
|
+
for (const commit of entry.features) sections.push(this.formatCommit(commit));
|
|
1301
|
+
sections.push("");
|
|
1199
1302
|
}
|
|
1200
|
-
|
|
1303
|
+
if (entry.fixes.length > 0) {
|
|
1304
|
+
sections.push("### Bug Fixes\n");
|
|
1305
|
+
for (const commit of entry.fixes) sections.push(this.formatCommit(commit));
|
|
1306
|
+
sections.push("");
|
|
1307
|
+
}
|
|
1308
|
+
return sections.join("\n");
|
|
1309
|
+
}
|
|
1201
1310
|
/**
|
|
1202
|
-
*
|
|
1203
|
-
*
|
|
1204
|
-
* Iterates through all repository providers, prepares Drizzle config for each,
|
|
1205
|
-
* and executes the specified drizzle-kit command.
|
|
1206
|
-
*
|
|
1207
|
-
* @param options - Configuration including command to run, flags, and logging
|
|
1311
|
+
* Parse git log output into a changelog entry.
|
|
1208
1312
|
*/
|
|
1209
|
-
|
|
1210
|
-
const
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
for (const primitive of repositoryProvider.getRepositories()) {
|
|
1220
|
-
const provider = primitive.provider;
|
|
1221
|
-
const providerName = provider.name;
|
|
1222
|
-
const dialect = provider.dialect;
|
|
1223
|
-
if (accepted.has(providerName)) continue;
|
|
1224
|
-
accepted.add(providerName);
|
|
1225
|
-
if (options.provider && options.provider !== providerName) {
|
|
1226
|
-
this.log.debug(`Skipping provider '${providerName}' (filter: ${options.provider})`);
|
|
1313
|
+
parseCommits(commitsOutput) {
|
|
1314
|
+
const entry = {
|
|
1315
|
+
features: [],
|
|
1316
|
+
fixes: []
|
|
1317
|
+
};
|
|
1318
|
+
for (const line of commitsOutput.trim().split("\n")) {
|
|
1319
|
+
if (!line.trim()) continue;
|
|
1320
|
+
const commit = this.parser.parseCommit(line, this.config);
|
|
1321
|
+
if (!commit) {
|
|
1322
|
+
this.log.trace("Skipping commit", { line });
|
|
1227
1323
|
continue;
|
|
1228
1324
|
}
|
|
1229
|
-
this.log.
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
kit: drizzleKitProvider,
|
|
1233
|
-
provider,
|
|
1234
|
-
providerName,
|
|
1235
|
-
providerUrl: provider.url,
|
|
1236
|
-
dialect,
|
|
1237
|
-
entry,
|
|
1238
|
-
rootDir
|
|
1239
|
-
});
|
|
1240
|
-
const flags = options.commandFlags ? ` ${options.commandFlags}` : "";
|
|
1241
|
-
await this.utils.exec(`drizzle-kit ${options.command} --config=${drizzleConfigJsPath}${flags}`, { env: { NODE_OPTIONS: "--import tsx" } });
|
|
1325
|
+
this.log.trace("Parsed commit", { commit });
|
|
1326
|
+
if (commit.type === "feat") entry.features.push(commit);
|
|
1327
|
+
else if (commit.type === "fix") entry.fixes.push(commit);
|
|
1242
1328
|
}
|
|
1329
|
+
return entry;
|
|
1243
1330
|
}
|
|
1244
1331
|
/**
|
|
1245
|
-
*
|
|
1246
|
-
*
|
|
1247
|
-
* Creates temporary entities.js and drizzle.config.js files needed
|
|
1248
|
-
* for Drizzle Kit commands to run properly.
|
|
1249
|
-
*
|
|
1250
|
-
* @param options - Configuration options including kit, provider info, and paths
|
|
1251
|
-
* @returns Path to the generated drizzle.config.js file
|
|
1332
|
+
* Check if entry has any public commits.
|
|
1252
1333
|
*/
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
};
|
|
1262
|
-
if (options.provider.schema) config.schemaFilter = options.provider.schema;
|
|
1263
|
-
if (options.providerName === "d1") config.driver = "d1-http";
|
|
1264
|
-
if (options.providerName === "pglite") config.driver = "pglite";
|
|
1265
|
-
if (options.dialect === "sqlite") if (options.providerName === "d1") {
|
|
1266
|
-
const token = process.env.CLOUDFLARE_API_TOKEN;
|
|
1267
|
-
if (!token) throw new AlephaError("CLOUDFLARE_API_TOKEN environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit");
|
|
1268
|
-
const accountId = process.env.CLOUDFLARE_ACCOUNT_ID;
|
|
1269
|
-
if (!accountId) throw new AlephaError("CLOUDFLARE_ACCOUNT_ID environment variable is not set. https://orm.drizzle.team/docs/guides/d1-http-with-drizzle-kit");
|
|
1270
|
-
const url = options.providerUrl;
|
|
1271
|
-
if (!url.startsWith("cloudflare-d1://")) throw new AlephaError("D1 provider URL must start with 'cloudflare-d1://'.");
|
|
1272
|
-
const [, databaseId] = url.replace("cloudflare-d1://", "").replace("cloudflare-d1:", "").split(":");
|
|
1273
|
-
if (!databaseId) throw new AlephaError("Database ID is missing in the D1 provider URL. Cloudflare D1 URL format: cloudflare-d1://<database_name>:<database_id>");
|
|
1274
|
-
config.dbCredentials = {
|
|
1275
|
-
accountId,
|
|
1276
|
-
databaseId,
|
|
1277
|
-
token
|
|
1278
|
-
};
|
|
1279
|
-
} else {
|
|
1280
|
-
let url = options.providerUrl;
|
|
1281
|
-
url = url.replace("sqlite://", "").replace("file://", "");
|
|
1282
|
-
url = join(options.rootDir, url);
|
|
1283
|
-
config.dbCredentials = { url };
|
|
1284
|
-
}
|
|
1285
|
-
const drizzleConfigJs = `export default ${JSON.stringify(config, null, 2)}`;
|
|
1286
|
-
return await this.utils.writeConfigFile("drizzle.config.js", drizzleConfigJs, options.rootDir);
|
|
1334
|
+
hasChanges(entry) {
|
|
1335
|
+
return entry.features.length > 0 || entry.fixes.length > 0;
|
|
1336
|
+
}
|
|
1337
|
+
/**
|
|
1338
|
+
* Get the latest version tag.
|
|
1339
|
+
*/
|
|
1340
|
+
async getLatestTag(git) {
|
|
1341
|
+
return (await git("tag --sort=-version:refname")).trim().split("\n").filter((tag) => tag.match(/^\d+\.\d+\.\d+$/))[0] || null;
|
|
1287
1342
|
}
|
|
1343
|
+
command = $command({
|
|
1344
|
+
name: "changelog",
|
|
1345
|
+
description: "Generate changelog from conventional commits (outputs to stdout)",
|
|
1346
|
+
flags: t.object({
|
|
1347
|
+
from: t.optional(t.string({
|
|
1348
|
+
aliases: ["f"],
|
|
1349
|
+
description: "Starting ref (default: latest tag)"
|
|
1350
|
+
})),
|
|
1351
|
+
to: t.optional(t.string({
|
|
1352
|
+
aliases: ["t"],
|
|
1353
|
+
description: "Ending ref (default: HEAD)"
|
|
1354
|
+
}))
|
|
1355
|
+
}),
|
|
1356
|
+
handler: async ({ flags, root }) => {
|
|
1357
|
+
const git = (cmd) => this.git.exec(cmd, root);
|
|
1358
|
+
let fromRef;
|
|
1359
|
+
if (flags.from) {
|
|
1360
|
+
fromRef = flags.from;
|
|
1361
|
+
this.log.debug("Using specified from ref", { from: fromRef });
|
|
1362
|
+
} else {
|
|
1363
|
+
const latestTag = await this.getLatestTag(git);
|
|
1364
|
+
if (!latestTag) {
|
|
1365
|
+
process.stdout.write("No version tags found in repository\n");
|
|
1366
|
+
return;
|
|
1367
|
+
}
|
|
1368
|
+
fromRef = latestTag;
|
|
1369
|
+
this.log.debug("Using latest tag", { from: fromRef });
|
|
1370
|
+
}
|
|
1371
|
+
const toRef = flags.to || "HEAD";
|
|
1372
|
+
this.log.debug("Using to ref", { to: toRef });
|
|
1373
|
+
const commitsOutput = await git(`log ${fromRef}..${toRef} --oneline`);
|
|
1374
|
+
if (!commitsOutput.trim()) {
|
|
1375
|
+
process.stdout.write(`No changes in range ${fromRef}..${toRef}\n`);
|
|
1376
|
+
return;
|
|
1377
|
+
}
|
|
1378
|
+
const entry = this.parseCommits(commitsOutput);
|
|
1379
|
+
if (!this.hasChanges(entry)) {
|
|
1380
|
+
process.stdout.write(`No public changes in range ${fromRef}..${toRef}\n`);
|
|
1381
|
+
return;
|
|
1382
|
+
}
|
|
1383
|
+
process.stdout.write(this.formatEntry(entry));
|
|
1384
|
+
}
|
|
1385
|
+
});
|
|
1386
|
+
};
|
|
1387
|
+
|
|
1388
|
+
//#endregion
|
|
1389
|
+
//#region ../../src/cli/commands/gen/openapi.ts
|
|
1390
|
+
var OpenApiCommand = class {
|
|
1391
|
+
log = $logger();
|
|
1392
|
+
utils = $inject(AlephaCliUtils);
|
|
1393
|
+
fs = $inject(FileSystemProvider);
|
|
1394
|
+
command = $command({
|
|
1395
|
+
name: "openapi",
|
|
1396
|
+
description: "Generate OpenAPI specification from actions",
|
|
1397
|
+
flags: t.object({ out: t.optional(t.text({
|
|
1398
|
+
aliases: ["o"],
|
|
1399
|
+
description: "Output file path"
|
|
1400
|
+
})) }),
|
|
1401
|
+
handler: async ({ root, flags }) => {
|
|
1402
|
+
const { alepha } = await this.utils.loadAlephaFromServerEntryFile(root);
|
|
1403
|
+
try {
|
|
1404
|
+
const openapiProvider = alepha.inject(ServerSwaggerProvider);
|
|
1405
|
+
await alepha.events.emit("configure", alepha);
|
|
1406
|
+
let json = openapiProvider.json;
|
|
1407
|
+
if (!json) json = openapiProvider.generateSwaggerDoc({ info: {
|
|
1408
|
+
title: "API Documentation",
|
|
1409
|
+
version: "1.0.0"
|
|
1410
|
+
} });
|
|
1411
|
+
if (!json) {
|
|
1412
|
+
this.log.error("No actions found to generate OpenAPI specification.");
|
|
1413
|
+
return;
|
|
1414
|
+
}
|
|
1415
|
+
if (flags.out) await this.fs.writeFile(this.fs.join(root, flags.out), JSON.stringify(json, null, 2));
|
|
1416
|
+
else this.log.info(JSON.stringify(json, null, 2));
|
|
1417
|
+
} catch (err) {
|
|
1418
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1419
|
+
if (message.includes("Service not found")) {
|
|
1420
|
+
this.log.error("Missing $swagger() primitive in your server configuration.");
|
|
1421
|
+
return;
|
|
1422
|
+
}
|
|
1423
|
+
this.log.error(`OpenAPI generation failed - ${message}`, { err });
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
});
|
|
1427
|
+
};
|
|
1428
|
+
|
|
1429
|
+
//#endregion
|
|
1430
|
+
//#region ../../src/cli/commands/gen.ts
|
|
1431
|
+
var GenCommand = class {
|
|
1432
|
+
changelog = $inject(ChangelogCommand);
|
|
1433
|
+
openapi = $inject(OpenApiCommand);
|
|
1434
|
+
gen = $command({
|
|
1435
|
+
name: "gen",
|
|
1436
|
+
description: "Generate code, documentation, ...",
|
|
1437
|
+
children: [this.changelog.command, this.openapi.command],
|
|
1438
|
+
handler: async ({ help }) => {
|
|
1439
|
+
help();
|
|
1440
|
+
}
|
|
1441
|
+
});
|
|
1288
1442
|
};
|
|
1289
1443
|
|
|
1290
1444
|
//#endregion
|
|
1291
|
-
//#region ../../src/cli/commands/
|
|
1292
|
-
var
|
|
1445
|
+
//#region ../../src/cli/commands/init.ts
|
|
1446
|
+
var InitCommand = class {
|
|
1293
1447
|
utils = $inject(AlephaCliUtils);
|
|
1294
1448
|
/**
|
|
1295
|
-
*
|
|
1296
|
-
*
|
|
1297
|
-
* This command runs the following checks in order:
|
|
1298
|
-
* - Clean the project
|
|
1299
|
-
* - Format the code
|
|
1300
|
-
* - Lint the code
|
|
1301
|
-
* - Run tests (if Vitest is a dev dependency)
|
|
1302
|
-
* - Check database migrations (if a migrations directory exists)
|
|
1303
|
-
* - Type check the code
|
|
1304
|
-
* - Build the project
|
|
1305
|
-
* - Clean the project again
|
|
1449
|
+
* Ensure the project has the necessary Alepha configuration files.
|
|
1450
|
+
* Add the correct dependencies to package.json and install them.
|
|
1306
1451
|
*/
|
|
1307
|
-
|
|
1308
|
-
name: "
|
|
1309
|
-
description: "
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1452
|
+
init = $command({
|
|
1453
|
+
name: "init",
|
|
1454
|
+
description: "Add missing Alepha configuration files to the project",
|
|
1455
|
+
flags: t.object({
|
|
1456
|
+
yarn: t.optional(t.boolean({ description: "Use Yarn package manager" })),
|
|
1457
|
+
pnpm: t.optional(t.boolean({ description: "Use pnpm package manager" })),
|
|
1458
|
+
npm: t.optional(t.boolean({ description: "Use npm package manager" })),
|
|
1459
|
+
bun: t.optional(t.boolean({ description: "Use Bun package manager" })),
|
|
1460
|
+
react: t.optional(t.boolean({ description: "Include Alepha React dependencies" })),
|
|
1461
|
+
ui: t.optional(t.boolean({ description: "Include Alepha UI dependencies" })),
|
|
1462
|
+
test: t.optional(t.boolean({ description: "Include Vitest and create test directory" }))
|
|
1463
|
+
}),
|
|
1464
|
+
handler: async ({ run, flags, root }) => {
|
|
1465
|
+
if (flags.ui) flags.react = true;
|
|
1466
|
+
const isExpo = await this.utils.hasExpo(root);
|
|
1467
|
+
await run({
|
|
1468
|
+
name: "ensuring configuration files",
|
|
1469
|
+
handler: async () => {
|
|
1470
|
+
await this.utils.ensureConfig(root, {
|
|
1471
|
+
tsconfigJson: true,
|
|
1472
|
+
packageJson: flags,
|
|
1473
|
+
biomeJson: true,
|
|
1474
|
+
viteConfigTs: !isExpo,
|
|
1475
|
+
editorconfig: true,
|
|
1476
|
+
indexHtml: !!flags.react && !isExpo
|
|
1477
|
+
});
|
|
1478
|
+
if (!flags.react) await this.utils.ensureSrcMain(root);
|
|
1479
|
+
}
|
|
1480
|
+
});
|
|
1481
|
+
const pm = await this.utils.getPackageManager(root, flags);
|
|
1482
|
+
if (pm === "yarn") {
|
|
1483
|
+
await this.utils.ensureYarn(root);
|
|
1484
|
+
await run("yarn set version stable");
|
|
1485
|
+
} else if (pm === "bun") await this.utils.ensureBun(root);
|
|
1486
|
+
else if (pm === "pnpm") await this.utils.ensurePnpm(root);
|
|
1487
|
+
else await this.utils.ensureNpm(root);
|
|
1488
|
+
await run(`${pm} install`, { alias: `installing dependencies with ${pm}` });
|
|
1489
|
+
if (!isExpo) await this.utils.ensureDependency(root, "vite", { run });
|
|
1490
|
+
await this.utils.ensureDependency(root, "@biomejs/biome", { run });
|
|
1491
|
+
if (flags.test) {
|
|
1492
|
+
await this.utils.ensureTestDir(root);
|
|
1493
|
+
await run(`${pm} ${pm === "yarn" ? "add" : "install"} -D vitest`, { alias: "setup testing with Vitest" });
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
});
|
|
1497
|
+
};
|
|
1498
|
+
|
|
1499
|
+
//#endregion
|
|
1500
|
+
//#region ../../src/cli/commands/lint.ts
|
|
1501
|
+
var LintCommand = class {
|
|
1502
|
+
utils = $inject(AlephaCliUtils);
|
|
1503
|
+
lint = $command({
|
|
1504
|
+
name: "lint",
|
|
1505
|
+
description: "Run linter across the codebase using Biome",
|
|
1506
|
+
handler: async ({ root }) => {
|
|
1507
|
+
await this.utils.ensureConfig(root, { biomeJson: true });
|
|
1508
|
+
await this.utils.ensureDependency(root, "@biomejs/biome");
|
|
1509
|
+
await this.utils.exec("biome check --formatter-enabled=false --fix");
|
|
1319
1510
|
}
|
|
1320
1511
|
});
|
|
1512
|
+
};
|
|
1513
|
+
|
|
1514
|
+
//#endregion
|
|
1515
|
+
//#region ../../src/cli/commands/root.ts
|
|
1516
|
+
var RootCommand = class {
|
|
1517
|
+
log = $logger();
|
|
1518
|
+
cli = $inject(CliProvider);
|
|
1519
|
+
alepha = $inject(Alepha);
|
|
1520
|
+
color = $inject(ConsoleColorProvider);
|
|
1321
1521
|
/**
|
|
1322
|
-
*
|
|
1522
|
+
* Called when no command is provided
|
|
1323
1523
|
*/
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1524
|
+
root = $command({
|
|
1525
|
+
root: true,
|
|
1526
|
+
flags: t.object({ version: t.optional(t.boolean({
|
|
1527
|
+
description: "Show Alepha CLI version",
|
|
1528
|
+
aliases: ["v"]
|
|
1529
|
+
})) }),
|
|
1530
|
+
handler: async ({ flags }) => {
|
|
1531
|
+
if (flags.version) {
|
|
1532
|
+
this.log.info(this.color.set("WHITE_BOLD", `Alepha v${version}`));
|
|
1533
|
+
if (this.alepha.isBun()) this.log.info(this.color.set("GREY_DARK", `└─ Bun v${Bun.version}`));
|
|
1534
|
+
else this.log.info(this.color.set("GREY_DARK", `└─ Node ${process.version}`));
|
|
1535
|
+
return;
|
|
1536
|
+
}
|
|
1537
|
+
this.cli.printHelp();
|
|
1330
1538
|
}
|
|
1331
1539
|
});
|
|
1332
1540
|
};
|
|
1333
1541
|
|
|
1334
1542
|
//#endregion
|
|
1335
|
-
//#region ../../src/cli/commands/
|
|
1336
|
-
var
|
|
1337
|
-
log = $logger();
|
|
1543
|
+
//#region ../../src/cli/commands/run.ts
|
|
1544
|
+
var RunCommand = class {
|
|
1338
1545
|
utils = $inject(AlephaCliUtils);
|
|
1339
|
-
env = $env(t.object({ VITEST_ARGS: t.string({ default: "" }) }));
|
|
1340
1546
|
run = $command({
|
|
1341
1547
|
name: "run",
|
|
1342
1548
|
hide: true,
|
|
@@ -1355,171 +1561,12 @@ var ViteCommands = class {
|
|
|
1355
1561
|
await this.utils.exec(`tsx ${flags.watch ? "watch " : ""}${args}`);
|
|
1356
1562
|
}
|
|
1357
1563
|
});
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
dev = $command({
|
|
1365
|
-
name: "dev",
|
|
1366
|
-
description: "Run the project in development mode",
|
|
1367
|
-
args: t.optional(t.text({
|
|
1368
|
-
title: "path",
|
|
1369
|
-
description: "Filepath to run"
|
|
1370
|
-
})),
|
|
1371
|
-
handler: async ({ args, root }) => {
|
|
1372
|
-
const expo = await this.utils.hasExpo(root);
|
|
1373
|
-
await this.utils.ensureConfig(root, {
|
|
1374
|
-
viteConfigTs: !expo,
|
|
1375
|
-
tsconfigJson: true
|
|
1376
|
-
});
|
|
1377
|
-
if (expo) {
|
|
1378
|
-
await this.utils.exec(`expo start`);
|
|
1379
|
-
return;
|
|
1380
|
-
}
|
|
1381
|
-
const entry = await boot.getServerEntry(root, args);
|
|
1382
|
-
this.log.trace("Entry file found", { entry });
|
|
1383
|
-
try {
|
|
1384
|
-
await access(join(root, "index.html"));
|
|
1385
|
-
} catch {
|
|
1386
|
-
this.log.trace("No index.html found, running entry file with tsx");
|
|
1387
|
-
let cmd = "tsx --watch";
|
|
1388
|
-
if (await this.utils.exists(root, ".env")) cmd += ` --env-file=./.env`;
|
|
1389
|
-
cmd += ` ${entry}`;
|
|
1390
|
-
await this.utils.exec(cmd);
|
|
1391
|
-
return;
|
|
1392
|
-
}
|
|
1393
|
-
await this.utils.ensureDependency(root, "vite");
|
|
1394
|
-
await this.utils.exec(`vite`);
|
|
1395
|
-
}
|
|
1396
|
-
});
|
|
1397
|
-
build = $command({
|
|
1398
|
-
name: "build",
|
|
1399
|
-
description: "Build the project for production",
|
|
1400
|
-
args: t.optional(t.text({
|
|
1401
|
-
title: "path",
|
|
1402
|
-
description: "Filepath to build"
|
|
1403
|
-
})),
|
|
1404
|
-
flags: t.object({
|
|
1405
|
-
stats: t.optional(t.boolean({ description: "Generate build stats report" })),
|
|
1406
|
-
vercel: t.optional(t.boolean({ description: "Generate Vercel deployment configuration" })),
|
|
1407
|
-
cloudflare: t.optional(t.boolean({ description: "Generate Cloudflare Workers configuration" })),
|
|
1408
|
-
docker: t.optional(t.boolean({ description: "Generate Docker configuration" })),
|
|
1409
|
-
sitemap: t.optional(t.text({ description: "Generate sitemap.xml with base URL" }))
|
|
1410
|
-
}),
|
|
1411
|
-
handler: async ({ flags, args, run, root }) => {
|
|
1412
|
-
process.env.ALEPHA_BUILD_MODE = "cli";
|
|
1413
|
-
process.env.NODE_ENV = "production";
|
|
1414
|
-
if (await this.utils.hasExpo(root)) return;
|
|
1415
|
-
await this.utils.ensureConfig(root, {
|
|
1416
|
-
viteConfigTs: true,
|
|
1417
|
-
tsconfigJson: true
|
|
1418
|
-
});
|
|
1419
|
-
const entry = await boot.getServerEntry(root, args);
|
|
1420
|
-
this.log.trace("Entry file found", { entry });
|
|
1421
|
-
const distDir = "dist";
|
|
1422
|
-
const clientDir = "public";
|
|
1423
|
-
await this.utils.ensureDependency(root, "vite", { run });
|
|
1424
|
-
await run.rm("dist", { alias: "clean dist" });
|
|
1425
|
-
const viteAlephaBuildOptions = (await createRequire(import.meta.url)("vite").resolveConfig({}, "build", "production")).plugins.find((it) => it.name === "alepha:build")?.[OPTIONS] || {};
|
|
1426
|
-
await this.utils.loadEnv(root, [".env", ".env.production"]);
|
|
1427
|
-
const stats = flags.stats ?? viteAlephaBuildOptions.stats ?? false;
|
|
1428
|
-
const hasServer = viteAlephaBuildOptions.serverEntry !== false;
|
|
1429
|
-
let hasClient = false;
|
|
1430
|
-
try {
|
|
1431
|
-
await access(join(root, "index.html"));
|
|
1432
|
-
hasClient = true;
|
|
1433
|
-
} catch {}
|
|
1434
|
-
const clientOptions = typeof viteAlephaBuildOptions.client === "object" ? viteAlephaBuildOptions.client : {};
|
|
1435
|
-
if (hasClient) await run({
|
|
1436
|
-
name: "vite build client",
|
|
1437
|
-
handler: () => buildClient({
|
|
1438
|
-
silent: true,
|
|
1439
|
-
dist: `${distDir}/${clientDir}`,
|
|
1440
|
-
stats,
|
|
1441
|
-
precompress: clientOptions.precompress
|
|
1442
|
-
})
|
|
1443
|
-
});
|
|
1444
|
-
await run({
|
|
1445
|
-
name: "vite build server",
|
|
1446
|
-
handler: async () => {
|
|
1447
|
-
let clientBuilt = false;
|
|
1448
|
-
try {
|
|
1449
|
-
await readFile(`${distDir}/${clientDir}/index.html`, "utf-8");
|
|
1450
|
-
clientBuilt = true;
|
|
1451
|
-
} catch {}
|
|
1452
|
-
await buildServer({
|
|
1453
|
-
silent: true,
|
|
1454
|
-
entry,
|
|
1455
|
-
distDir,
|
|
1456
|
-
clientDir: clientBuilt ? clientDir : void 0,
|
|
1457
|
-
stats
|
|
1458
|
-
});
|
|
1459
|
-
if (clientBuilt && hasServer) await unlink(`${distDir}/${clientDir}/index.html`);
|
|
1460
|
-
}
|
|
1461
|
-
});
|
|
1462
|
-
await copyAssets({
|
|
1463
|
-
root,
|
|
1464
|
-
entry: `${distDir}/index.js`,
|
|
1465
|
-
distDir,
|
|
1466
|
-
run
|
|
1467
|
-
});
|
|
1468
|
-
if (hasClient) {
|
|
1469
|
-
const sitemapBaseUrl = flags.sitemap ?? clientOptions.sitemap?.hostname;
|
|
1470
|
-
if (sitemapBaseUrl) await run({
|
|
1471
|
-
name: "add sitemap",
|
|
1472
|
-
handler: async () => {
|
|
1473
|
-
await writeFile(`${distDir}/${clientDir}/sitemap.xml`, await generateSitemap({
|
|
1474
|
-
entry: `${distDir}/index.js`,
|
|
1475
|
-
baseUrl: sitemapBaseUrl
|
|
1476
|
-
}));
|
|
1477
|
-
}
|
|
1478
|
-
});
|
|
1479
|
-
if (clientOptions.prerender) await run({
|
|
1480
|
-
name: "pre-render pages",
|
|
1481
|
-
handler: async () => {
|
|
1482
|
-
await prerenderPages({
|
|
1483
|
-
dist: `${distDir}/${clientDir}`,
|
|
1484
|
-
entry: `${distDir}/index.js`,
|
|
1485
|
-
compress: clientOptions.precompress
|
|
1486
|
-
});
|
|
1487
|
-
}
|
|
1488
|
-
});
|
|
1489
|
-
}
|
|
1490
|
-
if (flags.vercel || viteAlephaBuildOptions.vercel) {
|
|
1491
|
-
const config = typeof viteAlephaBuildOptions.vercel === "object" ? viteAlephaBuildOptions.vercel : {};
|
|
1492
|
-
await run({
|
|
1493
|
-
name: "add Vercel config",
|
|
1494
|
-
handler: () => generateVercel({
|
|
1495
|
-
distDir,
|
|
1496
|
-
clientDir,
|
|
1497
|
-
config
|
|
1498
|
-
})
|
|
1499
|
-
});
|
|
1500
|
-
}
|
|
1501
|
-
if (flags.cloudflare || viteAlephaBuildOptions.cloudflare) {
|
|
1502
|
-
const config = typeof viteAlephaBuildOptions.cloudflare === "boolean" ? {} : viteAlephaBuildOptions.cloudflare;
|
|
1503
|
-
await run({
|
|
1504
|
-
name: "add Cloudflare config",
|
|
1505
|
-
handler: () => generateCloudflare({
|
|
1506
|
-
distDir,
|
|
1507
|
-
config
|
|
1508
|
-
})
|
|
1509
|
-
});
|
|
1510
|
-
}
|
|
1511
|
-
if (flags.docker || viteAlephaBuildOptions.docker) {
|
|
1512
|
-
const dockerConfig = typeof viteAlephaBuildOptions.docker === "object" ? viteAlephaBuildOptions.docker : {};
|
|
1513
|
-
await run({
|
|
1514
|
-
name: "add Docker config",
|
|
1515
|
-
handler: () => generateDocker({
|
|
1516
|
-
distDir,
|
|
1517
|
-
...dockerConfig
|
|
1518
|
-
})
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
}
|
|
1522
|
-
});
|
|
1564
|
+
};
|
|
1565
|
+
|
|
1566
|
+
//#endregion
|
|
1567
|
+
//#region ../../src/cli/commands/test.ts
|
|
1568
|
+
var TestCommand = class {
|
|
1569
|
+
utils = $inject(AlephaCliUtils);
|
|
1523
1570
|
test = $command({
|
|
1524
1571
|
name: "test",
|
|
1525
1572
|
description: "Run tests using Vitest",
|
|
@@ -1543,15 +1590,82 @@ var ViteCommands = class {
|
|
|
1543
1590
|
});
|
|
1544
1591
|
};
|
|
1545
1592
|
|
|
1593
|
+
//#endregion
|
|
1594
|
+
//#region ../../src/cli/commands/typecheck.ts
|
|
1595
|
+
var TypecheckCommand = class {
|
|
1596
|
+
utils = $inject(AlephaCliUtils);
|
|
1597
|
+
log = $logger();
|
|
1598
|
+
/**
|
|
1599
|
+
* Run TypeScript type checking across the codebase with no emit.
|
|
1600
|
+
*/
|
|
1601
|
+
typecheck = $command({
|
|
1602
|
+
name: "typecheck",
|
|
1603
|
+
aliases: ["tc"],
|
|
1604
|
+
description: "Check TypeScript types across the codebase",
|
|
1605
|
+
handler: async ({ root }) => {
|
|
1606
|
+
this.log.info("Starting TypeScript type checking...");
|
|
1607
|
+
await this.utils.ensureDependency(root, "typescript");
|
|
1608
|
+
await this.utils.exec("tsc --noEmit");
|
|
1609
|
+
this.log.info("TypeScript type checking completed successfully.");
|
|
1610
|
+
}
|
|
1611
|
+
});
|
|
1612
|
+
};
|
|
1613
|
+
|
|
1614
|
+
//#endregion
|
|
1615
|
+
//#region ../../src/cli/commands/verify.ts
|
|
1616
|
+
var VerifyCommand = class {
|
|
1617
|
+
utils = $inject(AlephaCliUtils);
|
|
1618
|
+
/**
|
|
1619
|
+
* Run a series of verification commands to ensure code quality and correctness.
|
|
1620
|
+
*
|
|
1621
|
+
* This command runs the following checks in order:
|
|
1622
|
+
* - Clean the project
|
|
1623
|
+
* - Format the code
|
|
1624
|
+
* - Lint the code
|
|
1625
|
+
* - Run tests (if Vitest is a dev dependency)
|
|
1626
|
+
* - Check database migrations (if a migrations directory exists)
|
|
1627
|
+
* - Type check the code
|
|
1628
|
+
* - Build the project
|
|
1629
|
+
* - Clean the project again
|
|
1630
|
+
*/
|
|
1631
|
+
verify = $command({
|
|
1632
|
+
name: "verify",
|
|
1633
|
+
description: "Verify the Alepha project",
|
|
1634
|
+
handler: async ({ root, run }) => {
|
|
1635
|
+
await run("alepha clean");
|
|
1636
|
+
await run("alepha format");
|
|
1637
|
+
await run("alepha lint");
|
|
1638
|
+
await run("alepha typecheck");
|
|
1639
|
+
if ((await this.utils.readPackageJson(root)).devDependencies?.vitest) await run("alepha test");
|
|
1640
|
+
if (await this.utils.exists(root, "migrations")) await run("alepha db:check-migrations");
|
|
1641
|
+
if (!await this.utils.hasExpo(root)) await run("alepha build");
|
|
1642
|
+
await run("alepha clean");
|
|
1643
|
+
}
|
|
1644
|
+
});
|
|
1645
|
+
};
|
|
1646
|
+
|
|
1546
1647
|
//#endregion
|
|
1547
1648
|
//#region ../../src/cli/apps/AlephaCli.ts
|
|
1649
|
+
/**
|
|
1650
|
+
* Register `tsx` when running in Node.js, ignore for Bun.
|
|
1651
|
+
*
|
|
1652
|
+
* It's required to have a full TypeScript support. (mostly .tsx files)
|
|
1653
|
+
*/
|
|
1654
|
+
if (typeof Bun === "undefined") {
|
|
1655
|
+
const { register } = await import("tsx/esm/api");
|
|
1656
|
+
register();
|
|
1657
|
+
}
|
|
1658
|
+
/**
|
|
1659
|
+
* Allow to extend Alepha CLI via `alepha.config.ts` file located in the project root.
|
|
1660
|
+
*/
|
|
1548
1661
|
var AlephaCliExtension = class {
|
|
1549
1662
|
alepha = $inject(Alepha);
|
|
1550
1663
|
fs = $inject(FileSystemProvider);
|
|
1551
1664
|
onConfigure = $hook({
|
|
1552
1665
|
on: "configure",
|
|
1553
1666
|
handler: async () => {
|
|
1554
|
-
const
|
|
1667
|
+
const root = process.cwd();
|
|
1668
|
+
const extensionPath = this.fs.join(root, "alepha.config.ts");
|
|
1555
1669
|
if (!await this.fs.exists(extensionPath)) return;
|
|
1556
1670
|
const { default: Extension } = await import(extensionPath);
|
|
1557
1671
|
if (typeof Extension !== "function") return;
|
|
@@ -1563,13 +1677,21 @@ const AlephaCli = $module({
|
|
|
1563
1677
|
name: "alepha.cli",
|
|
1564
1678
|
services: [
|
|
1565
1679
|
AlephaCliExtension,
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1680
|
+
BuildCommand,
|
|
1681
|
+
CleanCommand,
|
|
1682
|
+
DbCommand,
|
|
1683
|
+
DeployCommand,
|
|
1684
|
+
DevCommand,
|
|
1685
|
+
FormatCommand,
|
|
1686
|
+
InitCommand,
|
|
1687
|
+
LintCommand,
|
|
1688
|
+
RootCommand,
|
|
1689
|
+
RunCommand,
|
|
1690
|
+
TestCommand,
|
|
1691
|
+
TypecheckCommand,
|
|
1692
|
+
VerifyCommand,
|
|
1693
|
+
GenCommand,
|
|
1694
|
+
GitProvider
|
|
1573
1695
|
]
|
|
1574
1696
|
});
|
|
1575
1697
|
|
|
@@ -1606,7 +1728,10 @@ var AlephaPackageBuilderCli = class {
|
|
|
1606
1728
|
pkgData.exports["./tsconfig.base"] = "./tsconfig.base.json";
|
|
1607
1729
|
pkgData.exports["./package.json"] = "./package.json";
|
|
1608
1730
|
}
|
|
1609
|
-
if (packageName === "@alepha/ui")
|
|
1731
|
+
if (packageName === "@alepha/ui") {
|
|
1732
|
+
pkgData.exports["./styles"] = "./src/core/styles.css";
|
|
1733
|
+
pkgData.exports["./json/styles"] = "./src/json/styles.css";
|
|
1734
|
+
}
|
|
1610
1735
|
await this.fs.writeFile("package.json", JSON.stringify(pkgData, null, 2));
|
|
1611
1736
|
const tmpDir = join(root, "node_modules/.alepha");
|
|
1612
1737
|
await this.fs.mkdir(tmpDir, { recursive: true }).catch(() => {});
|
|
@@ -1767,11 +1892,16 @@ async function analyzeModules(srcDir, packageName) {
|
|
|
1767
1892
|
//#region ../../src/cli/defineConfig.ts
|
|
1768
1893
|
const defineConfig = (config) => {
|
|
1769
1894
|
return (alepha) => {
|
|
1770
|
-
const { commands } = config(alepha);
|
|
1895
|
+
const { commands, services = [] } = config(alepha);
|
|
1896
|
+
for (const it of services) alepha.with(it);
|
|
1771
1897
|
return { ...commands };
|
|
1772
1898
|
};
|
|
1773
1899
|
};
|
|
1900
|
+
/**
|
|
1901
|
+
* @alias defineConfig
|
|
1902
|
+
*/
|
|
1903
|
+
const defineAlephaConfig = defineConfig;
|
|
1774
1904
|
|
|
1775
1905
|
//#endregion
|
|
1776
|
-
export { AlephaCli, AlephaCliUtils, AlephaPackageBuilderCli,
|
|
1906
|
+
export { AlephaCli, AlephaCliUtils, AlephaPackageBuilderCli, BuildCommand, ChangelogCommand, CleanCommand, DEFAULT_IGNORE, DbCommand, DeployCommand, DevCommand, FormatCommand, GitMessageParser, GitProvider, InitCommand, LintCommand, OpenApiCommand, RootCommand, RunCommand, TestCommand, TypecheckCommand, VerifyCommand, analyzeModules, changelogOptions, defineAlephaConfig, defineConfig, version };
|
|
1777
1907
|
//# sourceMappingURL=index.js.map
|