alepha 0.21.2 → 0.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -1
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts +393 -403
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +25 -56
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.browser.js +31 -1
- package/dist/api/files/index.browser.js.map +1 -1
- package/dist/api/files/index.d.ts +313 -208
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +152 -42
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +2 -2
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +289 -292
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +39 -33
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +211 -216
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +188 -195
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/oauth/index.d.ts +71 -76
- package/dist/api/oauth/index.d.ts.map +1 -1
- package/dist/api/oauth/index.js.map +1 -1
- package/dist/api/organizations/index.browser.js.map +1 -1
- package/dist/api/organizations/index.d.ts +104 -109
- package/dist/api/organizations/index.d.ts.map +1 -1
- package/dist/api/organizations/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +43 -16
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +488 -344
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +175 -35
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.d.ts +396 -402
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/subscriptions/index.d.ts +644 -652
- package/dist/api/subscriptions/index.d.ts.map +1 -1
- package/dist/api/subscriptions/index.js +1 -1
- package/dist/api/subscriptions/index.js.map +1 -1
- package/dist/api/users/index.browser.js +7 -0
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +1073 -1006
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +283 -61
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.browser.js.map +1 -1
- package/dist/api/verifications/index.d.ts +134 -140
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/background/index.d.ts +95 -0
- package/dist/background/index.d.ts.map +1 -0
- package/dist/background/index.js +121 -0
- package/dist/background/index.js.map +1 -0
- package/dist/background/index.workerd.js +110 -0
- package/dist/background/index.workerd.js.map +1 -0
- package/dist/batch/index.d.ts +5 -7
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/bin/index.js.map +1 -1
- package/dist/bucket/index.d.ts +76 -54
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +58 -11
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +200 -5
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.d.ts +7 -10
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/cache/database/index.d.ts +22 -26
- package/dist/cache/database/index.d.ts.map +1 -1
- package/dist/cache/database/index.js.map +1 -1
- package/dist/cache/redis/index.d.ts +4 -7
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/captcha/index.d.ts +3 -6
- package/dist/captcha/index.d.ts.map +1 -1
- package/dist/captcha/index.js.map +1 -1
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +417 -214
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +325 -563
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +3 -5
- package/dist/cli/devtools/index.d.ts.map +1 -1
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/i18n/index.d.ts +8 -12
- package/dist/cli/i18n/index.d.ts.map +1 -1
- package/dist/cli/i18n/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +126 -1342
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +136 -2374
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/platform-lib/index.d.ts +1446 -0
- package/dist/cli/platform-lib/index.d.ts.map +1 -0
- package/dist/cli/platform-lib/index.js +2597 -0
- package/dist/cli/platform-lib/index.js.map +1 -0
- package/dist/cli/vendor/index.d.ts +17 -21
- package/dist/cli/vendor/index.d.ts.map +1 -1
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.d.ts +21 -20
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +39 -10
- package/dist/command/index.js.map +1 -1
- package/dist/{containers → container}/core/index.d.ts +13 -15
- package/dist/container/core/index.d.ts.map +1 -0
- package/dist/{containers → container}/core/index.js +23 -14
- package/dist/container/core/index.js.map +1 -0
- package/dist/{containers → container}/core/index.workerd.js +37 -22
- package/dist/container/core/index.workerd.js.map +1 -0
- package/dist/core/index.browser.js +27 -1
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +48 -24
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +27 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +27 -1
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +27 -1
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.browser.js.map +1 -1
- package/dist/crypto/index.d.ts +5 -8
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.js.map +1 -1
- package/dist/datetime/index.d.ts +3 -4
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/brevo/index.d.ts +2 -4
- package/dist/email/brevo/index.d.ts.map +1 -1
- package/dist/email/brevo/index.js.map +1 -1
- package/dist/email/cloudflare/index.d.ts +20 -7
- package/dist/email/cloudflare/index.d.ts.map +1 -1
- package/dist/email/cloudflare/index.js +46 -9
- package/dist/email/cloudflare/index.js.map +1 -1
- package/dist/email/core/index.d.ts +6 -9
- package/dist/email/core/index.d.ts.map +1 -1
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/core/index.workerd.js.map +1 -1
- package/dist/email/smtp/index.d.ts +10 -13
- package/dist/email/smtp/index.d.ts.map +1 -1
- package/dist/email/smtp/index.js +107 -32
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +1 -2
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +9 -14
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.d.ts +2 -4
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/lock/redis/index.js.map +1 -1
- package/dist/logger/index.d.ts +105 -76
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +196 -174
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +16 -20
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +19 -1
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +76 -62
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +20 -2
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +28 -20
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +12 -15
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/core/index.js.map +1 -1
- package/dist/queue/core/index.workerd.js.map +1 -1
- package/dist/queue/redis/index.d.ts +3 -5
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/queue/redis/index.js.map +1 -1
- package/dist/react/auth/index.browser.js +9 -2
- package/dist/react/auth/index.browser.js.map +1 -1
- package/dist/react/auth/index.d.ts +14 -9
- package/dist/react/auth/index.d.ts.map +1 -1
- package/dist/react/auth/index.js +9 -2
- package/dist/react/auth/index.js.map +1 -1
- package/dist/react/core/index.d.ts +7 -8
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +6 -3
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +2 -4
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js.map +1 -1
- package/dist/react/head/index.browser.js.map +1 -1
- package/dist/react/head/index.d.ts +2 -4
- package/dist/react/head/index.d.ts.map +1 -1
- package/dist/react/head/index.js.map +1 -1
- package/dist/react/i18n/index.d.ts +47 -11
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/i18n/index.js +33 -1
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.d.ts +1 -2
- package/dist/react/intro/index.d.ts.map +1 -1
- package/dist/react/intro/index.js +2 -2
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +65 -19
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +327 -222
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +65 -29
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/index.d.ts +1 -2
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +16 -17
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/ui/index.d.ts +20 -25
- package/dist/react/ui/index.d.ts.map +1 -1
- package/dist/react/ui/index.js.map +1 -1
- package/dist/redis/index.bun.js.map +1 -1
- package/dist/redis/index.d.ts +17 -19
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts +2 -4
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/retry/index.js.map +1 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/router/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +10 -13
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +45 -48
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.browser.js.map +1 -1
- package/dist/server/auth/index.d.ts +167 -172
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +4 -8
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.browser.js.map +1 -1
- package/dist/server/cookies/index.d.ts +5 -7
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +88 -73
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +19 -0
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +11 -14
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/etag/index.d.ts +6 -9
- package/dist/server/etag/index.d.ts.map +1 -1
- package/dist/server/etag/index.js.map +1 -1
- package/dist/server/health/index.d.ts +18 -21
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/health/index.js.map +1 -1
- package/dist/server/links/index.browser.js +2 -0
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +63 -67
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +2 -0
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +5 -7
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/proxy/index.d.ts +3 -5
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/proxy/index.js.map +1 -1
- package/dist/server/rate-limit/index.d.ts +10 -13
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +3 -5
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +5 -8
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +3 -5
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.browser.js.map +1 -1
- package/dist/system/index.d.ts +2 -4
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js.map +1 -1
- package/dist/system/index.workerd.js.map +1 -1
- package/dist/topic/core/index.d.ts +4 -6
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/core/index.js.map +1 -1
- package/dist/topic/redis/index.d.ts +5 -8
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/topic/redis/index.js.map +1 -1
- package/package.json +45 -22
- package/src/api/audits/__tests__/AuditService.spec.ts +18 -110
- package/src/api/audits/controllers/AdminAuditController.ts +14 -0
- package/src/api/audits/services/AuditService.ts +21 -88
- package/src/api/files/__tests__/FileService.spec.ts +207 -2
- package/src/api/files/index.ts +3 -0
- package/src/api/files/schemas/fileCreatorSummarySchema.ts +22 -0
- package/src/api/files/schemas/fileResourceSchema.ts +10 -1
- package/src/api/files/services/FileService.ts +170 -72
- package/src/api/jobs/__tests__/$job.spec.ts +24 -1
- package/src/api/jobs/index.ts +4 -3
- package/src/api/jobs/primitives/$job.ts +7 -3
- package/src/api/jobs/providers/DirectJobDispatcher.ts +17 -36
- package/src/api/jobs/providers/JobProvider.ts +53 -24
- package/src/api/jobs/schemas/jobConfigAtom.ts +1 -1
- package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +4 -1
- package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +3 -1
- package/src/api/parameters/__tests__/$parameter.spec.ts +19 -2
- package/src/api/parameters/audits/ParameterAudits.ts +17 -0
- package/src/api/parameters/controllers/AdminParameterController.ts +95 -19
- package/src/api/parameters/index.ts +3 -0
- package/src/api/parameters/schemas/activateParameterBodySchema.ts +3 -3
- package/src/api/parameters/schemas/createParameterVersionBodySchema.ts +3 -2
- package/src/api/parameters/schemas/parameterCreatorSummarySchema.ts +25 -0
- package/src/api/parameters/schemas/parameterResponseSchema.ts +5 -0
- package/src/api/parameters/schemas/rollbackParameterBodySchema.ts +4 -2
- package/src/api/parameters/services/ParameterProvider.ts +69 -6
- package/src/api/subscriptions/jobs/SubscriptionJobs.ts +1 -1
- package/src/api/users/__tests__/AdminSessionController.spec.ts +37 -0
- package/src/api/users/audits/SessionAudits.ts +33 -0
- package/src/api/users/audits/UserAudits.ts +19 -43
- package/src/api/users/controllers/AdminUserController.ts +66 -1
- package/src/api/users/entities/sessions.ts +6 -0
- package/src/api/users/entities/users.ts +2 -0
- package/src/api/users/index.ts +9 -1
- package/src/api/users/primitives/$realm.ts +3 -0
- package/src/api/users/schemas/sessionResourceSchema.ts +16 -0
- package/src/api/users/schemas/updateUserSchema.ts +1 -8
- package/src/api/users/schemas/userQuerySchema.ts +7 -0
- package/src/api/users/services/CredentialService.ts +15 -6
- package/src/api/users/services/IdentityService.ts +2 -1
- package/src/api/users/services/RegistrationService.ts +2 -1
- package/src/api/users/services/SessionCrudService.ts +19 -2
- package/src/api/users/services/SessionService.ts +39 -19
- package/src/api/users/services/UserService.ts +106 -8
- package/src/background/__tests__/BackgroundTaskProvider.spec.ts +96 -0
- package/src/background/index.ts +37 -0
- package/src/background/index.workerd.ts +28 -0
- package/src/background/providers/BackgroundTaskProvider.ts +70 -0
- package/src/background/providers/WorkerdBackgroundTaskProvider.ts +43 -0
- package/src/bucket/__tests__/$bucket.spec.ts +18 -0
- package/src/bucket/__tests__/LocalFileStorageProvider.spec.ts +5 -0
- package/src/bucket/__tests__/MemoryFileStorageProvider.spec.ts +5 -0
- package/src/bucket/__tests__/NodeS3BucketProvider.spec.ts +23 -4
- package/src/bucket/__tests__/shared.ts +30 -0
- package/src/bucket/index.ts +5 -5
- package/src/bucket/index.workerd.ts +11 -4
- package/src/bucket/primitives/$bucket.ts +27 -0
- package/src/bucket/providers/FileStorageProvider.ts +13 -0
- package/src/bucket/providers/LocalFileStorageProvider.ts +17 -1
- package/src/bucket/providers/MemoryFileStorageProvider.ts +7 -0
- package/src/bucket/providers/{CloudflareR2Provider.ts → R2FileStorageProvider.ts} +10 -1
- package/src/bucket/providers/{NodeS3BucketProvider.ts → S3FileStorageProvider.ts} +27 -5
- package/src/cli/core/__tests__/BuildDockerTask.spec.ts +25 -1
- package/src/cli/core/__tests__/init.spec.ts +0 -219
- package/src/cli/core/commands/__tests__/BuildCommand.spec.ts +43 -0
- package/src/cli/core/commands/build.ts +108 -30
- package/src/cli/core/commands/init.ts +0 -12
- package/src/cli/core/commands/pack.ts +133 -0
- package/src/cli/core/index.ts +3 -0
- package/src/cli/core/providers/ViteDevServerProvider.ts +40 -16
- package/src/cli/core/services/PackageManagerUtils.ts +0 -16
- package/src/cli/core/services/ProjectScaffolder.ts +29 -291
- package/src/cli/core/tasks/BuildCloudflareTask.ts +353 -47
- package/src/cli/core/tasks/BuildDockerTask.ts +33 -3
- package/src/cli/core/tasks/BuildTask.ts +34 -0
- package/src/cli/core/templates/apiIndexTs.ts +1 -22
- package/src/cli/core/templates/mainCss.ts +0 -1
- package/src/cli/core/templates/webAppRouterTs.ts +0 -99
- package/src/cli/core/templates/webIndexTs.ts +1 -22
- package/src/cli/platform/__tests__/SecretsCommand.spec.ts +5 -3
- package/src/cli/platform/commands/SecretsCommand.ts +8 -6
- package/src/cli/platform/commands/platform.ts +192 -46
- package/src/cli/platform/index.ts +12 -52
- package/src/cli/{platform → platform-lib}/__tests__/CloudflareAdapter.spec.ts +426 -169
- package/src/cli/{platform → platform-lib}/__tests__/NamingService.spec.ts +91 -4
- package/src/cli/{platform → platform-lib}/__tests__/VercelAdapter.spec.ts +56 -85
- package/src/cli/{platform → platform-lib}/adapters/CloudflareAdapter.ts +402 -165
- package/src/cli/{platform → platform-lib}/adapters/PlatformAdapter.ts +62 -35
- package/src/cli/{platform → platform-lib}/adapters/VercelAdapter.ts +6 -10
- package/src/cli/{platform → platform-lib}/atoms/platformOptions.ts +34 -1
- package/src/cli/platform-lib/index.ts +67 -0
- package/src/cli/platform-lib/services/NamingService.ts +136 -0
- package/src/cli/{platform → platform-lib}/services/PlatformInspector.ts +60 -13
- package/src/cli/{platform → platform-lib}/services/PlatformOrchestrator.ts +54 -43
- package/src/cli/{platform → platform-lib}/services/WranglerApi.ts +4 -2
- package/src/command/__tests__/Runner.spec.ts +20 -0
- package/src/command/helpers/EnvUtils.ts +19 -3
- package/src/command/helpers/Runner.ts +12 -2
- package/src/command/providers/CliProvider.ts +34 -1
- package/src/{containers → container}/core/__tests__/$container.spec.ts +5 -5
- package/src/{containers → container}/core/index.ts +4 -4
- package/src/{containers → container}/core/index.workerd.ts +19 -3
- package/src/{containers → container}/core/primitives/$container.ts +1 -1
- package/src/{containers → container}/core/providers/CloudflareContainerProvider.ts +17 -19
- package/src/{containers → container}/core/providers/ContainerProvider.ts +16 -2
- package/src/{containers → container}/core/providers/MockContainerProvider.ts +1 -1
- package/src/core/Alepha.ts +49 -1
- package/src/core/__tests__/$env.spec.ts +42 -0
- package/src/core/__tests__/dump.spec.ts +47 -0
- package/src/email/cloudflare/__tests__/CloudflareEmailProvider.spec.ts +42 -10
- package/src/email/cloudflare/index.ts +14 -5
- package/src/email/cloudflare/providers/CloudflareEmailProvider.ts +54 -9
- package/src/logger/__tests__/Logger.spec.ts +55 -0
- package/src/logger/index.ts +13 -0
- package/src/logger/services/Logger.ts +31 -1
- package/src/orm/__tests__/orm-showcase-tests.ts +27 -0
- package/src/orm/__tests__/orm-showcase.spec.ts +12 -0
- package/src/orm/core/interfaces/PgQuery.ts +4 -1
- package/src/orm/core/services/Repository.ts +27 -11
- package/src/react/auth/hooks/useAuth.ts +10 -5
- package/src/react/core/__tests__/useQuery.browser.spec.tsx +25 -0
- package/src/react/core/hooks/useAction.ts +14 -3
- package/src/react/core/hooks/useQuery.ts +24 -4
- package/src/react/i18n/components/Translate.tsx +47 -0
- package/src/react/i18n/index.ts +2 -0
- package/src/react/intro/components/GettingStartedAdminSlide.tsx +2 -2
- package/src/react/router/__tests__/$page.spec.tsx +3 -2
- package/src/react/router/__tests__/page-can.spec.ts +18 -13
- package/src/react/router/hooks/useQueryParams.ts +114 -14
- package/src/react/router/primitives/$page.ts +85 -4
- package/src/react/router/providers/ReactBrowserRouterProvider.ts +3 -7
- package/src/react/router/providers/ReactServerProvider.ts +4 -13
- package/src/react/ui/services/SchemaControl.ts +3 -4
- package/src/server/core/providers/ServerMultipartProvider.ts +19 -0
- package/src/server/links/providers/LinkProvider.ts +10 -0
- package/dist/containers/core/index.d.ts.map +0 -1
- package/dist/containers/core/index.js.map +0 -1
- package/dist/containers/core/index.workerd.js.map +0 -1
- package/src/cli/core/templates/componentsJsonTs.ts +0 -39
- package/src/cli/core/templates/saasAdminLayoutTsx.ts +0 -77
- package/src/cli/core/templates/saasAdminPagesTsx.ts +0 -26
- package/src/cli/core/templates/saasAuthLayoutTsx.ts +0 -22
- package/src/cli/core/templates/saasAuthPagesTsx.ts +0 -62
- package/src/cli/core/templates/saasRealmProviderTs.ts +0 -52
- package/src/cli/platform/services/NamingService.ts +0 -54
- /package/dist/orm/core/{chunk-o8xxKEmq.js → chunk-B4FMCO8f.js} +0 -0
- /package/dist/react/testing/{chunk-6Ep1yQYe.js → chunk-BpyX8vjI.js} +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/GitHubSecretStore.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/PlatformCacheProvider.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/PlatformInspector.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/PlatformOrchestrator.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/SecretFilterService.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/__tests__/detectResources.spec.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/GitHubSecretStore.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/MemorySecretStore.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/PlatformCacheProvider.ts +0 -0
- /package/src/cli/{platform → platform-lib}/providers/SecretStoreProvider.ts +0 -0
- /package/src/cli/{platform → platform-lib}/schemas/cloudflare.ts +0 -0
- /package/src/cli/{platform → platform-lib}/schemas/platform.ts +0 -0
- /package/src/cli/{platform → platform-lib}/schemas/vercel.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/CloudflareApi.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/SecretFilterService.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/VercelApi.ts +0 -0
- /package/src/cli/{platform → platform-lib}/services/VercelCli.ts +0 -0
- /package/src/{containers → container}/core/interfaces/ContainerOptions.ts +0 -0
- /package/src/{containers → container}/core/providers/NodeContainerProvider.ts +0 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { $audit } from "alepha/api/audits";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Runtime parameter (config) audit events.
|
|
5
|
+
*
|
|
6
|
+
* Holds the `parameter` audit type. Using `$audit` pulls in the audits module
|
|
7
|
+
* automatically — the parameters module does not need to import it. Register
|
|
8
|
+
* as a variant and log via `parameterAudits.parameter.log("rollback", …)`.
|
|
9
|
+
*/
|
|
10
|
+
export class ParameterAudits {
|
|
11
|
+
public readonly parameter = $audit({
|
|
12
|
+
type: "parameter",
|
|
13
|
+
description:
|
|
14
|
+
"Runtime parameter changes (create, rollback, activate, delete).",
|
|
15
|
+
actions: ["create", "rollback", "activate", "delete"],
|
|
16
|
+
});
|
|
17
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { $inject, AlephaError, t } from "alepha";
|
|
1
|
+
import { $inject, Alepha, AlephaError, t } from "alepha";
|
|
2
2
|
import { $secure } from "alepha/security";
|
|
3
3
|
import { $action, okSchema } from "alepha/server";
|
|
4
|
+
import { ParameterAudits } from "../audits/ParameterAudits.ts";
|
|
4
5
|
import { activateParameterBodySchema } from "../schemas/activateParameterBodySchema.ts";
|
|
5
6
|
import { createParameterVersionBodySchema } from "../schemas/createParameterVersionBodySchema.ts";
|
|
6
7
|
import { parameterCurrentResponseSchema } from "../schemas/parameterCurrentResponseSchema.ts";
|
|
@@ -29,6 +30,7 @@ export class AdminParameterController {
|
|
|
29
30
|
protected readonly url = "/parameters";
|
|
30
31
|
protected readonly group = "admin:parameters";
|
|
31
32
|
protected readonly provider = $inject(ParameterProvider);
|
|
33
|
+
protected readonly alepha = $inject(Alepha);
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Get tree structure of all parameter names.
|
|
@@ -162,16 +164,26 @@ export class AdminParameterController {
|
|
|
162
164
|
body: createParameterVersionBodySchema,
|
|
163
165
|
response: parameterResponseSchema,
|
|
164
166
|
},
|
|
165
|
-
handler: async ({ params, body }) => {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
167
|
+
handler: async ({ params, body, user }) => {
|
|
168
|
+
const result = await this.provider.save(
|
|
169
|
+
params.name,
|
|
170
|
+
body.content,
|
|
171
|
+
body.schemaHash,
|
|
172
|
+
{
|
|
173
|
+
activationDate: body.activationDate
|
|
174
|
+
? new Date(body.activationDate)
|
|
175
|
+
: undefined,
|
|
176
|
+
changeDescription: body.changeDescription,
|
|
177
|
+
tags: body.tags,
|
|
178
|
+
creatorId: user?.id,
|
|
179
|
+
creatorName: this.creatorNameOf(user),
|
|
180
|
+
},
|
|
181
|
+
);
|
|
182
|
+
await this.audit("create", params.name, {
|
|
183
|
+
version: result.version,
|
|
184
|
+
scheduled: result.status !== "current",
|
|
174
185
|
});
|
|
186
|
+
return result;
|
|
175
187
|
},
|
|
176
188
|
});
|
|
177
189
|
|
|
@@ -190,12 +202,21 @@ export class AdminParameterController {
|
|
|
190
202
|
body: rollbackParameterBodySchema,
|
|
191
203
|
response: parameterResponseSchema,
|
|
192
204
|
},
|
|
193
|
-
handler: async ({ params, body }) => {
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
205
|
+
handler: async ({ params, body, user }) => {
|
|
206
|
+
const result = await this.provider.rollback(
|
|
207
|
+
params.name,
|
|
208
|
+
body.targetVersion,
|
|
209
|
+
{
|
|
210
|
+
changeDescription: body.changeDescription,
|
|
211
|
+
creatorId: user?.id,
|
|
212
|
+
creatorName: this.creatorNameOf(user),
|
|
213
|
+
},
|
|
214
|
+
);
|
|
215
|
+
await this.audit("rollback", params.name, {
|
|
216
|
+
version: result.version,
|
|
217
|
+
targetVersion: body.targetVersion,
|
|
198
218
|
});
|
|
219
|
+
return result;
|
|
199
220
|
},
|
|
200
221
|
});
|
|
201
222
|
|
|
@@ -214,7 +235,7 @@ export class AdminParameterController {
|
|
|
214
235
|
body: activateParameterBodySchema,
|
|
215
236
|
response: parameterResponseSchema,
|
|
216
237
|
},
|
|
217
|
-
handler: async ({ params, body }) => {
|
|
238
|
+
handler: async ({ params, body, user }) => {
|
|
218
239
|
const allVersions = await this.provider.getHistory(params.name);
|
|
219
240
|
const withStatuses = this.provider.calculateStatuses(allVersions);
|
|
220
241
|
const target = withStatuses.find((v) => v.version === body.version);
|
|
@@ -236,16 +257,21 @@ export class AdminParameterController {
|
|
|
236
257
|
}
|
|
237
258
|
|
|
238
259
|
// Create new version with same content but immediate activation
|
|
239
|
-
|
|
260
|
+
const result = await this.provider.save(
|
|
240
261
|
params.name,
|
|
241
262
|
target.content,
|
|
242
263
|
target.schemaHash,
|
|
243
264
|
{
|
|
244
265
|
changeDescription: `Early activation of version ${body.version}`,
|
|
245
|
-
creatorId:
|
|
246
|
-
creatorName:
|
|
266
|
+
creatorId: user?.id,
|
|
267
|
+
creatorName: this.creatorNameOf(user),
|
|
247
268
|
},
|
|
248
269
|
);
|
|
270
|
+
await this.audit("activate", params.name, {
|
|
271
|
+
version: result.version,
|
|
272
|
+
activatedFrom: body.version,
|
|
273
|
+
});
|
|
274
|
+
return result;
|
|
249
275
|
},
|
|
250
276
|
});
|
|
251
277
|
|
|
@@ -264,6 +290,7 @@ export class AdminParameterController {
|
|
|
264
290
|
},
|
|
265
291
|
handler: async ({ params }) => {
|
|
266
292
|
await this.provider.delete(params.name);
|
|
293
|
+
await this.audit("delete", params.name);
|
|
267
294
|
return { ok: true };
|
|
268
295
|
},
|
|
269
296
|
});
|
|
@@ -290,7 +317,56 @@ export class AdminParameterController {
|
|
|
290
317
|
},
|
|
291
318
|
handler: async ({ body }) => {
|
|
292
319
|
const deleted = await this.provider.deleteMany(body.names);
|
|
320
|
+
for (const name of deleted) {
|
|
321
|
+
await this.audit("delete", name);
|
|
322
|
+
}
|
|
293
323
|
return { deleted };
|
|
294
324
|
},
|
|
295
325
|
});
|
|
326
|
+
|
|
327
|
+
/**
|
|
328
|
+
* Derive a human-readable creator name from the authenticated session token.
|
|
329
|
+
*
|
|
330
|
+
* The name is snapshotted onto the version at write time rather than joined
|
|
331
|
+
* from the users table on read: this keeps the parameters module free of any
|
|
332
|
+
* dependency on the users module (no import, no circular-import risk). The
|
|
333
|
+
* trade-off is that the stored name does not follow later user renames.
|
|
334
|
+
*
|
|
335
|
+
* Precedence: `username` → `email`. The token's `name` is intentionally
|
|
336
|
+
* skipped: the security layer fills it with a placeholder ("Anonymous User")
|
|
337
|
+
* when the issuer supplies no name, which would otherwise be snapshotted.
|
|
338
|
+
*/
|
|
339
|
+
protected creatorNameOf(user?: {
|
|
340
|
+
username?: string;
|
|
341
|
+
email?: string;
|
|
342
|
+
}): string | undefined {
|
|
343
|
+
return user?.username ?? user?.email;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Record a parameter mutation via the `ParameterAudits` holder — best-effort.
|
|
348
|
+
*
|
|
349
|
+
* `ParameterAudits` is resolved lazily from the container; when it is not
|
|
350
|
+
* registered, auditing is silently skipped. Actor (userId / email / realm),
|
|
351
|
+
* IP, and request id are auto-filled by `AuditService` from the request
|
|
352
|
+
* context. Failures never break the underlying operation.
|
|
353
|
+
*/
|
|
354
|
+
protected async audit(
|
|
355
|
+
action: "create" | "rollback" | "activate" | "delete",
|
|
356
|
+
name: string,
|
|
357
|
+
metadata?: Record<string, unknown>,
|
|
358
|
+
): Promise<void> {
|
|
359
|
+
if (!this.alepha.has(ParameterAudits)) {
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
try {
|
|
363
|
+
await this.alepha.inject(ParameterAudits).parameter.log(action, {
|
|
364
|
+
resourceType: "parameter",
|
|
365
|
+
resourceId: name,
|
|
366
|
+
metadata,
|
|
367
|
+
});
|
|
368
|
+
} catch {
|
|
369
|
+
// Auditing is best-effort; never fail the operation because of it.
|
|
370
|
+
}
|
|
371
|
+
}
|
|
296
372
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { $module } from "alepha";
|
|
2
|
+
import { ParameterAudits } from "./audits/ParameterAudits.ts";
|
|
2
3
|
import { AdminParameterController } from "./controllers/AdminParameterController.ts";
|
|
3
4
|
import { $parameter } from "./primitives/$parameter.ts";
|
|
4
5
|
import { ParameterProvider } from "./services/ParameterProvider.ts";
|
|
@@ -6,6 +7,7 @@ import { ParameterProvider } from "./services/ParameterProvider.ts";
|
|
|
6
7
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
7
8
|
|
|
8
9
|
// Controller exports
|
|
10
|
+
export * from "./audits/ParameterAudits.ts";
|
|
9
11
|
export * from "./controllers/AdminParameterController.ts";
|
|
10
12
|
// Entity exports
|
|
11
13
|
export * from "./entities/parameters.ts";
|
|
@@ -45,4 +47,5 @@ export const AlephaApiParameters = $module({
|
|
|
45
47
|
name: "alepha.api.parameters",
|
|
46
48
|
primitives: [$parameter],
|
|
47
49
|
services: [ParameterProvider, AdminParameterController],
|
|
50
|
+
variants: [ParameterAudits],
|
|
48
51
|
});
|
|
@@ -3,12 +3,12 @@ import { parameters } from "../entities/parameters.ts";
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Activate parameter body schema.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* Creator fields are omitted; the controller captures the authenticated user
|
|
8
|
+
* server-side.
|
|
7
9
|
*/
|
|
8
10
|
export const activateParameterBodySchema = t.pick(parameters.schema, [
|
|
9
11
|
"version",
|
|
10
|
-
"creatorId",
|
|
11
|
-
"creatorName",
|
|
12
12
|
]);
|
|
13
13
|
|
|
14
14
|
export type ActivateParameterBody = Static<typeof activateParameterBodySchema>;
|
|
@@ -4,6 +4,9 @@ import { parameters } from "../entities/parameters.ts";
|
|
|
4
4
|
/**
|
|
5
5
|
* Create parameter version body schema.
|
|
6
6
|
* Uses t.pick to derive from entity, with required fields made non-optional.
|
|
7
|
+
*
|
|
8
|
+
* Creator fields are intentionally omitted: the controller captures the
|
|
9
|
+
* authenticated user server-side, so they cannot be spoofed by the client.
|
|
7
10
|
*/
|
|
8
11
|
export const createParameterVersionBodySchema = t.extend(
|
|
9
12
|
t.pick(parameters.schema, [
|
|
@@ -11,8 +14,6 @@ export const createParameterVersionBodySchema = t.extend(
|
|
|
11
14
|
"schemaHash",
|
|
12
15
|
"changeDescription",
|
|
13
16
|
"tags",
|
|
14
|
-
"creatorId",
|
|
15
|
-
"creatorName",
|
|
16
17
|
]),
|
|
17
18
|
{
|
|
18
19
|
activationDate: t.optional(
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Static, t } from "alepha";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Slim view of a parameter version's creator, embedded by the admin history
|
|
5
|
+
* endpoint via a best-effort left join (`parameters.creatorId` → `users.id`)
|
|
6
|
+
* so the UI can render a human-readable identifier (and link) instead of a
|
|
7
|
+
* bare UUID.
|
|
8
|
+
*
|
|
9
|
+
* Optional end-to-end: the join only runs when the `users` entity is
|
|
10
|
+
* registered in the running app (see `ParameterProvider.resolveCreatorJoin`),
|
|
11
|
+
* and a version whose creator was deleted — or who lives in a non-default
|
|
12
|
+
* realm — comes back with `creator` undefined. Callers fall back to the raw
|
|
13
|
+
* `creatorId`.
|
|
14
|
+
*/
|
|
15
|
+
export const parameterCreatorSummarySchema = t.object({
|
|
16
|
+
id: t.uuid(),
|
|
17
|
+
email: t.optional(t.string({ format: "email" })),
|
|
18
|
+
username: t.optional(t.shortText({ minLength: 3, maxLength: 30 })),
|
|
19
|
+
firstName: t.optional(t.string()),
|
|
20
|
+
lastName: t.optional(t.string()),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export type ParameterCreatorSummary = Static<
|
|
24
|
+
typeof parameterCreatorSummarySchema
|
|
25
|
+
>;
|
|
@@ -1,14 +1,19 @@
|
|
|
1
1
|
import { type Static, t } from "alepha";
|
|
2
2
|
import { parameters } from "../entities/parameters.ts";
|
|
3
|
+
import { parameterCreatorSummarySchema } from "./parameterCreatorSummarySchema.ts";
|
|
3
4
|
import { parameterStatusSchema } from "./parameterStatusSchema.ts";
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Parameter response schema for API responses.
|
|
7
8
|
* Extends the entity schema with a calculated status field.
|
|
8
9
|
* Status is derived from activationDate at query time, not stored.
|
|
10
|
+
*
|
|
11
|
+
* `creator` is embedded on read via a best-effort left join on `creatorId`
|
|
12
|
+
* (see `parameterCreatorSummarySchema`); it is not a stored column.
|
|
9
13
|
*/
|
|
10
14
|
export const parameterResponseSchema = t.extend(parameters.schema, {
|
|
11
15
|
status: parameterStatusSchema,
|
|
16
|
+
creator: t.optional(parameterCreatorSummarySchema),
|
|
12
17
|
});
|
|
13
18
|
|
|
14
19
|
export type ParameterResponse = Static<typeof parameterResponseSchema>;
|
|
@@ -3,10 +3,12 @@ import { parameters } from "../entities/parameters.ts";
|
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Rollback parameter body schema.
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
|
+
* Creator fields are omitted; the controller captures the authenticated user
|
|
8
|
+
* server-side.
|
|
7
9
|
*/
|
|
8
10
|
export const rollbackParameterBodySchema = t.extend(
|
|
9
|
-
t.pick(parameters.schema, ["changeDescription"
|
|
11
|
+
t.pick(parameters.schema, ["changeDescription"]),
|
|
10
12
|
{
|
|
11
13
|
targetVersion: t.integer({
|
|
12
14
|
description: "Version number to rollback to",
|
|
@@ -12,7 +12,7 @@ import { CryptoProvider } from "alepha/crypto";
|
|
|
12
12
|
import { DateTimeProvider } from "alepha/datetime";
|
|
13
13
|
import { LockProvider } from "alepha/lock";
|
|
14
14
|
import { $logger } from "alepha/logger";
|
|
15
|
-
import { $repository } from "alepha/orm";
|
|
15
|
+
import { $repository, RepositoryProvider } from "alepha/orm";
|
|
16
16
|
import { $topic } from "alepha/topic";
|
|
17
17
|
import { type Parameter, parameters } from "../entities/parameters.ts";
|
|
18
18
|
import type { ParameterPrimitive } from "../primitives/$parameter.ts";
|
|
@@ -50,6 +50,7 @@ export class ParameterProvider {
|
|
|
50
50
|
protected readonly crypto = $inject(CryptoProvider);
|
|
51
51
|
protected readonly lockProvider = $inject(LockProvider);
|
|
52
52
|
protected readonly schemaValidator = $inject(SchemaValidator);
|
|
53
|
+
protected readonly repositoryProvider = $inject(RepositoryProvider);
|
|
53
54
|
protected readonly repo = $repository(parameters);
|
|
54
55
|
|
|
55
56
|
/**
|
|
@@ -326,10 +327,10 @@ export class ParameterProvider {
|
|
|
326
327
|
* - Other future versions are "future"
|
|
327
328
|
* - Other past versions are "expired"
|
|
328
329
|
*/
|
|
329
|
-
public calculateStatuses(
|
|
330
|
-
versions:
|
|
330
|
+
public calculateStatuses<T extends Parameter>(
|
|
331
|
+
versions: T[],
|
|
331
332
|
now?: Date,
|
|
332
|
-
):
|
|
333
|
+
): Array<T & { status: ParameterStatus }> {
|
|
333
334
|
const effectiveNow = now ?? this.dateTimeProvider.now().toDate();
|
|
334
335
|
|
|
335
336
|
// Sort by activationDate ascending, then version ascending for ties
|
|
@@ -458,17 +459,49 @@ export class ParameterProvider {
|
|
|
458
459
|
}
|
|
459
460
|
|
|
460
461
|
/**
|
|
461
|
-
*
|
|
462
|
+
* Best-effort left join embedding the creating user on each version, so the
|
|
463
|
+
* admin UI can render a human-readable identifier (live, not snapshotted)
|
|
464
|
+
* instead of the bare `creatorId`. Joins `parameters.creatorId` → `users.id`.
|
|
465
|
+
*
|
|
466
|
+
* The `users` entity is resolved from the repository registry at runtime
|
|
467
|
+
* rather than imported: that keeps the parameters module free of any
|
|
468
|
+
* dependency on the users module (no import, no circular-import risk). When
|
|
469
|
+
* the users module is not registered the join is skipped and `creator` comes
|
|
470
|
+
* back undefined.
|
|
471
|
+
*/
|
|
472
|
+
protected resolveCreatorJoin() {
|
|
473
|
+
const usersEntity = this.repositoryProvider
|
|
474
|
+
.getRepositories()
|
|
475
|
+
.find((repo) => repo.entity.name === "users")?.entity;
|
|
476
|
+
if (!usersEntity) {
|
|
477
|
+
return undefined;
|
|
478
|
+
}
|
|
479
|
+
return {
|
|
480
|
+
creator: {
|
|
481
|
+
join: usersEntity,
|
|
482
|
+
on: ["creatorId", usersEntity.cols.id] as [
|
|
483
|
+
"creatorId",
|
|
484
|
+
{ name: string },
|
|
485
|
+
],
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Get all versions of a parameter, each with the creating user embedded
|
|
492
|
+
* (best-effort, see {@link resolveCreatorJoin}).
|
|
462
493
|
*/
|
|
463
494
|
public async getHistory(
|
|
464
495
|
name: string,
|
|
465
496
|
options?: { limit?: number; offset?: number },
|
|
466
497
|
): Promise<Parameter[]> {
|
|
498
|
+
const withCreator = this.resolveCreatorJoin();
|
|
467
499
|
return this.repo.findMany({
|
|
468
500
|
where: { name },
|
|
469
501
|
orderBy: { column: "version", direction: "desc" },
|
|
470
502
|
limit: options?.limit,
|
|
471
503
|
offset: options?.offset,
|
|
504
|
+
...(withCreator ? { with: withCreator } : {}),
|
|
472
505
|
});
|
|
473
506
|
}
|
|
474
507
|
|
|
@@ -563,6 +596,12 @@ export class ParameterProvider {
|
|
|
563
596
|
|
|
564
597
|
/**
|
|
565
598
|
* Get parameter info including current value with default fallback.
|
|
599
|
+
*
|
|
600
|
+
* When no version exists in the DB yet but a primitive is registered, this
|
|
601
|
+
* lazily materializes v1 from the primitive's `default`. After this call,
|
|
602
|
+
* the parameter has a concrete current row admins can edit / roll back /
|
|
603
|
+
* compare against, instead of running on phantom defaults-from-code state.
|
|
604
|
+
* Idempotent: subsequent calls return the same row without re-creating.
|
|
566
605
|
*/
|
|
567
606
|
public async getCurrentWithDefault(name: string): Promise<{
|
|
568
607
|
current: ParameterWithStatus | null;
|
|
@@ -571,10 +610,34 @@ export class ParameterProvider {
|
|
|
571
610
|
currentValue: unknown | null;
|
|
572
611
|
schema: TObject | null;
|
|
573
612
|
}> {
|
|
574
|
-
|
|
613
|
+
let { current, next } = await this.loadCurrentAndNext(name);
|
|
575
614
|
|
|
576
615
|
// Get default and current from registered primitive
|
|
577
616
|
const param = this.primitives.get(name);
|
|
617
|
+
|
|
618
|
+
// No version in DB yet but the primitive is registered: seed v1 from
|
|
619
|
+
// the compiled defaults. Always-on parameters are then a tangible row
|
|
620
|
+
// the admin UI can edit (and that history can grow from). Unregistered
|
|
621
|
+
// names (orphans from a removed `$parameter`) are not seeded.
|
|
622
|
+
if (!current && param) {
|
|
623
|
+
try {
|
|
624
|
+
current = await this.save(
|
|
625
|
+
name,
|
|
626
|
+
param.options.default as Static<TObject>,
|
|
627
|
+
this.schemaHashes.get(name) ?? "",
|
|
628
|
+
{ changeDescription: "Auto-seeded from compiled defaults" },
|
|
629
|
+
);
|
|
630
|
+
} catch (err) {
|
|
631
|
+
// A concurrent caller may have raced us to insert v1; fall back to
|
|
632
|
+
// re-reading instead of bubbling up a unique-constraint error.
|
|
633
|
+
this.log.warn("Auto-seed of parameter failed, retrying read", {
|
|
634
|
+
name,
|
|
635
|
+
error: (err as Error).message,
|
|
636
|
+
});
|
|
637
|
+
({ current, next } = await this.loadCurrentAndNext(name));
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
|
|
578
641
|
const defaultValue = param?.options.default ?? null;
|
|
579
642
|
const currentValue = this.getCachedCurrentContent(name) ?? null;
|
|
580
643
|
const schema = param?.schema ?? null;
|
|
@@ -301,7 +301,7 @@ export class SubscriptionJobs {
|
|
|
301
301
|
* Runs daily at 2 AM.
|
|
302
302
|
*/
|
|
303
303
|
public readonly gracePeriodSweep = $job({
|
|
304
|
-
cron: "0
|
|
304
|
+
cron: "0 3 * * *",
|
|
305
305
|
lock: true,
|
|
306
306
|
handler: async ({ now }) => {
|
|
307
307
|
const settings = await this.config.getSettings();
|
|
@@ -75,6 +75,43 @@ describe("alepha/api/users - AdminSessionController", () => {
|
|
|
75
75
|
expect(result.userAgent?.browser).toBe("Chrome");
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
+
it("should embed the slim user summary on findSessions + getSession", async ({
|
|
79
|
+
expect,
|
|
80
|
+
}) => {
|
|
81
|
+
const { sessionService, userService, controller, dateTimeProvider } =
|
|
82
|
+
await setup();
|
|
83
|
+
|
|
84
|
+
const user = await userService.users().create({
|
|
85
|
+
username: "withuser",
|
|
86
|
+
email: "withuser@example.com",
|
|
87
|
+
firstName: "With",
|
|
88
|
+
lastName: "User",
|
|
89
|
+
roles: ["user"],
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const session = await sessionService.sessions().create({
|
|
93
|
+
userId: user.id,
|
|
94
|
+
refreshToken: crypto.randomUUID(),
|
|
95
|
+
expiresAt: dateTimeProvider.now().add(7, "days").toISOString(),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const listed = await controller.findSessions(
|
|
99
|
+
{ query: { userId: user.id } },
|
|
100
|
+
{ user: adminUser },
|
|
101
|
+
);
|
|
102
|
+
const found = listed.content.find((s) => s.id === session.id);
|
|
103
|
+
expect(found?.user?.id).toBe(user.id);
|
|
104
|
+
expect(found?.user?.email).toBe("withuser@example.com");
|
|
105
|
+
expect(found?.user?.username).toBe("withuser");
|
|
106
|
+
expect(found?.user?.firstName).toBe("With");
|
|
107
|
+
|
|
108
|
+
const fetched = await controller.getSession(
|
|
109
|
+
{ params: { id: session.id } },
|
|
110
|
+
{ user: adminUser },
|
|
111
|
+
);
|
|
112
|
+
expect(fetched.user?.email).toBe("withuser@example.com");
|
|
113
|
+
});
|
|
114
|
+
|
|
78
115
|
it("should throw error for non-existent session", async ({ expect }) => {
|
|
79
116
|
const { controller } = await setup();
|
|
80
117
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { $audit } from "alepha/api/audits";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Authentication & session-security audit events.
|
|
5
|
+
*
|
|
6
|
+
* Holds two audit types:
|
|
7
|
+
* - `auth` — login / logout / token refresh / MFA.
|
|
8
|
+
* - `security` — rate limiting, session invalidation, and related guards.
|
|
9
|
+
*
|
|
10
|
+
* Failed events are logged with `success: false`; severity (`warning`) is
|
|
11
|
+
* derived centrally in `AuditService.create`. Register as a module variant
|
|
12
|
+
* and log via the exposed primitives:
|
|
13
|
+
* `sessionAudits(realm)?.auth.log("login", { success: false, … })`.
|
|
14
|
+
*/
|
|
15
|
+
export class SessionAudits {
|
|
16
|
+
public readonly auth = $audit({
|
|
17
|
+
type: "auth",
|
|
18
|
+
description: "Authentication events (login, logout, token refresh, MFA).",
|
|
19
|
+
actions: ["login", "logout", "token_refresh", "mfa_setup", "mfa_verify"],
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
public readonly security = $audit({
|
|
23
|
+
type: "security",
|
|
24
|
+
description:
|
|
25
|
+
"Security events (rate limiting, session invalidation, blocked access).",
|
|
26
|
+
actions: [
|
|
27
|
+
"rate_limited",
|
|
28
|
+
"sessions_invalidated",
|
|
29
|
+
"permission_denied",
|
|
30
|
+
"blocked",
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
}
|
|
@@ -1,49 +1,25 @@
|
|
|
1
|
-
import { $
|
|
2
|
-
import { AuditService, type CreateAudit } from "alepha/api/audits";
|
|
3
|
-
|
|
4
|
-
type AuditContext = Omit<CreateAudit, "type" | "action">;
|
|
1
|
+
import { $audit } from "alepha/api/audits";
|
|
5
2
|
|
|
6
3
|
/**
|
|
7
|
-
* User-
|
|
8
|
-
*
|
|
9
|
-
* This service wraps the core AuditService to provide user-related audit logging.
|
|
4
|
+
* User-management audit events.
|
|
10
5
|
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
6
|
+
* Holds the `user` audit type. Mirrors the `$notification`/`$job` holder
|
|
7
|
+
* pattern (see {@link UserNotifications}) — register as a module variant and
|
|
8
|
+
* log via the exposed primitive: `userAudits(realm)?.user.log("create", …)`.
|
|
13
9
|
*/
|
|
14
10
|
export class UserAudits {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
) {
|
|
30
|
-
return this.auditService.recordUser(action, context);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Record an authentication-related audit event.
|
|
35
|
-
*/
|
|
36
|
-
public recordAuth(
|
|
37
|
-
action: "login" | "logout" | "login_failed" | "token_refresh",
|
|
38
|
-
context: AuditContext,
|
|
39
|
-
) {
|
|
40
|
-
return this.auditService.recordAuth(action, context);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* Record a generic audit event.
|
|
45
|
-
*/
|
|
46
|
-
public record(category: string, action: string, context: AuditContext) {
|
|
47
|
-
return this.auditService.record(category, action, context);
|
|
48
|
-
}
|
|
11
|
+
public readonly user = $audit({
|
|
12
|
+
type: "user",
|
|
13
|
+
description:
|
|
14
|
+
"User management events (create, update, delete, role/password changes).",
|
|
15
|
+
actions: [
|
|
16
|
+
"create",
|
|
17
|
+
"update",
|
|
18
|
+
"delete",
|
|
19
|
+
"role_change",
|
|
20
|
+
"password_change",
|
|
21
|
+
"enable",
|
|
22
|
+
"disable",
|
|
23
|
+
],
|
|
24
|
+
});
|
|
49
25
|
}
|