alepha 0.14.2 → 0.14.4
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 +1 -1
- 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 +706 -785
- 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 +58 -137
- 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 +29 -108
- 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 +504 -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 +277 -351
- 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 +787 -852
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +827 -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 +128 -128
- 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/bin/index.d.ts +1 -2
- package/dist/bin/index.js +0 -1
- package/dist/bin/index.js.map +1 -1
- package/dist/cli/index.d.ts +252 -131
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +595 -395
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +46 -11
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +99 -19
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +40 -22
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +45 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +40 -22
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +40 -22
- package/dist/core/index.native.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/logger/index.d.ts +1 -1
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +12 -2
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/index.d.ts +59 -195
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +201 -430
- package/dist/orm/index.js.map +1 -1
- package/dist/security/index.d.ts +1 -1
- 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.d.ts +12 -0
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +55 -2
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +6 -0
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +38 -1
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/core/index.browser.js +2 -2
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +10 -10
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +7 -4
- package/dist/server/core/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/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js +4 -0
- package/dist/server/static/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 +9 -5
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/vite/index.d.ts +101 -106
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +574 -503
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +7 -7
- 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 +9 -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 +25 -6
- package/src/cli/atoms/buildOptions.ts +88 -0
- package/src/cli/commands/build.ts +32 -69
- package/src/cli/commands/db.ts +0 -4
- package/src/cli/commands/dev.ts +34 -10
- package/src/cli/commands/gen/changelog.spec.ts +315 -0
- package/src/cli/commands/{changelog.ts → gen/changelog.ts} +9 -9
- package/src/cli/commands/gen/env.ts +53 -0
- package/src/cli/commands/gen/openapi.ts +71 -0
- package/src/cli/commands/gen/resource.ts +15 -0
- package/src/cli/commands/gen.ts +24 -0
- package/src/cli/commands/init.ts +2 -1
- package/src/cli/commands/root.ts +12 -3
- package/src/cli/commands/test.ts +0 -1
- package/src/cli/commands/typecheck.ts +5 -0
- package/src/cli/commands/verify.ts +1 -1
- package/src/cli/defineConfig.ts +49 -7
- package/src/cli/index.ts +2 -2
- package/src/cli/services/AlephaCliUtils.ts +105 -55
- 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/helpers/Runner.ts +1 -1
- package/src/command/primitives/$command.spec.ts +1588 -0
- package/src/command/primitives/$command.ts +0 -6
- package/src/command/providers/CliProvider.ts +75 -27
- package/src/core/Alepha.ts +87 -0
- 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/index.ts +15 -3
- 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/mcp/transports/StdioMcpTransport.ts +1 -1
- 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.ts +2 -8
- 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/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 +394 -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 +1125 -0
- package/src/server/cache/providers/ServerCacheProvider.ts +94 -9
- package/src/server/compress/providers/ServerCompressProvider.spec.ts +31 -0
- package/src/server/compress/providers/ServerCompressProvider.ts +63 -2
- 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/helpers/ServerReply.ts +2 -2
- 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 +14 -2
- 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/static/providers/ServerStaticProvider.ts +10 -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 +19 -12
- 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/helpers/importViteReact.ts +13 -0
- package/src/vite/index.ts +1 -21
- package/src/vite/plugins/viteAlephaDev.ts +32 -5
- package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
- package/src/vite/tasks/buildClient.ts +11 -0
- package/src/vite/tasks/buildServer.ts +47 -3
- package/src/vite/tasks/devServer.ts +69 -0
- package/src/vite/tasks/index.ts +2 -1
- 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/assets/viteConfigTs.ts +0 -14
- package/src/cli/commands/run.ts +0 -24
- package/src/vite/plugins/viteAlepha.ts +0 -37
- package/src/vite/plugins/viteAlephaBuild.ts +0 -281
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { dirname, join, relative, resolve } from "node:path";
|
|
4
|
+
import type { Plugin } from "vite";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Preload manifest mapping short keys to source paths.
|
|
8
|
+
* Generated at build time, consumed by SSRManifestProvider at runtime.
|
|
9
|
+
*/
|
|
10
|
+
export interface PreloadManifest {
|
|
11
|
+
[key: string]: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Vite plugin that generates a preload manifest for SSR module preloading.
|
|
16
|
+
*
|
|
17
|
+
* Instead of injecting source paths directly into $page definitions (which would
|
|
18
|
+
* leak component paths in the browser bundle), this plugin:
|
|
19
|
+
*
|
|
20
|
+
* 1. Collects all lazy import paths from $page definitions during transform
|
|
21
|
+
* 2. Generates a manifest file mapping short keys to resolved source paths
|
|
22
|
+
* 3. Injects only the short key into $page definitions
|
|
23
|
+
*
|
|
24
|
+
* The manifest is written to `.vite/preload-manifest.json` alongside Vite's
|
|
25
|
+
* other manifests. The CLI build command moves all manifests to
|
|
26
|
+
* `dist/server/.ssr/` where SSRManifestProvider loads them at runtime.
|
|
27
|
+
*
|
|
28
|
+
* Before:
|
|
29
|
+
* ```typescript
|
|
30
|
+
* $page({
|
|
31
|
+
* path: '/users/:id',
|
|
32
|
+
* lazy: () => import('./UserDetail.tsx'),
|
|
33
|
+
* })
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* After:
|
|
37
|
+
* ```typescript
|
|
38
|
+
* $page({
|
|
39
|
+
* path: '/users/:id',
|
|
40
|
+
* lazy: () => import('./UserDetail.tsx'),
|
|
41
|
+
* [Symbol.for("alepha.page.preload")]: "a1b2c3",
|
|
42
|
+
* })
|
|
43
|
+
* ```
|
|
44
|
+
*
|
|
45
|
+
* Manifest (.alepha/preload-manifest.json):
|
|
46
|
+
* ```json
|
|
47
|
+
* {
|
|
48
|
+
* "a1b2c3": "src/pages/UserDetail.tsx"
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export function viteAlephaSsrPreload(): Plugin {
|
|
53
|
+
let root = "";
|
|
54
|
+
const preloadMap = new Map<string, string>(); // key -> sourcePath
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Generate a short hash key for a source path.
|
|
58
|
+
* Uses first 8 chars of MD5 hash for brevity while avoiding collisions.
|
|
59
|
+
*/
|
|
60
|
+
function generateKey(sourcePath: string): string {
|
|
61
|
+
return createHash("md5").update(sourcePath).digest("hex").slice(0, 8);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
name: "alepha-preload",
|
|
66
|
+
configResolved(config) {
|
|
67
|
+
root = config.root;
|
|
68
|
+
},
|
|
69
|
+
transform(code, id) {
|
|
70
|
+
// Only process TypeScript/JavaScript files
|
|
71
|
+
if (!id.match(/\.[tj]sx?$/)) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Skip node_modules
|
|
76
|
+
if (id.includes("node_modules")) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Quick check if file contains $page with lazy
|
|
81
|
+
if (!code.includes("$page") || !code.includes("lazy")) {
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Collect all insertions first, then apply in reverse order
|
|
86
|
+
const insertions: Array<{ position: number; text: string }> = [];
|
|
87
|
+
|
|
88
|
+
// Find all $page({ occurrences
|
|
89
|
+
const pageStartRegex = /\$page\s*\(\s*\{/g;
|
|
90
|
+
let pageMatch: RegExpExecArray | null = pageStartRegex.exec(code);
|
|
91
|
+
|
|
92
|
+
while (pageMatch !== null) {
|
|
93
|
+
const startIndex = pageMatch.index;
|
|
94
|
+
const objectStartIndex = startIndex + pageMatch[0].length - 1; // Position of '{'
|
|
95
|
+
|
|
96
|
+
// Find the matching closing brace using brace counting
|
|
97
|
+
let braceCount = 1;
|
|
98
|
+
let i = objectStartIndex + 1;
|
|
99
|
+
while (i < code.length && braceCount > 0) {
|
|
100
|
+
if (code[i] === "{") braceCount++;
|
|
101
|
+
else if (code[i] === "}") braceCount--;
|
|
102
|
+
i++;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Malformed, skip
|
|
106
|
+
if (braceCount !== 0) {
|
|
107
|
+
pageMatch = pageStartRegex.exec(code);
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const objectEndIndex = i - 1; // Position of matching '}'
|
|
112
|
+
const pageContent = code.slice(objectStartIndex, objectEndIndex + 1);
|
|
113
|
+
|
|
114
|
+
// Skip if already has preload symbol
|
|
115
|
+
if (pageContent.includes("alepha.page.preload")) {
|
|
116
|
+
pageMatch = pageStartRegex.exec(code);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Find lazy: () => import('...') within this $page block
|
|
121
|
+
const lazyRegex =
|
|
122
|
+
/lazy\s*:\s*\(\s*\)\s*=>\s*import\s*\(\s*['"]([^'"]+)['"]\s*\)/;
|
|
123
|
+
const lazyMatch = lazyRegex.exec(pageContent);
|
|
124
|
+
|
|
125
|
+
if (!lazyMatch) {
|
|
126
|
+
pageMatch = pageStartRegex.exec(code);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const importPath = lazyMatch[1];
|
|
131
|
+
|
|
132
|
+
// Resolve the import path relative to the current file
|
|
133
|
+
const currentDir = dirname(id);
|
|
134
|
+
let resolvedPath: string;
|
|
135
|
+
|
|
136
|
+
if (importPath.startsWith(".")) {
|
|
137
|
+
// Relative import
|
|
138
|
+
resolvedPath = resolve(currentDir, importPath);
|
|
139
|
+
} else if (importPath.startsWith("/")) {
|
|
140
|
+
// Absolute import from root
|
|
141
|
+
resolvedPath = resolve(root, importPath.slice(1));
|
|
142
|
+
} else {
|
|
143
|
+
// Package import - skip preloading for external packages
|
|
144
|
+
pageMatch = pageStartRegex.exec(code);
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Make path relative to root for SSR manifest lookup
|
|
149
|
+
let relativePath = relative(root, resolvedPath);
|
|
150
|
+
|
|
151
|
+
// Normalize path separators for cross-platform compatibility
|
|
152
|
+
relativePath = relativePath.replace(/\\/g, "/");
|
|
153
|
+
|
|
154
|
+
// Handle extension - Vite resolves .jsx imports to .tsx files
|
|
155
|
+
// Try to use .tsx when the source has .jsx since TypeScript is more common
|
|
156
|
+
if (!relativePath.match(/\.[tj]sx?$/)) {
|
|
157
|
+
relativePath = `${relativePath}.tsx`;
|
|
158
|
+
} else if (relativePath.endsWith(".jsx")) {
|
|
159
|
+
// Import said .jsx but actual file is likely .tsx
|
|
160
|
+
relativePath = relativePath.replace(/\.jsx$/, ".tsx");
|
|
161
|
+
} else if (relativePath.endsWith(".js")) {
|
|
162
|
+
// Import said .js but actual file is likely .ts
|
|
163
|
+
relativePath = relativePath.replace(/\.js$/, ".ts");
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Generate short key and store mapping
|
|
167
|
+
const key = generateKey(relativePath);
|
|
168
|
+
preloadMap.set(key, relativePath);
|
|
169
|
+
|
|
170
|
+
// Check if we need a comma (look at character before closing brace)
|
|
171
|
+
const beforeBrace = code.slice(0, objectEndIndex).trimEnd();
|
|
172
|
+
const needsComma = !beforeBrace.endsWith(",");
|
|
173
|
+
// Use Symbol.for() so it can be looked up at runtime without importing
|
|
174
|
+
// Only inject the short key, not the full path
|
|
175
|
+
const preloadProperty = `${needsComma ? "," : ""} [Symbol.for("alepha.page.preload")]: "${key}"`;
|
|
176
|
+
|
|
177
|
+
insertions.push({ position: objectEndIndex, text: preloadProperty });
|
|
178
|
+
|
|
179
|
+
pageMatch = pageStartRegex.exec(code);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
if (insertions.length === 0) {
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Apply insertions in reverse order to preserve positions
|
|
187
|
+
let result = code;
|
|
188
|
+
for (let j = insertions.length - 1; j >= 0; j--) {
|
|
189
|
+
const { position, text } = insertions[j];
|
|
190
|
+
result = result.slice(0, position) + text + result.slice(position);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
code: result,
|
|
195
|
+
map: null,
|
|
196
|
+
};
|
|
197
|
+
},
|
|
198
|
+
writeBundle(options) {
|
|
199
|
+
// Only process client build (outputs to dist/public or similar)
|
|
200
|
+
// Skip server build which outputs to dist/server
|
|
201
|
+
const outDir = options.dir || "";
|
|
202
|
+
if (outDir.includes("server")) {
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// Write the preload manifest to the same .vite directory Vite uses
|
|
207
|
+
// The CLI build command will move all manifests to dist/server/.ssr/
|
|
208
|
+
if (preloadMap.size > 0) {
|
|
209
|
+
const viteDir = join(outDir, ".vite");
|
|
210
|
+
|
|
211
|
+
// Ensure .vite directory exists
|
|
212
|
+
if (!existsSync(viteDir)) {
|
|
213
|
+
mkdirSync(viteDir, { recursive: true });
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const manifest: PreloadManifest = Object.fromEntries(preloadMap);
|
|
217
|
+
const manifestPath = join(viteDir, "preload-manifest.json");
|
|
218
|
+
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2));
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
};
|
|
222
|
+
}
|
|
@@ -2,6 +2,8 @@ import type { UserConfig } from "vite";
|
|
|
2
2
|
import { analyzer as viteAnalyzer } from "vite-bundle-analyzer";
|
|
3
3
|
import { createBufferedLogger } from "../helpers/createBufferedLogger.ts";
|
|
4
4
|
import { importVite } from "../helpers/importVite.ts";
|
|
5
|
+
import { importViteReact } from "../helpers/importViteReact.ts";
|
|
6
|
+
import { viteAlephaSsrPreload } from "../plugins/viteAlephaSsrPreload.ts";
|
|
5
7
|
import {
|
|
6
8
|
type ViteCompressOptions,
|
|
7
9
|
viteCompress,
|
|
@@ -62,6 +64,12 @@ export async function buildClient(opts: BuildClientOptions): Promise<void> {
|
|
|
62
64
|
const { build: viteBuild, mergeConfig } = await importVite();
|
|
63
65
|
const plugins: any[] = [];
|
|
64
66
|
|
|
67
|
+
const viteReact = await importViteReact();
|
|
68
|
+
if (viteReact) plugins.push(viteReact());
|
|
69
|
+
|
|
70
|
+
// Add preload plugin for SSR module preloading
|
|
71
|
+
plugins.push(viteAlephaSsrPreload());
|
|
72
|
+
|
|
65
73
|
const compress: ViteCompressOptions | undefined = opts.precompress
|
|
66
74
|
? typeof opts.precompress === "object"
|
|
67
75
|
? opts.precompress
|
|
@@ -93,6 +101,9 @@ export async function buildClient(opts: BuildClientOptions): Promise<void> {
|
|
|
93
101
|
build: {
|
|
94
102
|
chunkSizeWarningLimit: 1000,
|
|
95
103
|
outDir: opts.dist,
|
|
104
|
+
// Generate manifest for SSR module preloading
|
|
105
|
+
manifest: true,
|
|
106
|
+
ssrManifest: true,
|
|
96
107
|
rollupOptions: {
|
|
97
108
|
output: {
|
|
98
109
|
entryFileNames: "entry.[hash].js",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { readFile, writeFile } from "node:fs/promises";
|
|
1
|
+
import { readFile, rm, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
import { AlephaError } from "alepha";
|
|
4
4
|
import type * as vite from "vite";
|
|
@@ -6,6 +6,8 @@ import type { UserConfig } from "vite";
|
|
|
6
6
|
import { analyzer as viteAnalyzer } from "vite-bundle-analyzer";
|
|
7
7
|
import { createBufferedLogger } from "../helpers/createBufferedLogger.ts";
|
|
8
8
|
import { importVite } from "../helpers/importVite.ts";
|
|
9
|
+
import { importViteReact } from "../helpers/importViteReact.ts";
|
|
10
|
+
import { viteAlephaSsrPreload } from "../plugins/viteAlephaSsrPreload.ts";
|
|
9
11
|
import { generateExternals } from "./generateExternals.ts";
|
|
10
12
|
|
|
11
13
|
export interface BuildServerOptions {
|
|
@@ -63,6 +65,13 @@ export async function buildServer(
|
|
|
63
65
|
const { build: viteBuild, mergeConfig } = await importVite();
|
|
64
66
|
const plugins: any[] = [];
|
|
65
67
|
|
|
68
|
+
const viteReact = await importViteReact();
|
|
69
|
+
if (viteReact && opts.clientDir) {
|
|
70
|
+
plugins.push(viteReact());
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
plugins.push(viteAlephaSsrPreload());
|
|
74
|
+
|
|
66
75
|
if (opts.stats) {
|
|
67
76
|
plugins.push(
|
|
68
77
|
viteAnalyzer({
|
|
@@ -85,7 +94,7 @@ export async function buildServer(
|
|
|
85
94
|
noExternal: true,
|
|
86
95
|
},
|
|
87
96
|
build: {
|
|
88
|
-
sourcemap: true,
|
|
97
|
+
sourcemap: true,
|
|
89
98
|
ssr: opts.entry,
|
|
90
99
|
outDir: `${opts.distDir}/server`,
|
|
91
100
|
minify: true,
|
|
@@ -138,6 +147,29 @@ export async function buildServer(
|
|
|
138
147
|
template = `__alepha.set("alepha.react.server.template", \`${index.replace(/>\s*</g, "><").trim()}\`);\n`;
|
|
139
148
|
}
|
|
140
149
|
|
|
150
|
+
// Embed SSR manifests if client was built
|
|
151
|
+
// This bundles all manifest data into index.js for serverless deployments
|
|
152
|
+
let manifest = "";
|
|
153
|
+
if (opts.clientDir) {
|
|
154
|
+
const viteDir = `${opts.distDir}/${opts.clientDir}/.vite`;
|
|
155
|
+
const ssrManifest = await loadJsonFile(`${viteDir}/ssr-manifest.json`);
|
|
156
|
+
const clientManifest = await loadJsonFile(`${viteDir}/manifest.json`);
|
|
157
|
+
const preloadManifest = await loadJsonFile(
|
|
158
|
+
`${viteDir}/preload-manifest.json`,
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const combined = {
|
|
162
|
+
ssr: ssrManifest,
|
|
163
|
+
client: clientManifest,
|
|
164
|
+
preload: preloadManifest,
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
manifest = `__alepha.set("alepha.react.ssr.manifest", ${JSON.stringify(combined)});\n`;
|
|
168
|
+
|
|
169
|
+
// Remove .vite directory - no longer needed at runtime
|
|
170
|
+
await rm(viteDir, { recursive: true, force: true });
|
|
171
|
+
}
|
|
172
|
+
|
|
141
173
|
const warning =
|
|
142
174
|
"// This file was automatically generated. DO NOT MODIFY." +
|
|
143
175
|
"\n" +
|
|
@@ -145,12 +177,24 @@ export async function buildServer(
|
|
|
145
177
|
|
|
146
178
|
await writeFile(
|
|
147
179
|
`${opts.distDir}/index.js`,
|
|
148
|
-
`${warning}\
|
|
180
|
+
`${warning}\n${template}${manifest}import './server/${entryFile}';\n`.trim(),
|
|
149
181
|
);
|
|
150
182
|
|
|
151
183
|
return { entryFile };
|
|
152
184
|
}
|
|
153
185
|
|
|
186
|
+
/**
|
|
187
|
+
* Load a JSON file, returning undefined if it doesn't exist.
|
|
188
|
+
*/
|
|
189
|
+
async function loadJsonFile(path: string): Promise<any> {
|
|
190
|
+
try {
|
|
191
|
+
const content = await readFile(path, "utf-8");
|
|
192
|
+
return JSON.parse(content);
|
|
193
|
+
} catch {
|
|
194
|
+
return undefined;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
154
198
|
/**
|
|
155
199
|
* Extract entry filename from Vite build result.
|
|
156
200
|
*/
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { InlineConfig } from "vite";
|
|
2
|
+
import { importVite } from "../helpers/importVite.ts";
|
|
3
|
+
import { importViteReact } from "../helpers/importViteReact.ts";
|
|
4
|
+
import { viteAlephaDev } from "../plugins/viteAlephaDev.ts";
|
|
5
|
+
import { viteAlephaSsrPreload } from "../plugins/viteAlephaSsrPreload.ts";
|
|
6
|
+
|
|
7
|
+
export interface DevServerOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Path to the server entry file.
|
|
10
|
+
* If not provided, will auto-detect.
|
|
11
|
+
*/
|
|
12
|
+
entry?: string;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Port to run the dev server on.
|
|
16
|
+
*/
|
|
17
|
+
port?: number;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Host to bind the dev server to.
|
|
21
|
+
*/
|
|
22
|
+
host?: string | boolean;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Enable debug logging.
|
|
26
|
+
*/
|
|
27
|
+
debug?: boolean;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Start Vite development server with Alepha plugins.
|
|
32
|
+
*
|
|
33
|
+
* This task starts the Vite dev server with all required plugins:
|
|
34
|
+
* - @vitejs/plugin-react (JSX/TSX compilation)
|
|
35
|
+
* - viteAlephaDev (Alepha server integration)
|
|
36
|
+
* - viteAlephaSsrPreload (SSR module preloading)
|
|
37
|
+
*/
|
|
38
|
+
export async function devServer(opts: DevServerOptions = {}): Promise<void> {
|
|
39
|
+
const { createServer, mergeConfig } = await importVite();
|
|
40
|
+
const plugins: any[] = [];
|
|
41
|
+
|
|
42
|
+
// Add React plugin for JSX/TSX compilation
|
|
43
|
+
const viteReact = await importViteReact();
|
|
44
|
+
if (viteReact) plugins.push(viteReact());
|
|
45
|
+
|
|
46
|
+
// Add SSR preload plugin
|
|
47
|
+
plugins.push(viteAlephaSsrPreload());
|
|
48
|
+
|
|
49
|
+
// Add Alepha dev plugin
|
|
50
|
+
plugins.push(
|
|
51
|
+
await viteAlephaDev({
|
|
52
|
+
serverEntry: opts.entry,
|
|
53
|
+
debug: opts.debug,
|
|
54
|
+
}),
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const config: InlineConfig = {
|
|
58
|
+
plugins,
|
|
59
|
+
server: {
|
|
60
|
+
port: opts.port,
|
|
61
|
+
host: opts.host,
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const server = await createServer(mergeConfig(config, {}));
|
|
66
|
+
await server.listen();
|
|
67
|
+
|
|
68
|
+
// server.printUrls();
|
|
69
|
+
}
|
package/src/vite/tasks/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Build tasks for Alepha applications.
|
|
3
3
|
*
|
|
4
4
|
* These tasks can be used by:
|
|
5
|
-
* - Vite plugins (viteAlephaDev,
|
|
5
|
+
* - Vite plugins (viteAlephaDev, viteAlephaSsrPreload)
|
|
6
6
|
* - CLI commands (alepha build, alepha dev)
|
|
7
7
|
*
|
|
8
8
|
* Each task is a standalone async function with explicit inputs and outputs.
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
export * from "./buildClient.ts";
|
|
14
14
|
export * from "./buildServer.ts";
|
|
15
15
|
export * from "./copyAssets.ts";
|
|
16
|
+
export * from "./devServer.ts";
|
|
16
17
|
export * from "./generateCloudflare.ts";
|
|
17
18
|
export * from "./generateDocker.ts";
|
|
18
19
|
export * from "./generateExternals.ts";
|
|
@@ -132,13 +132,19 @@ export class AlephaRunner {
|
|
|
132
132
|
process.env[key] = env[key];
|
|
133
133
|
}
|
|
134
134
|
|
|
135
|
+
let port = 5173;
|
|
136
|
+
const address = server.httpServer?.address();
|
|
137
|
+
if (typeof address === "object" && address?.port) {
|
|
138
|
+
port = address.port;
|
|
139
|
+
}
|
|
140
|
+
|
|
135
141
|
process.env.NODE_ENV ??= "development";
|
|
136
142
|
process.env.VITE_ALEPHA_DEV = "true";
|
|
137
143
|
process.env.SERVER_HOST ??=
|
|
138
144
|
typeof server.config.server.host === "string"
|
|
139
145
|
? server.config.server.host
|
|
140
146
|
: "localhost";
|
|
141
|
-
process.env.SERVER_PORT ??= String(
|
|
147
|
+
process.env.SERVER_PORT ??= String(port);
|
|
142
148
|
|
|
143
149
|
try {
|
|
144
150
|
const now = Date.now();
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { Alepha, t } from "alepha";
|
|
2
|
+
import { NodeHttpServerProvider } from "alepha/server";
|
|
3
|
+
import { test } from "vitest";
|
|
4
|
+
import WebSocket from "ws";
|
|
5
|
+
import { AlephaWebSocket } from "../index.ts";
|
|
6
|
+
import { $channel } from "../primitives/$channel.ts";
|
|
7
|
+
import { $websocket } from "../primitives/$websocket.ts";
|
|
8
|
+
|
|
9
|
+
test("$websocket with channel-based architecture", async ({ expect }) => {
|
|
10
|
+
const alepha = Alepha.create().with(AlephaWebSocket);
|
|
11
|
+
|
|
12
|
+
const messages: any[] = [];
|
|
13
|
+
|
|
14
|
+
class ChatController {
|
|
15
|
+
// Define channel inside the class
|
|
16
|
+
chatChannel = $channel({
|
|
17
|
+
path: "/ws/chat",
|
|
18
|
+
schema: {
|
|
19
|
+
// Server → Client messages
|
|
20
|
+
in: t.union([
|
|
21
|
+
t.object({
|
|
22
|
+
type: t.const("append"),
|
|
23
|
+
content: t.text(),
|
|
24
|
+
username: t.text(),
|
|
25
|
+
}),
|
|
26
|
+
t.object({
|
|
27
|
+
type: t.const("system"),
|
|
28
|
+
message: t.text(),
|
|
29
|
+
}),
|
|
30
|
+
]),
|
|
31
|
+
// Client → Server messages
|
|
32
|
+
out: t.object({
|
|
33
|
+
content: t.text(),
|
|
34
|
+
}),
|
|
35
|
+
},
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
chat = $websocket({
|
|
39
|
+
channel: this.chatChannel,
|
|
40
|
+
handler: async ({ connectionId, roomId, message, reply }) => {
|
|
41
|
+
// Broadcast to all in room except sender
|
|
42
|
+
await reply({
|
|
43
|
+
message: {
|
|
44
|
+
type: "append",
|
|
45
|
+
content: message.content,
|
|
46
|
+
username: connectionId,
|
|
47
|
+
},
|
|
48
|
+
exceptSelf: true,
|
|
49
|
+
});
|
|
50
|
+
},
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const controller = alepha.inject(ChatController);
|
|
55
|
+
await alepha.start();
|
|
56
|
+
|
|
57
|
+
const httpServer = alepha.inject(NodeHttpServerProvider);
|
|
58
|
+
const hostname = httpServer.hostname.replace("http://", "ws://");
|
|
59
|
+
|
|
60
|
+
// Connect two clients to the same room
|
|
61
|
+
const ws1 = new WebSocket(`${hostname}/ws/chat?roomId=room-1`);
|
|
62
|
+
const ws2 = new WebSocket(`${hostname}/ws/chat?roomId=room-1`);
|
|
63
|
+
|
|
64
|
+
await Promise.all([
|
|
65
|
+
new Promise((resolve) => ws1.on("open", resolve)),
|
|
66
|
+
new Promise((resolve) => ws2.on("open", resolve)),
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
// Listen for messages on ws2
|
|
70
|
+
ws2.on("message", (data) => {
|
|
71
|
+
const message = JSON.parse(data.toString());
|
|
72
|
+
messages.push(message);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Wait a bit for connections to be established
|
|
76
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
77
|
+
|
|
78
|
+
// Send message from ws1
|
|
79
|
+
ws1.send(
|
|
80
|
+
JSON.stringify({
|
|
81
|
+
roomId: "room-1",
|
|
82
|
+
message: {
|
|
83
|
+
content: "Hello from client 1!",
|
|
84
|
+
},
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
// Wait for message to be received
|
|
89
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
90
|
+
|
|
91
|
+
// ws2 should receive the message, but not ws1 (exceptSelf)
|
|
92
|
+
expect(messages.length).toBe(1);
|
|
93
|
+
expect(messages[0].type).toBe("append");
|
|
94
|
+
expect(messages[0].content).toBe("Hello from client 1!");
|
|
95
|
+
expect(messages[0].username).toContain("ws-");
|
|
96
|
+
|
|
97
|
+
// Test emit API from server
|
|
98
|
+
await controller.chat.emit({
|
|
99
|
+
roomId: "room-1",
|
|
100
|
+
message: {
|
|
101
|
+
type: "system",
|
|
102
|
+
message: "Server announcement",
|
|
103
|
+
},
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
107
|
+
|
|
108
|
+
// Both clients should receive the system message
|
|
109
|
+
expect(messages.length).toBe(2);
|
|
110
|
+
expect(messages[1].type).toBe("system");
|
|
111
|
+
expect(messages[1].message).toBe("Server announcement");
|
|
112
|
+
|
|
113
|
+
ws1.close();
|
|
114
|
+
ws2.close();
|
|
115
|
+
await alepha.stop();
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
test("$websocket room isolation", async ({ expect }) => {
|
|
119
|
+
const alepha = Alepha.create().with(AlephaWebSocket);
|
|
120
|
+
|
|
121
|
+
class ChatController {
|
|
122
|
+
chatChannel = $channel({
|
|
123
|
+
path: "/ws/chat",
|
|
124
|
+
schema: {
|
|
125
|
+
in: t.object({
|
|
126
|
+
type: t.const("message"),
|
|
127
|
+
content: t.text(),
|
|
128
|
+
}),
|
|
129
|
+
out: t.object({
|
|
130
|
+
content: t.text(),
|
|
131
|
+
}),
|
|
132
|
+
},
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
chat = $websocket({
|
|
136
|
+
channel: this.chatChannel,
|
|
137
|
+
handler: async ({ roomId, message, reply }) => {
|
|
138
|
+
await reply({
|
|
139
|
+
message: {
|
|
140
|
+
type: "message",
|
|
141
|
+
content: message.content,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
},
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const controller = alepha.inject(ChatController);
|
|
149
|
+
await alepha.start();
|
|
150
|
+
|
|
151
|
+
const httpServer = alepha.inject(NodeHttpServerProvider);
|
|
152
|
+
const hostname = httpServer.hostname.replace("http://", "ws://");
|
|
153
|
+
|
|
154
|
+
// Connect clients to different rooms
|
|
155
|
+
const room1Client = new WebSocket(`${hostname}/ws/chat?roomId=room-1`);
|
|
156
|
+
const room2Client = new WebSocket(`${hostname}/ws/chat?roomId=room-2`);
|
|
157
|
+
|
|
158
|
+
await Promise.all([
|
|
159
|
+
new Promise((resolve) => room1Client.on("open", resolve)),
|
|
160
|
+
new Promise((resolve) => room2Client.on("open", resolve)),
|
|
161
|
+
]);
|
|
162
|
+
|
|
163
|
+
const room1Messages: any[] = [];
|
|
164
|
+
const room2Messages: any[] = [];
|
|
165
|
+
|
|
166
|
+
room1Client.on("message", (data) => {
|
|
167
|
+
room1Messages.push(JSON.parse(data.toString()));
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
room2Client.on("message", (data) => {
|
|
171
|
+
room2Messages.push(JSON.parse(data.toString()));
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
await new Promise((resolve) => setTimeout(resolve, 100));
|
|
175
|
+
|
|
176
|
+
// Send to room-1 only
|
|
177
|
+
await controller.chat.emit({
|
|
178
|
+
roomId: "room-1",
|
|
179
|
+
message: {
|
|
180
|
+
type: "message",
|
|
181
|
+
content: "Message for room 1",
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
await new Promise((resolve) => setTimeout(resolve, 200));
|
|
186
|
+
|
|
187
|
+
// Only room1Client should receive the message
|
|
188
|
+
expect(room1Messages.length).toBe(1);
|
|
189
|
+
expect(room1Messages[0].content).toBe("Message for room 1");
|
|
190
|
+
expect(room2Messages.length).toBe(0);
|
|
191
|
+
|
|
192
|
+
room1Client.close();
|
|
193
|
+
room2Client.close();
|
|
194
|
+
await alepha.stop();
|
|
195
|
+
});
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Alepha, t } from "alepha";
|
|
2
|
+
import { test } from "vitest";
|
|
3
|
+
import { $channel } from "../primitives/$channel.ts";
|
|
4
|
+
|
|
5
|
+
test("$channel should create a channel primitive", async ({ expect }) => {
|
|
6
|
+
const alepha = Alepha.create();
|
|
7
|
+
|
|
8
|
+
class TestApp {
|
|
9
|
+
chat = $channel({
|
|
10
|
+
path: "/ws/chat",
|
|
11
|
+
description: "Chat channel",
|
|
12
|
+
schema: {
|
|
13
|
+
in: t.object({
|
|
14
|
+
type: t.const("message"),
|
|
15
|
+
content: t.text(),
|
|
16
|
+
}),
|
|
17
|
+
out: t.object({
|
|
18
|
+
content: t.text(),
|
|
19
|
+
}),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const app = alepha.inject(TestApp);
|
|
25
|
+
|
|
26
|
+
expect(app.chat).toBeDefined();
|
|
27
|
+
expect(app.chat.options.path).toBe("/ws/chat");
|
|
28
|
+
expect(app.chat.options.schema.in).toBeDefined();
|
|
29
|
+
expect(app.chat.options.schema.out).toBeDefined();
|
|
30
|
+
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export const viteConfigTs = (
|
|
2
|
-
serverEntry?: string,
|
|
3
|
-
) => `
|
|
4
|
-
import { viteAlepha } from "alepha/vite";
|
|
5
|
-
|
|
6
|
-
export default {
|
|
7
|
-
plugins: [
|
|
8
|
-
viteAlepha(${serverEntry ? `{ serverEntry: "${serverEntry}" }` : ""}),
|
|
9
|
-
],
|
|
10
|
-
test: {
|
|
11
|
-
globals: true,
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
`.trim();
|