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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.js","names":[],"sources":["../../src/crypto/providers/BrowserCryptoProvider.ts","../../src/crypto/index.browser.ts"],"sourcesContent":["import { AlephaError } from \"alepha\";\n\nexport class BrowserCryptoProvider {\n protected static readonly AES_ALGORITHM = \"AES-GCM\";\n protected static readonly AES_IV_LENGTH = 12;\n public hashPassword(): never {\n throw new AlephaError(\"hashPassword is not supported in the browser\");\n }\n\n public verifyPassword(): never {\n throw new AlephaError(\"verifyPassword is not supported in the browser\");\n }\n\n public async hash(data: string, algorithm = \"SHA-256\"): Promise<string> {\n const encoded = new TextEncoder().encode(data);\n const digest = await crypto.subtle.digest(algorithm, encoded);\n return this.toHex(digest);\n }\n\n public async hmac(\n data: string,\n secret: string,\n algorithm = \"SHA-256\",\n ): Promise<string> {\n const key = await crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(secret),\n { name: \"HMAC\", hash: algorithm },\n false,\n [\"sign\"],\n );\n const signature = await crypto.subtle.sign(\n \"HMAC\",\n key,\n new TextEncoder().encode(data),\n );\n return this.toHex(signature);\n }\n\n public async verifyHmac(\n data: string,\n signature: string,\n secret: string,\n algorithm = \"SHA-256\",\n ): Promise<boolean> {\n const expected = await this.hmac(data, secret, algorithm);\n return this.equals(expected, signature);\n }\n\n public async encrypt(plaintext: string, key: string): Promise<string> {\n const iv = crypto.getRandomValues(\n new Uint8Array(BrowserCryptoProvider.AES_IV_LENGTH),\n );\n const cryptoKey = await this.deriveAesKey(key);\n const encoded = new TextEncoder().encode(plaintext);\n const encrypted = await crypto.subtle.encrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: iv.buffer as ArrayBuffer,\n },\n cryptoKey,\n encoded,\n );\n // Web Crypto appends the auth tag to the ciphertext\n const encryptedBytes = new Uint8Array(encrypted);\n const ciphertext = encryptedBytes.slice(0, -16);\n const tag = encryptedBytes.slice(-16);\n return `${this.toHex(iv)}:${this.toHex(tag)}:${this.toHex(ciphertext)}`;\n }\n\n public async decrypt(ciphertext: string, key: string): Promise<string> {\n const parts = ciphertext.split(\":\");\n if (parts.length !== 3) {\n throw new AlephaError(\"Invalid ciphertext format\");\n }\n\n const [ivHex, tagHex, encryptedHex] = parts;\n const iv = this.fromHex(ivHex!);\n const tag = this.fromHex(tagHex!);\n const encrypted = this.fromHex(encryptedHex!);\n // Web Crypto expects tag appended to ciphertext\n const combined = new Uint8Array(encrypted.length + tag.length);\n combined.set(encrypted);\n combined.set(tag, encrypted.length);\n const cryptoKey = await this.deriveAesKey(key);\n const decrypted = await crypto.subtle.decrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: iv.buffer as ArrayBuffer,\n },\n cryptoKey,\n combined.buffer as ArrayBuffer,\n );\n return new TextDecoder().decode(decrypted);\n }\n\n public equals(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false;\n }\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n }\n\n public randomUUID(): string {\n return crypto.randomUUID();\n }\n\n public randomText(length: number): string {\n const bytes = crypto.getRandomValues(new Uint8Array(length));\n return this.toBase64Url(bytes.buffer as ArrayBuffer).slice(0, length);\n }\n\n public randomCode(length: number): string {\n const max = 10 ** length;\n const array = new Uint32Array(1);\n // Rejection sampling to avoid modulo bias\n const limit = Math.floor(0x100000000 / max) * max;\n let value: number;\n do {\n crypto.getRandomValues(array);\n value = array[0]!;\n } while (value >= limit);\n const code = value % max;\n return String(code).padStart(length, \"0\");\n }\n\n protected toHex(buffer: ArrayBuffer | Uint8Array): string {\n const bytes =\n buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n protected fromHex(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n }\n\n protected toBase64Url(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n }\n\n protected async deriveAesKey(key: string): Promise<CryptoKey> {\n const encoded = new TextEncoder().encode(key);\n const hash = await crypto.subtle.digest(\"SHA-256\", encoded);\n return crypto.subtle.importKey(\n \"raw\",\n hash,\n { name: BrowserCryptoProvider.AES_ALGORITHM },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n\n /**\n * Derive an AES-GCM key from a low-entropy user passphrase using\n * PBKDF2-SHA-256. Use this in place of {@link deriveAesKey} whenever the\n * key material is a human-chosen string — a single SHA-256 over a\n * passphrase is brute-forceable by anyone with the ciphertext.\n *\n * OWASP 2023 recommends 600k iterations of PBKDF2-SHA-256 for password\n * storage; we use the same budget for client-side at-rest content keys.\n * Each protected blob carries its own random salt so the same passphrase\n * derives a different key per blob.\n */\n public async deriveKeyFromPassphrase(\n passphrase: string,\n saltHex: string,\n iterations = 600_000,\n ): Promise<CryptoKey> {\n const baseKey = await crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(passphrase),\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"],\n );\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: this.fromHex(saltHex).buffer as ArrayBuffer,\n iterations,\n hash: \"SHA-256\",\n },\n baseKey,\n { name: BrowserCryptoProvider.AES_ALGORITHM, length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n\n /**\n * Encrypt `plaintext` with a pre-derived passphrase key, returning a\n * self-contained envelope (versioned for forward compatibility):\n *\n * { v: 1, salt, iv, ciphertext, kdf }\n *\n * `salt` + `kdf` are echoed back so {@link decryptWithPassphrase} can\n * reproduce the exact derivation. Each call generates a fresh IV — pass\n * a stable salt across saves of the same protected blob so the\n * passphrase only has to be derived once per session.\n */\n public async encryptWithPassphrase(\n plaintext: string,\n key: CryptoKey,\n saltHex: string,\n iterations = 600_000,\n ): Promise<string> {\n const iv = crypto.getRandomValues(\n new Uint8Array(BrowserCryptoProvider.AES_IV_LENGTH),\n );\n const encrypted = await crypto.subtle.encrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: iv.buffer as ArrayBuffer,\n },\n key,\n new TextEncoder().encode(plaintext),\n );\n return JSON.stringify({\n v: 1,\n salt: saltHex,\n iv: this.toHex(iv),\n ciphertext: this.toHex(new Uint8Array(encrypted)),\n kdf: { name: \"PBKDF2\", iterations, hash: \"SHA-256\" },\n });\n }\n\n /**\n * Reverse of {@link encryptWithPassphrase}. Throws when the passphrase\n * is wrong or the envelope is corrupt — both surface as the same\n * `OperationError` from Web Crypto, which the UI presents as a generic\n * \"wrong passphrase\" without revealing which.\n */\n public async decryptWithPassphrase(\n envelope: string,\n passphrase: string,\n ): Promise<string> {\n let parsed: {\n v?: number;\n salt?: string;\n iv?: string;\n ciphertext?: string;\n kdf?: { iterations?: number };\n };\n try {\n parsed = JSON.parse(envelope);\n } catch {\n throw new AlephaError(\"Invalid protected folio envelope\");\n }\n if (!parsed.salt || !parsed.iv || !parsed.ciphertext) {\n throw new AlephaError(\"Invalid protected folio envelope\");\n }\n const key = await this.deriveKeyFromPassphrase(\n passphrase,\n parsed.salt,\n parsed.kdf?.iterations ?? 600_000,\n );\n const decrypted = await crypto.subtle.decrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: this.fromHex(parsed.iv).buffer as ArrayBuffer,\n },\n key,\n this.fromHex(parsed.ciphertext).buffer as ArrayBuffer,\n );\n return new TextDecoder().decode(decrypted);\n }\n}\n","import { $module } from \"alepha\";\nimport { BrowserCryptoProvider } from \"./providers/BrowserCryptoProvider.ts\";\n\nexport { BrowserCryptoProvider as CryptoProvider } from \"./providers/BrowserCryptoProvider.ts\";\n\n/**\n * Cryptographic utilities: hashing, HMAC, AES-256-GCM encryption, password hashing, and secure random generation.\n *\n * @module alepha.crypto\n */\nexport const AlephaCrypto = $module({\n name: \"alepha.crypto\",\n services: [BrowserCryptoProvider],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.browser.js","names":[],"sources":["../../src/crypto/providers/BrowserCryptoProvider.ts","../../src/crypto/index.browser.ts"],"sourcesContent":["import { AlephaError } from \"alepha\";\n\nexport class BrowserCryptoProvider {\n protected static readonly AES_ALGORITHM = \"AES-GCM\";\n protected static readonly AES_IV_LENGTH = 12;\n public hashPassword(): never {\n throw new AlephaError(\"hashPassword is not supported in the browser\");\n }\n\n public verifyPassword(): never {\n throw new AlephaError(\"verifyPassword is not supported in the browser\");\n }\n\n public async hash(data: string, algorithm = \"SHA-256\"): Promise<string> {\n const encoded = new TextEncoder().encode(data);\n const digest = await crypto.subtle.digest(algorithm, encoded);\n return this.toHex(digest);\n }\n\n public async hmac(\n data: string,\n secret: string,\n algorithm = \"SHA-256\",\n ): Promise<string> {\n const key = await crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(secret),\n { name: \"HMAC\", hash: algorithm },\n false,\n [\"sign\"],\n );\n const signature = await crypto.subtle.sign(\n \"HMAC\",\n key,\n new TextEncoder().encode(data),\n );\n return this.toHex(signature);\n }\n\n public async verifyHmac(\n data: string,\n signature: string,\n secret: string,\n algorithm = \"SHA-256\",\n ): Promise<boolean> {\n const expected = await this.hmac(data, secret, algorithm);\n return this.equals(expected, signature);\n }\n\n public async encrypt(plaintext: string, key: string): Promise<string> {\n const iv = crypto.getRandomValues(\n new Uint8Array(BrowserCryptoProvider.AES_IV_LENGTH),\n );\n const cryptoKey = await this.deriveAesKey(key);\n const encoded = new TextEncoder().encode(plaintext);\n const encrypted = await crypto.subtle.encrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: iv.buffer as ArrayBuffer,\n },\n cryptoKey,\n encoded,\n );\n // Web Crypto appends the auth tag to the ciphertext\n const encryptedBytes = new Uint8Array(encrypted);\n const ciphertext = encryptedBytes.slice(0, -16);\n const tag = encryptedBytes.slice(-16);\n return `${this.toHex(iv)}:${this.toHex(tag)}:${this.toHex(ciphertext)}`;\n }\n\n public async decrypt(ciphertext: string, key: string): Promise<string> {\n const parts = ciphertext.split(\":\");\n if (parts.length !== 3) {\n throw new AlephaError(\"Invalid ciphertext format\");\n }\n\n const [ivHex, tagHex, encryptedHex] = parts;\n const iv = this.fromHex(ivHex!);\n const tag = this.fromHex(tagHex!);\n const encrypted = this.fromHex(encryptedHex!);\n // Web Crypto expects tag appended to ciphertext\n const combined = new Uint8Array(encrypted.length + tag.length);\n combined.set(encrypted);\n combined.set(tag, encrypted.length);\n const cryptoKey = await this.deriveAesKey(key);\n const decrypted = await crypto.subtle.decrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: iv.buffer as ArrayBuffer,\n },\n cryptoKey,\n combined.buffer as ArrayBuffer,\n );\n return new TextDecoder().decode(decrypted);\n }\n\n public equals(a: string, b: string): boolean {\n if (a.length !== b.length) {\n return false;\n }\n let result = 0;\n for (let i = 0; i < a.length; i++) {\n result |= a.charCodeAt(i) ^ b.charCodeAt(i);\n }\n return result === 0;\n }\n\n public randomUUID(): string {\n return crypto.randomUUID();\n }\n\n public randomText(length: number): string {\n const bytes = crypto.getRandomValues(new Uint8Array(length));\n return this.toBase64Url(bytes.buffer as ArrayBuffer).slice(0, length);\n }\n\n public randomCode(length: number): string {\n const max = 10 ** length;\n const array = new Uint32Array(1);\n // Rejection sampling to avoid modulo bias\n const limit = Math.floor(0x100000000 / max) * max;\n let value: number;\n do {\n crypto.getRandomValues(array);\n value = array[0]!;\n } while (value >= limit);\n const code = value % max;\n return String(code).padStart(length, \"0\");\n }\n\n protected toHex(buffer: ArrayBuffer | Uint8Array): string {\n const bytes =\n buffer instanceof Uint8Array ? buffer : new Uint8Array(buffer);\n return Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n }\n\n protected fromHex(hex: string): Uint8Array {\n const bytes = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n bytes[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);\n }\n return bytes;\n }\n\n protected toBase64Url(buffer: ArrayBuffer): string {\n const bytes = new Uint8Array(buffer);\n let binary = \"\";\n for (const byte of bytes) {\n binary += String.fromCharCode(byte);\n }\n return btoa(binary)\n .replace(/\\+/g, \"-\")\n .replace(/\\//g, \"_\")\n .replace(/=+$/, \"\");\n }\n\n protected async deriveAesKey(key: string): Promise<CryptoKey> {\n const encoded = new TextEncoder().encode(key);\n const hash = await crypto.subtle.digest(\"SHA-256\", encoded);\n return crypto.subtle.importKey(\n \"raw\",\n hash,\n { name: BrowserCryptoProvider.AES_ALGORITHM },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n\n /**\n * Derive an AES-GCM key from a low-entropy user passphrase using\n * PBKDF2-SHA-256. Use this in place of {@link deriveAesKey} whenever the\n * key material is a human-chosen string — a single SHA-256 over a\n * passphrase is brute-forceable by anyone with the ciphertext.\n *\n * OWASP 2023 recommends 600k iterations of PBKDF2-SHA-256 for password\n * storage; we use the same budget for client-side at-rest content keys.\n * Each protected blob carries its own random salt so the same passphrase\n * derives a different key per blob.\n */\n public async deriveKeyFromPassphrase(\n passphrase: string,\n saltHex: string,\n iterations = 600_000,\n ): Promise<CryptoKey> {\n const baseKey = await crypto.subtle.importKey(\n \"raw\",\n new TextEncoder().encode(passphrase),\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"],\n );\n return crypto.subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: this.fromHex(saltHex).buffer as ArrayBuffer,\n iterations,\n hash: \"SHA-256\",\n },\n baseKey,\n { name: BrowserCryptoProvider.AES_ALGORITHM, length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n\n /**\n * Encrypt `plaintext` with a pre-derived passphrase key, returning a\n * self-contained envelope (versioned for forward compatibility):\n *\n * { v: 1, salt, iv, ciphertext, kdf }\n *\n * `salt` + `kdf` are echoed back so {@link decryptWithPassphrase} can\n * reproduce the exact derivation. Each call generates a fresh IV — pass\n * a stable salt across saves of the same protected blob so the\n * passphrase only has to be derived once per session.\n */\n public async encryptWithPassphrase(\n plaintext: string,\n key: CryptoKey,\n saltHex: string,\n iterations = 600_000,\n ): Promise<string> {\n const iv = crypto.getRandomValues(\n new Uint8Array(BrowserCryptoProvider.AES_IV_LENGTH),\n );\n const encrypted = await crypto.subtle.encrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: iv.buffer as ArrayBuffer,\n },\n key,\n new TextEncoder().encode(plaintext),\n );\n return JSON.stringify({\n v: 1,\n salt: saltHex,\n iv: this.toHex(iv),\n ciphertext: this.toHex(new Uint8Array(encrypted)),\n kdf: { name: \"PBKDF2\", iterations, hash: \"SHA-256\" },\n });\n }\n\n /**\n * Reverse of {@link encryptWithPassphrase}. Throws when the passphrase\n * is wrong or the envelope is corrupt — both surface as the same\n * `OperationError` from Web Crypto, which the UI presents as a generic\n * \"wrong passphrase\" without revealing which.\n */\n public async decryptWithPassphrase(\n envelope: string,\n passphrase: string,\n ): Promise<string> {\n let parsed: {\n v?: number;\n salt?: string;\n iv?: string;\n ciphertext?: string;\n kdf?: { iterations?: number };\n };\n try {\n parsed = JSON.parse(envelope);\n } catch {\n throw new AlephaError(\"Invalid protected folio envelope\");\n }\n if (!parsed.salt || !parsed.iv || !parsed.ciphertext) {\n throw new AlephaError(\"Invalid protected folio envelope\");\n }\n const key = await this.deriveKeyFromPassphrase(\n passphrase,\n parsed.salt,\n parsed.kdf?.iterations ?? 600_000,\n );\n const decrypted = await crypto.subtle.decrypt(\n {\n name: BrowserCryptoProvider.AES_ALGORITHM,\n iv: this.fromHex(parsed.iv).buffer as ArrayBuffer,\n },\n key,\n this.fromHex(parsed.ciphertext).buffer as ArrayBuffer,\n );\n return new TextDecoder().decode(decrypted);\n }\n}\n","import { $module } from \"alepha\";\nimport { BrowserCryptoProvider } from \"./providers/BrowserCryptoProvider.ts\";\n\nexport { BrowserCryptoProvider as CryptoProvider } from \"./providers/BrowserCryptoProvider.ts\";\n\n/**\n * Cryptographic utilities: hashing, HMAC, AES-256-GCM encryption, password hashing, and secure random generation.\n *\n * @module alepha.crypto\n */\nexport const AlephaCrypto = $module({\n name: \"alepha.crypto\",\n services: [BrowserCryptoProvider],\n});\n"],"mappings":"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"}
|
package/dist/crypto/index.d.ts
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import * as _$alepha from "alepha";
|
|
2
1
|
import { Alepha } from "alepha";
|
|
3
2
|
import { ScryptOptions } from "node:crypto";
|
|
4
|
-
import * as _$alepha_logger0 from "alepha/logger";
|
|
5
|
-
import * as _$typebox from "typebox";
|
|
6
3
|
|
|
7
4
|
//#region ../../src/crypto/providers/CryptoProvider.d.ts
|
|
8
5
|
declare class CryptoProvider {
|
|
@@ -40,17 +37,17 @@ declare class CryptoProvider {
|
|
|
40
37
|
//#endregion
|
|
41
38
|
//#region ../../src/crypto/providers/SecretProvider.d.ts
|
|
42
39
|
declare const DEFAULT_SECRET_KEY_VALUE = "change-me-in-production";
|
|
43
|
-
declare const alephaSecretEnvSchema:
|
|
44
|
-
APP_SECRET:
|
|
40
|
+
declare const alephaSecretEnvSchema: import("typebox").TObject<{
|
|
41
|
+
APP_SECRET: import("typebox").TString;
|
|
45
42
|
}>;
|
|
46
43
|
declare class SecretProvider {
|
|
47
|
-
protected readonly log:
|
|
44
|
+
protected readonly log: import("alepha/logger").Logger;
|
|
48
45
|
protected readonly alepha: Alepha;
|
|
49
46
|
protected readonly env: {
|
|
50
47
|
APP_SECRET: string;
|
|
51
48
|
};
|
|
52
49
|
get secretKey(): string;
|
|
53
|
-
protected readonly configure:
|
|
50
|
+
protected readonly configure: import("alepha").HookPrimitive<"configure">;
|
|
54
51
|
}
|
|
55
52
|
//#endregion
|
|
56
53
|
//#region ../../src/crypto/index.d.ts
|
|
@@ -59,7 +56,7 @@ declare class SecretProvider {
|
|
|
59
56
|
*
|
|
60
57
|
* @module alepha.crypto
|
|
61
58
|
*/
|
|
62
|
-
declare const AlephaCrypto:
|
|
59
|
+
declare const AlephaCrypto: import("alepha").Service<import("alepha").Module>;
|
|
63
60
|
//#endregion
|
|
64
61
|
export { AlephaCrypto, CryptoProvider, DEFAULT_SECRET_KEY_VALUE, SecretProvider, alephaSecretEnvSchema };
|
|
65
62
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/crypto/providers/CryptoProvider.ts","../../src/crypto/providers/SecretProvider.ts","../../src/crypto/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/crypto/providers/CryptoProvider.ts","../../src/crypto/providers/SecretProvider.ts","../../src/crypto/index.ts"],"mappings":";;;;cAca,cAAA;EAAA,0BACe,cAAA,EAAgB,aAAA;EAAA,0BAKhB,iBAAA;EAAA,0BACA,WAAA;EAAA,0BACA,aAAA;EAAA,0BACA,aAAA;EAAA,0BACA,cAAA;EAAA,0BACA,cAAA;EAEb,YAAA,CAAa,QAAA,WAAmB,OAAA;EAWhC,cAAA,CACX,QAAA,UACA,MAAA,WACC,OAAA;EAuCI,IAAA,CAAK,IAAA,UAAc,SAAA;EAInB,IAAA,CAAK,IAAA,UAAc,MAAA,UAAgB,SAAA;EAInC,UAAA,CACL,IAAA,UACA,SAAA,UACA,MAAA,UACA,SAAA;EAMK,OAAA,CAAQ,SAAA,UAAmB,GAAA;EAc3B,OAAA,CAAQ,UAAA,UAAoB,GAAA;EAoB5B,MAAA,CAAO,CAAA,UAAW,CAAA;EAWlB,UAAA;EAIA,UAAA,CAAW,MAAA;EAIX,UAAA,CAAW,MAAA;EAAA,UAMR,WAAA,CACR,QAAA,UACA,IAAA,UACA,MAAA,UACA,OAAA,EAAS,aAAA,GACR,OAAA,CAAQ,MAAA;EAAA,UASD,YAAA,CAAa,GAAA,WAAc,MAAA;EA5JK;;;;;;;EA0K7B,uBAAA,CACX,UAAA,UACA,OAAA,UACA,UAAA,YACC,OAAA,CAAQ,SAAA;EAwBE,qBAAA,CACX,SAAA,UACA,GAAA,EAAK,SAAA,EACL,OAAA,UACA,UAAA,YACC,OAAA;EAkBU,qBAAA,CACX,QAAA,UACA,UAAA,WACC,OAAA;AAAA;;;cC5OQ,wBAAA;AAAA,cAEA,qBAAA,oBAAqB,OAAA;;;cAQrB,cAAA;EAAA,mBACQ,GAAA,0BAAG,MAAA;EAAA,mBACH,MAAA,EAAM,MAAA;EAAA,mBACN,GAAA;;;MAER,SAAA;EAAA,mBAIQ,SAAA,mBAAS,aAAA;AAAA;;;;;ADR9B;;;cEFa,YAAA,mBAAY,OAAA,kBAAA,MAAA"}
|
package/dist/crypto/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/crypto/providers/CryptoProvider.ts","../../src/crypto/providers/SecretProvider.ts","../../src/crypto/index.ts"],"sourcesContent":["import type { ScryptOptions } from \"node:crypto\";\nimport {\n createCipheriv,\n createDecipheriv,\n createHash,\n createHmac,\n randomBytes,\n randomInt,\n randomUUID,\n scrypt,\n timingSafeEqual,\n} from \"node:crypto\";\nimport { AlephaError } from \"alepha\";\n\nexport class CryptoProvider {\n protected static readonly SCRYPT_OPTIONS: ScryptOptions = {\n N: 16384,\n r: 8,\n p: 1,\n };\n protected static readonly SCRYPT_KEY_LENGTH = 64;\n protected static readonly SALT_LENGTH = 16;\n protected static readonly AES_ALGORITHM = \"aes-256-gcm\";\n protected static readonly AES_IV_LENGTH = 12;\n protected static readonly AES_TAG_LENGTH = 16;\n protected static readonly AES_KEY_LENGTH = 32;\n\n public async hashPassword(password: string): Promise<string> {\n const salt = randomBytes(CryptoProvider.SALT_LENGTH).toString(\"hex\");\n const derivedKey = (await this.scryptAsync(\n password,\n salt,\n CryptoProvider.SCRYPT_KEY_LENGTH,\n CryptoProvider.SCRYPT_OPTIONS,\n )) as Buffer;\n return `${salt}:${derivedKey.toString(\"hex\")}`;\n }\n\n public async verifyPassword(\n password: string,\n stored: string,\n ): Promise<boolean> {\n if (!stored || typeof stored !== \"string\") {\n return false;\n }\n\n const parts = stored.split(\":\");\n if (parts.length !== 2) {\n return false;\n }\n\n const [salt, originalHex] = parts;\n\n if (!salt || !originalHex) {\n return false;\n }\n\n if (originalHex.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(originalHex)) {\n return false;\n }\n\n try {\n const derivedKey = (await this.scryptAsync(\n password,\n salt,\n CryptoProvider.SCRYPT_KEY_LENGTH,\n CryptoProvider.SCRYPT_OPTIONS,\n )) as Buffer;\n const originalKey = Buffer.from(originalHex, \"hex\");\n\n if (derivedKey.length !== originalKey.length) {\n return false;\n }\n\n return timingSafeEqual(derivedKey, originalKey);\n } catch {\n return false;\n }\n }\n\n public hash(data: string, algorithm = \"sha256\"): string {\n return createHash(algorithm).update(data).digest(\"hex\");\n }\n\n public hmac(data: string, secret: string, algorithm = \"sha256\"): string {\n return createHmac(algorithm, secret).update(data).digest(\"hex\");\n }\n\n public verifyHmac(\n data: string,\n signature: string,\n secret: string,\n algorithm = \"sha256\",\n ): boolean {\n const expected = this.hmac(data, secret, algorithm);\n return this.equals(expected, signature);\n }\n\n public encrypt(plaintext: string, key: string): string {\n const keyBuffer = this.deriveAesKey(key);\n const iv = randomBytes(CryptoProvider.AES_IV_LENGTH);\n const cipher = createCipheriv(CryptoProvider.AES_ALGORITHM, keyBuffer, iv, {\n authTagLength: CryptoProvider.AES_TAG_LENGTH,\n });\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n return `${iv.toString(\"hex\")}:${tag.toString(\"hex\")}:${encrypted.toString(\"hex\")}`;\n }\n\n public decrypt(ciphertext: string, key: string): string {\n const parts = ciphertext.split(\":\");\n if (parts.length !== 3) {\n throw new AlephaError(\"Invalid ciphertext format\");\n }\n\n const [ivHex, tagHex, encryptedHex] = parts;\n const keyBuffer = this.deriveAesKey(key);\n const decipher = createDecipheriv(\n CryptoProvider.AES_ALGORITHM,\n keyBuffer,\n Buffer.from(ivHex!, \"hex\"),\n { authTagLength: CryptoProvider.AES_TAG_LENGTH },\n );\n decipher.setAuthTag(Buffer.from(tagHex!, \"hex\"));\n return (\n decipher.update(encryptedHex!, \"hex\", \"utf8\") + decipher.final(\"utf8\")\n );\n }\n\n public equals(a: string, b: string): boolean {\n const bufA = Buffer.from(a);\n const bufB = Buffer.from(b);\n if (bufA.length !== bufB.length) {\n // Constant-time compare against self to avoid timing leak on length mismatch\n timingSafeEqual(bufA, bufA);\n return false;\n }\n return timingSafeEqual(bufA, bufB);\n }\n\n public randomUUID(): string {\n return randomUUID();\n }\n\n public randomText(length: number): string {\n return randomBytes(length).toString(\"base64url\").slice(0, length);\n }\n\n public randomCode(length: number): string {\n const max = 10 ** length;\n const code = randomInt(max);\n return String(code).padStart(length, \"0\");\n }\n\n protected scryptAsync(\n password: string,\n salt: string,\n keylen: number,\n options: ScryptOptions,\n ): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n scrypt(password, salt, keylen, options, (err, derivedKey) => {\n if (err) reject(err);\n else resolve(derivedKey);\n });\n });\n }\n\n protected deriveAesKey(key: string): Buffer {\n return createHash(\"sha256\")\n .update(key)\n .digest()\n .subarray(0, CryptoProvider.AES_KEY_LENGTH);\n }\n\n /**\n * Web Crypto API parity with `BrowserCryptoProvider`. Node 18+ exposes\n * `globalThis.crypto.subtle`, so the implementations are the same on\n * both runtimes. Server-side use is unusual — passphrase-derived keys\n * are a browser-only flow in Alepha — but these stubs exist so the\n * type surface matches and shared call sites compile.\n */\n public async deriveKeyFromPassphrase(\n passphrase: string,\n saltHex: string,\n iterations = 600_000,\n ): Promise<CryptoKey> {\n const subtle = (globalThis as { crypto: { subtle: SubtleCrypto } }).crypto\n .subtle;\n const baseKey = await subtle.importKey(\n \"raw\",\n new TextEncoder().encode(passphrase),\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"],\n );\n return subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: hexToBytes(saltHex).buffer as ArrayBuffer,\n iterations,\n hash: \"SHA-256\",\n },\n baseKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n\n public async encryptWithPassphrase(\n plaintext: string,\n key: CryptoKey,\n saltHex: string,\n iterations = 600_000,\n ): Promise<string> {\n const subtle = (globalThis as { crypto: { subtle: SubtleCrypto } }).crypto\n .subtle;\n const iv = randomBytes(CryptoProvider.AES_IV_LENGTH);\n const encrypted = await subtle.encrypt(\n { name: \"AES-GCM\", iv: iv.buffer as ArrayBuffer },\n key,\n new TextEncoder().encode(plaintext),\n );\n return JSON.stringify({\n v: 1,\n salt: saltHex,\n iv: iv.toString(\"hex\"),\n ciphertext: Buffer.from(encrypted).toString(\"hex\"),\n kdf: { name: \"PBKDF2\", iterations, hash: \"SHA-256\" },\n });\n }\n\n public async decryptWithPassphrase(\n envelope: string,\n passphrase: string,\n ): Promise<string> {\n const subtle = (globalThis as { crypto: { subtle: SubtleCrypto } }).crypto\n .subtle;\n let parsed: {\n salt?: string;\n iv?: string;\n ciphertext?: string;\n kdf?: { iterations?: number };\n };\n try {\n parsed = JSON.parse(envelope);\n } catch {\n throw new AlephaError(\"Invalid protected envelope\");\n }\n if (!parsed.salt || !parsed.iv || !parsed.ciphertext) {\n throw new AlephaError(\"Invalid protected envelope\");\n }\n const key = await this.deriveKeyFromPassphrase(\n passphrase,\n parsed.salt,\n parsed.kdf?.iterations ?? 600_000,\n );\n const decrypted = await subtle.decrypt(\n { name: \"AES-GCM\", iv: hexToBytes(parsed.iv).buffer as ArrayBuffer },\n key,\n hexToBytes(parsed.ciphertext).buffer as ArrayBuffer,\n );\n return new TextDecoder().decode(decrypted);\n }\n}\n\nconst hexToBytes = (hex: string): Uint8Array => {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n out[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);\n }\n return out;\n};\n","import { $env, $hook, $inject, Alepha, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\n\nexport const DEFAULT_SECRET_KEY_VALUE = \"change-me-in-production\";\n\nexport const alephaSecretEnvSchema = t.object({\n APP_SECRET: t.text({\n default: DEFAULT_SECRET_KEY_VALUE,\n description:\n \"The secret key used for signing JWTs, encrypting cookies, and other security features.\",\n }),\n});\n\nexport class SecretProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(alephaSecretEnvSchema);\n\n public get secretKey(): string {\n return this.env.APP_SECRET;\n }\n\n protected readonly configure = $hook({\n on: \"configure\",\n handler: async () => {\n // It's not ideal from a security pov but it's the best for convenience,\n // it can be changed to a hard error in a future release.\n if (\n this.secretKey === DEFAULT_SECRET_KEY_VALUE &&\n this.alepha.isProduction()\n ) {\n this.log.warn(\n \"Using default secret key. Please set a secure APP_SECRET environment variable.\",\n );\n }\n },\n });\n}\n","import { $module } from \"alepha\";\nimport { CryptoProvider } from \"./providers/CryptoProvider.ts\";\nimport { SecretProvider } from \"./providers/SecretProvider.ts\";\n\nexport * from \"./providers/CryptoProvider.ts\";\nexport * from \"./providers/SecretProvider.ts\";\n\n/**\n * Cryptographic utilities: hashing, HMAC, AES-256-GCM encryption, password hashing, and secure random generation.\n *\n * @module alepha.crypto\n */\nexport const AlephaCrypto = $module({\n name: \"alepha.crypto\",\n services: [CryptoProvider, SecretProvider],\n});\n"],"mappings":";;;;AAcA,IAAa,iBAAb,MAAa,eAAe;CAC1B,OAA0B,iBAAgC;EACxD,GAAG;EACH,GAAG;EACH,GAAG;EACJ;CACD,OAA0B,oBAAoB;CAC9C,OAA0B,cAAc;CACxC,OAA0B,gBAAgB;CAC1C,OAA0B,gBAAgB;CAC1C,OAA0B,iBAAiB;CAC3C,OAA0B,iBAAiB;CAE3C,MAAa,aAAa,UAAmC;EAC3D,MAAM,OAAO,YAAY,eAAe,YAAY,CAAC,SAAS,MAAM;EAOpE,OAAO,GAAG,KAAK,IAAG,MANQ,KAAK,YAC7B,UACA,MACA,eAAe,mBACf,eAAe,eAChB,EAC4B,SAAS,MAAM;;CAG9C,MAAa,eACX,UACA,QACkB;EAClB,IAAI,CAAC,UAAU,OAAO,WAAW,UAC/B,OAAO;EAGT,MAAM,QAAQ,OAAO,MAAM,IAAI;EAC/B,IAAI,MAAM,WAAW,GACnB,OAAO;EAGT,MAAM,CAAC,MAAM,eAAe;EAE5B,IAAI,CAAC,QAAQ,CAAC,aACZ,OAAO;EAGT,IAAI,YAAY,SAAS,MAAM,KAAK,CAAC,eAAe,KAAK,YAAY,EACnE,OAAO;EAGT,IAAI;GACF,MAAM,aAAc,MAAM,KAAK,YAC7B,UACA,MACA,eAAe,mBACf,eAAe,eAChB;GACD,MAAM,cAAc,OAAO,KAAK,aAAa,MAAM;GAEnD,IAAI,WAAW,WAAW,YAAY,QACpC,OAAO;GAGT,OAAO,gBAAgB,YAAY,YAAY;UACzC;GACN,OAAO;;;CAIX,KAAY,MAAc,YAAY,UAAkB;EACtD,OAAO,WAAW,UAAU,CAAC,OAAO,KAAK,CAAC,OAAO,MAAM;;CAGzD,KAAY,MAAc,QAAgB,YAAY,UAAkB;EACtE,OAAO,WAAW,WAAW,OAAO,CAAC,OAAO,KAAK,CAAC,OAAO,MAAM;;CAGjE,WACE,MACA,WACA,QACA,YAAY,UACH;EACT,MAAM,WAAW,KAAK,KAAK,MAAM,QAAQ,UAAU;EACnD,OAAO,KAAK,OAAO,UAAU,UAAU;;CAGzC,QAAe,WAAmB,KAAqB;EACrD,MAAM,YAAY,KAAK,aAAa,IAAI;EACxC,MAAM,KAAK,YAAY,eAAe,cAAc;EACpD,MAAM,SAAS,eAAe,eAAe,eAAe,WAAW,IAAI,EACzE,eAAe,eAAe,gBAC/B,CAAC;EACF,MAAM,YAAY,OAAO,OAAO,CAC9B,OAAO,OAAO,WAAW,OAAO,EAChC,OAAO,OAAO,CACf,CAAC;EACF,MAAM,MAAM,OAAO,YAAY;EAC/B,OAAO,GAAG,GAAG,SAAS,MAAM,CAAC,GAAG,IAAI,SAAS,MAAM,CAAC,GAAG,UAAU,SAAS,MAAM;;CAGlF,QAAe,YAAoB,KAAqB;EACtD,MAAM,QAAQ,WAAW,MAAM,IAAI;EACnC,IAAI,MAAM,WAAW,GACnB,MAAM,IAAI,YAAY,4BAA4B;EAGpD,MAAM,CAAC,OAAO,QAAQ,gBAAgB;EACtC,MAAM,YAAY,KAAK,aAAa,IAAI;EACxC,MAAM,WAAW,iBACf,eAAe,eACf,WACA,OAAO,KAAK,OAAQ,MAAM,EAC1B,EAAE,eAAe,eAAe,gBAAgB,CACjD;EACD,SAAS,WAAW,OAAO,KAAK,QAAS,MAAM,CAAC;EAChD,OACE,SAAS,OAAO,cAAe,OAAO,OAAO,GAAG,SAAS,MAAM,OAAO;;CAI1E,OAAc,GAAW,GAAoB;EAC3C,MAAM,OAAO,OAAO,KAAK,EAAE;EAC3B,MAAM,OAAO,OAAO,KAAK,EAAE;EAC3B,IAAI,KAAK,WAAW,KAAK,QAAQ;GAE/B,gBAAgB,MAAM,KAAK;GAC3B,OAAO;;EAET,OAAO,gBAAgB,MAAM,KAAK;;CAGpC,aAA4B;EAC1B,OAAO,YAAY;;CAGrB,WAAkB,QAAwB;EACxC,OAAO,YAAY,OAAO,CAAC,SAAS,YAAY,CAAC,MAAM,GAAG,OAAO;;CAGnE,WAAkB,QAAwB;EAExC,MAAM,OAAO,UADD,MAAM,OACS;EAC3B,OAAO,OAAO,KAAK,CAAC,SAAS,QAAQ,IAAI;;CAG3C,YACE,UACA,MACA,QACA,SACiB;EACjB,OAAO,IAAI,SAAS,SAAS,WAAW;GACtC,OAAO,UAAU,MAAM,QAAQ,UAAU,KAAK,eAAe;IAC3D,IAAI,KAAK,OAAO,IAAI;SACf,QAAQ,WAAW;KACxB;IACF;;CAGJ,aAAuB,KAAqB;EAC1C,OAAO,WAAW,SAAS,CACxB,OAAO,IAAI,CACX,QAAQ,CACR,SAAS,GAAG,eAAe,eAAe;;;;;;;;;CAU/C,MAAa,wBACX,YACA,SACA,aAAa,KACO;EACpB,MAAM,SAAU,WAAoD,OACjE;EACH,MAAM,UAAU,MAAM,OAAO,UAC3B,OACA,IAAI,aAAa,CAAC,OAAO,WAAW,EACpC,EAAE,MAAM,UAAU,EAClB,OACA,CAAC,YAAY,CACd;EACD,OAAO,OAAO,UACZ;GACE,MAAM;GACN,MAAM,WAAW,QAAQ,CAAC;GAC1B;GACA,MAAM;GACP,EACD,SACA;GAAE,MAAM;GAAW,QAAQ;GAAK,EAChC,OACA,CAAC,WAAW,UAAU,CACvB;;CAGH,MAAa,sBACX,WACA,KACA,SACA,aAAa,KACI;EACjB,MAAM,SAAU,WAAoD,OACjE;EACH,MAAM,KAAK,YAAY,eAAe,cAAc;EACpD,MAAM,YAAY,MAAM,OAAO,QAC7B;GAAE,MAAM;GAAW,IAAI,GAAG;GAAuB,EACjD,KACA,IAAI,aAAa,CAAC,OAAO,UAAU,CACpC;EACD,OAAO,KAAK,UAAU;GACpB,GAAG;GACH,MAAM;GACN,IAAI,GAAG,SAAS,MAAM;GACtB,YAAY,OAAO,KAAK,UAAU,CAAC,SAAS,MAAM;GAClD,KAAK;IAAE,MAAM;IAAU;IAAY,MAAM;IAAW;GACrD,CAAC;;CAGJ,MAAa,sBACX,UACA,YACiB;EACjB,MAAM,SAAU,WAAoD,OACjE;EACH,IAAI;EAMJ,IAAI;GACF,SAAS,KAAK,MAAM,SAAS;UACvB;GACN,MAAM,IAAI,YAAY,6BAA6B;;EAErD,IAAI,CAAC,OAAO,QAAQ,CAAC,OAAO,MAAM,CAAC,OAAO,YACxC,MAAM,IAAI,YAAY,6BAA6B;EAErD,MAAM,MAAM,MAAM,KAAK,wBACrB,YACA,OAAO,MACP,OAAO,KAAK,cAAc,IAC3B;EACD,MAAM,YAAY,MAAM,OAAO,QAC7B;GAAE,MAAM;GAAW,IAAI,WAAW,OAAO,GAAG,CAAC;GAAuB,EACpE,KACA,WAAW,OAAO,WAAW,CAAC,OAC/B;EACD,OAAO,IAAI,aAAa,CAAC,OAAO,UAAU;;;AAI9C,MAAM,cAAc,QAA4B;CAC9C,MAAM,MAAM,IAAI,WAAW,IAAI,SAAS,EAAE;CAC1C,KAAK,IAAI,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK,GACnC,IAAI,IAAI,KAAK,OAAO,SAAS,IAAI,UAAU,GAAG,IAAI,EAAE,EAAE,GAAG;CAE3D,OAAO;;;;AChRT,MAAa,2BAA2B;AAExC,MAAa,wBAAwB,EAAE,OAAO,EAC5C,YAAY,EAAE,KAAK;CACjB,SAAS;CACT,aACE;CACH,CAAC,EACH,CAAC;AAEF,IAAa,iBAAb,MAA4B;CAC1B,MAAyB,SAAS;CAClC,SAA4B,QAAQ,OAAO;CAC3C,MAAyB,KAAK,sBAAsB;CAEpD,IAAW,YAAoB;EAC7B,OAAO,KAAK,IAAI;;CAGlB,YAA+B,MAAM;EACnC,IAAI;EACJ,SAAS,YAAY;GAGnB,IACE,KAAK,cAAA,6BACL,KAAK,OAAO,cAAc,EAE1B,KAAK,IAAI,KACP,iFACD;;EAGN,CAAC;;;;;;;;;ACxBJ,MAAa,eAAe,QAAQ;CAClC,MAAM;CACN,UAAU,CAAC,gBAAgB,eAAe;CAC3C,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/crypto/providers/CryptoProvider.ts","../../src/crypto/providers/SecretProvider.ts","../../src/crypto/index.ts"],"sourcesContent":["import type { ScryptOptions } from \"node:crypto\";\nimport {\n createCipheriv,\n createDecipheriv,\n createHash,\n createHmac,\n randomBytes,\n randomInt,\n randomUUID,\n scrypt,\n timingSafeEqual,\n} from \"node:crypto\";\nimport { AlephaError } from \"alepha\";\n\nexport class CryptoProvider {\n protected static readonly SCRYPT_OPTIONS: ScryptOptions = {\n N: 16384,\n r: 8,\n p: 1,\n };\n protected static readonly SCRYPT_KEY_LENGTH = 64;\n protected static readonly SALT_LENGTH = 16;\n protected static readonly AES_ALGORITHM = \"aes-256-gcm\";\n protected static readonly AES_IV_LENGTH = 12;\n protected static readonly AES_TAG_LENGTH = 16;\n protected static readonly AES_KEY_LENGTH = 32;\n\n public async hashPassword(password: string): Promise<string> {\n const salt = randomBytes(CryptoProvider.SALT_LENGTH).toString(\"hex\");\n const derivedKey = (await this.scryptAsync(\n password,\n salt,\n CryptoProvider.SCRYPT_KEY_LENGTH,\n CryptoProvider.SCRYPT_OPTIONS,\n )) as Buffer;\n return `${salt}:${derivedKey.toString(\"hex\")}`;\n }\n\n public async verifyPassword(\n password: string,\n stored: string,\n ): Promise<boolean> {\n if (!stored || typeof stored !== \"string\") {\n return false;\n }\n\n const parts = stored.split(\":\");\n if (parts.length !== 2) {\n return false;\n }\n\n const [salt, originalHex] = parts;\n\n if (!salt || !originalHex) {\n return false;\n }\n\n if (originalHex.length % 2 !== 0 || !/^[0-9a-f]+$/i.test(originalHex)) {\n return false;\n }\n\n try {\n const derivedKey = (await this.scryptAsync(\n password,\n salt,\n CryptoProvider.SCRYPT_KEY_LENGTH,\n CryptoProvider.SCRYPT_OPTIONS,\n )) as Buffer;\n const originalKey = Buffer.from(originalHex, \"hex\");\n\n if (derivedKey.length !== originalKey.length) {\n return false;\n }\n\n return timingSafeEqual(derivedKey, originalKey);\n } catch {\n return false;\n }\n }\n\n public hash(data: string, algorithm = \"sha256\"): string {\n return createHash(algorithm).update(data).digest(\"hex\");\n }\n\n public hmac(data: string, secret: string, algorithm = \"sha256\"): string {\n return createHmac(algorithm, secret).update(data).digest(\"hex\");\n }\n\n public verifyHmac(\n data: string,\n signature: string,\n secret: string,\n algorithm = \"sha256\",\n ): boolean {\n const expected = this.hmac(data, secret, algorithm);\n return this.equals(expected, signature);\n }\n\n public encrypt(plaintext: string, key: string): string {\n const keyBuffer = this.deriveAesKey(key);\n const iv = randomBytes(CryptoProvider.AES_IV_LENGTH);\n const cipher = createCipheriv(CryptoProvider.AES_ALGORITHM, keyBuffer, iv, {\n authTagLength: CryptoProvider.AES_TAG_LENGTH,\n });\n const encrypted = Buffer.concat([\n cipher.update(plaintext, \"utf8\"),\n cipher.final(),\n ]);\n const tag = cipher.getAuthTag();\n return `${iv.toString(\"hex\")}:${tag.toString(\"hex\")}:${encrypted.toString(\"hex\")}`;\n }\n\n public decrypt(ciphertext: string, key: string): string {\n const parts = ciphertext.split(\":\");\n if (parts.length !== 3) {\n throw new AlephaError(\"Invalid ciphertext format\");\n }\n\n const [ivHex, tagHex, encryptedHex] = parts;\n const keyBuffer = this.deriveAesKey(key);\n const decipher = createDecipheriv(\n CryptoProvider.AES_ALGORITHM,\n keyBuffer,\n Buffer.from(ivHex!, \"hex\"),\n { authTagLength: CryptoProvider.AES_TAG_LENGTH },\n );\n decipher.setAuthTag(Buffer.from(tagHex!, \"hex\"));\n return (\n decipher.update(encryptedHex!, \"hex\", \"utf8\") + decipher.final(\"utf8\")\n );\n }\n\n public equals(a: string, b: string): boolean {\n const bufA = Buffer.from(a);\n const bufB = Buffer.from(b);\n if (bufA.length !== bufB.length) {\n // Constant-time compare against self to avoid timing leak on length mismatch\n timingSafeEqual(bufA, bufA);\n return false;\n }\n return timingSafeEqual(bufA, bufB);\n }\n\n public randomUUID(): string {\n return randomUUID();\n }\n\n public randomText(length: number): string {\n return randomBytes(length).toString(\"base64url\").slice(0, length);\n }\n\n public randomCode(length: number): string {\n const max = 10 ** length;\n const code = randomInt(max);\n return String(code).padStart(length, \"0\");\n }\n\n protected scryptAsync(\n password: string,\n salt: string,\n keylen: number,\n options: ScryptOptions,\n ): Promise<Buffer> {\n return new Promise((resolve, reject) => {\n scrypt(password, salt, keylen, options, (err, derivedKey) => {\n if (err) reject(err);\n else resolve(derivedKey);\n });\n });\n }\n\n protected deriveAesKey(key: string): Buffer {\n return createHash(\"sha256\")\n .update(key)\n .digest()\n .subarray(0, CryptoProvider.AES_KEY_LENGTH);\n }\n\n /**\n * Web Crypto API parity with `BrowserCryptoProvider`. Node 18+ exposes\n * `globalThis.crypto.subtle`, so the implementations are the same on\n * both runtimes. Server-side use is unusual — passphrase-derived keys\n * are a browser-only flow in Alepha — but these stubs exist so the\n * type surface matches and shared call sites compile.\n */\n public async deriveKeyFromPassphrase(\n passphrase: string,\n saltHex: string,\n iterations = 600_000,\n ): Promise<CryptoKey> {\n const subtle = (globalThis as { crypto: { subtle: SubtleCrypto } }).crypto\n .subtle;\n const baseKey = await subtle.importKey(\n \"raw\",\n new TextEncoder().encode(passphrase),\n { name: \"PBKDF2\" },\n false,\n [\"deriveKey\"],\n );\n return subtle.deriveKey(\n {\n name: \"PBKDF2\",\n salt: hexToBytes(saltHex).buffer as ArrayBuffer,\n iterations,\n hash: \"SHA-256\",\n },\n baseKey,\n { name: \"AES-GCM\", length: 256 },\n false,\n [\"encrypt\", \"decrypt\"],\n );\n }\n\n public async encryptWithPassphrase(\n plaintext: string,\n key: CryptoKey,\n saltHex: string,\n iterations = 600_000,\n ): Promise<string> {\n const subtle = (globalThis as { crypto: { subtle: SubtleCrypto } }).crypto\n .subtle;\n const iv = randomBytes(CryptoProvider.AES_IV_LENGTH);\n const encrypted = await subtle.encrypt(\n { name: \"AES-GCM\", iv: iv.buffer as ArrayBuffer },\n key,\n new TextEncoder().encode(plaintext),\n );\n return JSON.stringify({\n v: 1,\n salt: saltHex,\n iv: iv.toString(\"hex\"),\n ciphertext: Buffer.from(encrypted).toString(\"hex\"),\n kdf: { name: \"PBKDF2\", iterations, hash: \"SHA-256\" },\n });\n }\n\n public async decryptWithPassphrase(\n envelope: string,\n passphrase: string,\n ): Promise<string> {\n const subtle = (globalThis as { crypto: { subtle: SubtleCrypto } }).crypto\n .subtle;\n let parsed: {\n salt?: string;\n iv?: string;\n ciphertext?: string;\n kdf?: { iterations?: number };\n };\n try {\n parsed = JSON.parse(envelope);\n } catch {\n throw new AlephaError(\"Invalid protected envelope\");\n }\n if (!parsed.salt || !parsed.iv || !parsed.ciphertext) {\n throw new AlephaError(\"Invalid protected envelope\");\n }\n const key = await this.deriveKeyFromPassphrase(\n passphrase,\n parsed.salt,\n parsed.kdf?.iterations ?? 600_000,\n );\n const decrypted = await subtle.decrypt(\n { name: \"AES-GCM\", iv: hexToBytes(parsed.iv).buffer as ArrayBuffer },\n key,\n hexToBytes(parsed.ciphertext).buffer as ArrayBuffer,\n );\n return new TextDecoder().decode(decrypted);\n }\n}\n\nconst hexToBytes = (hex: string): Uint8Array => {\n const out = new Uint8Array(hex.length / 2);\n for (let i = 0; i < hex.length; i += 2) {\n out[i / 2] = Number.parseInt(hex.substring(i, i + 2), 16);\n }\n return out;\n};\n","import { $env, $hook, $inject, Alepha, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\n\nexport const DEFAULT_SECRET_KEY_VALUE = \"change-me-in-production\";\n\nexport const alephaSecretEnvSchema = t.object({\n APP_SECRET: t.text({\n default: DEFAULT_SECRET_KEY_VALUE,\n description:\n \"The secret key used for signing JWTs, encrypting cookies, and other security features.\",\n }),\n});\n\nexport class SecretProvider {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly env = $env(alephaSecretEnvSchema);\n\n public get secretKey(): string {\n return this.env.APP_SECRET;\n }\n\n protected readonly configure = $hook({\n on: \"configure\",\n handler: async () => {\n // It's not ideal from a security pov but it's the best for convenience,\n // it can be changed to a hard error in a future release.\n if (\n this.secretKey === DEFAULT_SECRET_KEY_VALUE &&\n this.alepha.isProduction()\n ) {\n this.log.warn(\n \"Using default secret key. Please set a secure APP_SECRET environment variable.\",\n );\n }\n },\n });\n}\n","import { $module } from \"alepha\";\nimport { CryptoProvider } from \"./providers/CryptoProvider.ts\";\nimport { SecretProvider } from \"./providers/SecretProvider.ts\";\n\nexport * from \"./providers/CryptoProvider.ts\";\nexport * from \"./providers/SecretProvider.ts\";\n\n/**\n * Cryptographic utilities: hashing, HMAC, AES-256-GCM encryption, password hashing, and secure random generation.\n *\n * @module alepha.crypto\n */\nexport const AlephaCrypto = $module({\n name: \"alepha.crypto\",\n services: [CryptoProvider, SecretProvider],\n});\n"],"mappings":"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"}
|
package/dist/datetime/index.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import * as _$alepha from "alepha";
|
|
2
1
|
import { Alepha, KIND, Middleware, Primitive } from "alepha";
|
|
3
2
|
import dayjsDuration, { DurationUnitType } from "dayjs/plugin/duration.js";
|
|
4
3
|
import { Dayjs, ManipulateType, OpUnitType, PluginFunc, QUnitType } from "dayjs";
|
|
@@ -75,8 +74,8 @@ declare class DateTimeProvider {
|
|
|
75
74
|
protected readonly timeouts: Timeout[];
|
|
76
75
|
protected readonly intervals: Interval[];
|
|
77
76
|
constructor();
|
|
78
|
-
protected readonly onStart:
|
|
79
|
-
protected readonly onStop:
|
|
77
|
+
protected readonly onStart: import("alepha").HookPrimitive<"start">;
|
|
78
|
+
protected readonly onStop: import("alepha").HookPrimitive<"stop">;
|
|
80
79
|
setLocale(locale: string): void;
|
|
81
80
|
isDateTime(value: unknown): value is DateTime;
|
|
82
81
|
/**
|
|
@@ -291,7 +290,7 @@ declare const $timeout: (duration: DurationLike) => Middleware;
|
|
|
291
290
|
*
|
|
292
291
|
* @module alepha.datetime
|
|
293
292
|
*/
|
|
294
|
-
declare const AlephaDateTime:
|
|
293
|
+
declare const AlephaDateTime: import("alepha").Service<import("alepha").Module>;
|
|
295
294
|
//#endregion
|
|
296
295
|
export { $debounce, $interval, $throttle, $timeout, AlephaDateTime, DateTime, DateTimeInput, DateTimeProvider, DebounceOptions, Duration, DurationLike, type DurationUnitType, Interval, IntervalPrimitive, IntervalPrimitiveOptions, type ManipulateType, type OpUnitType, type QUnitType, ThrottleOptions, Timeout, isDateTime };
|
|
297
296
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$debounce.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/primitives/$throttle.ts","../../src/datetime/primitives/$timeout.ts","../../src/datetime/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$debounce.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/primitives/$throttle.ts","../../src/datetime/primitives/$timeout.ts","../../src/datetime/index.ts"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/primitives/$debounce.ts","../../src/datetime/primitives/$throttle.ts","../../src/datetime/primitives/$timeout.ts","../../src/datetime/index.ts"],"sourcesContent":["import \"dayjs/plugin/relativeTime.js\";\nimport \"dayjs/plugin/duration.js\";\nimport \"dayjs/plugin/utc.js\";\nimport \"dayjs/plugin/timezone.js\";\nimport \"dayjs/plugin/localizedFormat.js\";\nimport \"dayjs/locale/ar.js\";\nimport \"dayjs/locale/fr.js\";\nimport { $hook, $inject, Alepha } from \"alepha\";\nimport DayjsApi, {\n type Dayjs,\n type ManipulateType,\n type OpUnitType,\n type PluginFunc,\n type QUnitType,\n} from \"dayjs\";\nimport dayjsDuration, { type DurationUnitType } from \"dayjs/plugin/duration.js\";\nimport dayjsLocalizedFormat from \"dayjs/plugin/localizedFormat.js\";\nimport dayjsRelativeTime from \"dayjs/plugin/relativeTime.js\";\nimport dayjsTimezone from \"dayjs/plugin/timezone.js\";\nimport dayjsUtc from \"dayjs/plugin/utc.js\";\n\nexport type { DurationUnitType, ManipulateType, OpUnitType, QUnitType };\n\nexport type DateTimeInput = string | number | Date | DateTime | Dayjs;\n\nexport type DurationLike = number | Duration | [number, ManipulateType];\n\n/**\n * Immutable wrapper around the underlying date-time engine.\n *\n * Designed to isolate consumers from the engine in use (currently dayjs).\n * Methods that produce a new value return a new `DateTime` instance.\n */\nexport class DateTime {\n protected readonly inner: Dayjs;\n\n constructor(inner: Dayjs) {\n this.inner = inner;\n }\n\n /**\n * Add a duration to this date-time.\n */\n add(amount: number, unit?: ManipulateType): DateTime;\n add(duration: Duration): DateTime;\n add(amount: number | Duration, unit?: ManipulateType): DateTime {\n if (amount instanceof Duration) {\n return new DateTime(this.inner.add(amount.toDayjs()));\n }\n return new DateTime(this.inner.add(amount, unit));\n }\n\n /**\n * Subtract a duration from this date-time.\n */\n subtract(amount: number, unit?: ManipulateType): DateTime;\n subtract(duration: Duration): DateTime;\n subtract(amount: number | Duration, unit?: ManipulateType): DateTime {\n if (amount instanceof Duration) {\n return new DateTime(this.inner.subtract(amount.toDayjs()));\n }\n return new DateTime(this.inner.subtract(amount, unit));\n }\n\n startOf(unit: OpUnitType): DateTime {\n return new DateTime(this.inner.startOf(unit));\n }\n\n endOf(unit: OpUnitType): DateTime {\n return new DateTime(this.inner.endOf(unit));\n }\n\n isAfter(other: DateTimeInput): boolean {\n return this.inner.isAfter(toDayjs(other));\n }\n\n isBefore(other: DateTimeInput): boolean {\n return this.inner.isBefore(toDayjs(other));\n }\n\n isSame(other: DateTimeInput, unit?: OpUnitType): boolean {\n return this.inner.isSame(toDayjs(other), unit);\n }\n\n diff(other: DateTimeInput, unit?: QUnitType | OpUnitType): number {\n return this.inner.diff(toDayjs(other), unit);\n }\n\n tz(timezone: string): DateTime {\n return new DateTime(this.inner.tz(timezone));\n }\n\n locale(lang: string): DateTime {\n return new DateTime(this.inner.locale(lang));\n }\n\n format(template?: string): string {\n return this.inner.format(template);\n }\n\n fromNow(withoutSuffix?: boolean): string {\n return this.inner.fromNow(withoutSuffix);\n }\n\n toISOString(): string {\n return this.inner.toISOString();\n }\n\n toDate(): Date {\n return this.inner.toDate();\n }\n\n valueOf(): number {\n return this.inner.valueOf();\n }\n\n unix(): number {\n return this.inner.unix();\n }\n\n toJSON(): string {\n return this.inner.toISOString();\n }\n\n toString(): string {\n return this.inner.toISOString();\n }\n\n /**\n * Escape hatch for the underlying dayjs instance.\n *\n * Use sparingly — anything calling this becomes coupled to dayjs and\n * will need to migrate when the engine is replaced.\n */\n toDayjs(): Dayjs {\n return this.inner;\n }\n}\n\n/**\n * Immutable wrapper around the underlying duration engine.\n */\nexport class Duration {\n protected readonly inner: dayjsDuration.Duration;\n\n constructor(inner: dayjsDuration.Duration) {\n this.inner = inner;\n }\n\n asMilliseconds(): number {\n return this.inner.asMilliseconds();\n }\n\n asSeconds(): number {\n return this.inner.asSeconds();\n }\n\n asMinutes(): number {\n return this.inner.asMinutes();\n }\n\n asHours(): number {\n return this.inner.asHours();\n }\n\n asDays(): number {\n return this.inner.asDays();\n }\n\n as(unit: DurationUnitType): number {\n return this.inner.as(unit);\n }\n\n toISOString(): string {\n return this.inner.toISOString();\n }\n\n /**\n * Escape hatch for the underlying dayjs duration.\n */\n toDayjs(): dayjsDuration.Duration {\n return this.inner;\n }\n}\n\nexport const isDateTime = (value: unknown): value is DateTime => {\n return value instanceof DateTime;\n};\n\nconst toDayjs = (value: DateTimeInput): Dayjs => {\n if (value instanceof DateTime) {\n return value.toDayjs();\n }\n return DayjsApi(value as any);\n};\n\nexport class DateTimeProvider {\n public static PLUGINS: Array<PluginFunc<any>> = [\n dayjsDuration,\n dayjsRelativeTime,\n dayjsUtc,\n dayjsTimezone,\n dayjsLocalizedFormat,\n ];\n\n protected alepha = $inject(Alepha);\n protected ref: DateTime | null = null;\n protected readonly timeouts: Timeout[] = [];\n protected readonly intervals: Interval[] = [];\n\n constructor() {\n for (const plugin of DateTimeProvider.PLUGINS) {\n DayjsApi.extend(plugin);\n }\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n // we start intervals now but first tick will be rejected as App is not ready yet\n await Promise.all(\n this.intervals.map(async (interval) => {\n if (interval.timer != null) {\n return;\n }\n await interval.run();\n interval.timer = setInterval(interval.run, interval.duration);\n }),\n );\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: () => {\n for (const timeout of [...this.timeouts]) {\n this.clearTimeout(timeout);\n }\n\n for (const interval of this.intervals) {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n },\n });\n\n public setLocale(locale: string): void {\n DayjsApi.locale(locale);\n }\n\n public isDateTime(value: unknown): value is DateTime {\n return value instanceof DateTime;\n }\n\n /**\n * Create a new UTC DateTime instance.\n */\n public utc(date: DateTimeInput | null | undefined): DateTime {\n return new DateTime(DayjsApi.utc(unwrap(date)));\n }\n\n /**\n * Create a new DateTime instance.\n */\n public of(date: DateTimeInput | null | undefined): DateTime {\n if (date instanceof DateTime) {\n return date;\n }\n return new DateTime(DayjsApi(date as any));\n }\n\n /**\n * Get the current date as a string.\n */\n public toISOString(date: DateTimeInput = this.now()): string {\n return this.of(date).toISOString();\n }\n\n /**\n * Get the current date.\n */\n public now(): DateTime {\n return this.getCurrentDate();\n }\n\n /**\n * Get the current date as a string.\n *\n * This is much faster than `DateTimeProvider.now().toISOString()` as it avoids creating a DateTime instance.\n */\n public nowISOString(): string {\n if (this.ref) {\n return this.ref.toISOString();\n }\n return new Date().toISOString();\n }\n\n /**\n * Get the current date as milliseconds since epoch.\n *\n * This is much faster than `DateTimeProvider.now().valueOf()` as it avoids creating a DateTime instance.\n */\n public nowMillis(): number {\n if (this.ref) {\n return this.ref.valueOf();\n }\n return Date.now();\n }\n\n /**\n * Get the current date as a string.\n *\n * @protected\n */\n protected getCurrentDate(): DateTime {\n if (this.ref) {\n return this.ref;\n }\n\n return new DateTime(DayjsApi());\n }\n\n /**\n * Create a new Duration instance.\n */\n public duration = (\n duration: DurationLike,\n unit?: ManipulateType,\n ): Duration => {\n if (duration instanceof Duration) {\n return duration;\n }\n\n if (Array.isArray(duration)) {\n return new Duration(DayjsApi.duration(duration[0], duration[1]));\n }\n\n if (typeof duration === \"number\") {\n return new Duration(DayjsApi.duration(duration, unit || \"milliseconds\"));\n }\n\n return duration;\n };\n\n public isDurationLike(value: unknown): value is DurationLike {\n try {\n return DayjsApi.isDuration(\n this.duration(value as DurationLike).toDayjs(),\n );\n } catch {\n return false;\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Timer Management\n\n /**\n * Return a promise that resolves after the next tick.\n * It uses `setTimeout` with 0 ms delay.\n */\n public async tick(): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n\n /**\n * Wait for a certain duration.\n *\n * You can clear the timeout by using the `AbortSignal` API.\n * Aborted signal will resolve the promise immediately, it does not reject it.\n */\n public wait(\n duration: DurationLike,\n options: {\n signal?: AbortSignal;\n now?: number;\n } = {},\n ): Promise<void> {\n return new Promise((resolve) => {\n let clearTimeout: any;\n let callback: any;\n\n const timeout = this.createTimeout(\n () => {\n if (options.signal && clearTimeout) {\n options.signal.removeEventListener(\"abort\", callback);\n }\n resolve();\n },\n duration,\n options.now,\n );\n\n if (options.signal) {\n clearTimeout = () => this.clearTimeout(timeout);\n callback = () => {\n clearTimeout();\n resolve();\n };\n options.signal.addEventListener(\"abort\", callback);\n }\n });\n }\n\n public createInterval(\n run: () => unknown,\n duration: DurationLike,\n start = false,\n ): Interval {\n const interval: Interval = {\n run,\n duration: this.duration(duration).asMilliseconds(),\n };\n\n this.intervals.push(interval);\n\n if (start) {\n interval.timer = setInterval(interval.run, interval.duration);\n }\n\n return interval;\n }\n\n /**\n * Run a callback after a certain duration.\n */\n public createTimeout(\n callback: () => void,\n duration: DurationLike,\n now?: number,\n ): Timeout {\n if (this.ref && now) {\n const next = this.of(now).add(this.duration(duration));\n if (next.valueOf() < this.now().valueOf()) {\n callback();\n }\n return {\n now,\n duration: 0,\n callback: () => {},\n clear: () => {},\n };\n }\n\n const timeout: Timeout = {\n now: now ?? this.now().valueOf(),\n duration: this.duration(duration).asMilliseconds(),\n callback,\n clear: () => this.clearTimeout(timeout),\n };\n\n timeout.timer = setTimeout(() => {\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n timeout.callback();\n }, timeout.duration);\n\n this.timeouts.push(timeout);\n\n return timeout;\n }\n\n public clearTimeout(timeout: Timeout): void {\n clearTimeout(timeout.timer);\n timeout.duration = 0;\n timeout.timer = null;\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n }\n\n public clearInterval(interval: Interval): void {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n\n /**\n * Run a function with a deadline.\n */\n public async deadline<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n duration: DurationLike,\n ): Promise<T> {\n const abort = new AbortController();\n const timeout = this.createTimeout(() => abort.abort(), duration);\n try {\n return await fn(abort.signal);\n } finally {\n this.clearTimeout(timeout);\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Testing\n\n /**\n * Add time to the current date.\n */\n public async travel(\n duration: DurationLike,\n unit?: ManipulateType,\n ): Promise<void> {\n this.ref = this.ref || this.now();\n const ms = this.duration(duration, unit).asMilliseconds();\n const now = this.nowMillis();\n this.ref = this.ref.add(this.duration(duration, unit));\n\n for (const timeout of [...this.timeouts]) {\n if (!timeout.timer) {\n continue;\n }\n\n clearTimeout(timeout.timer);\n timeout.timer = null;\n\n const spent = now - timeout.now;\n timeout.duration = timeout.duration - spent - ms;\n\n if (timeout.duration <= 0) {\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n timeout.callback();\n } else {\n timeout.timer = setTimeout(() => {\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n timeout.callback();\n }, timeout.duration);\n }\n }\n\n for (const interval of this.intervals) {\n if (!interval.timer) {\n continue;\n }\n\n clearInterval(interval.timer);\n\n const repeat = Math.floor(ms / interval.duration);\n for (let i = 0; i < repeat; i++) {\n await interval.run();\n }\n\n // Keep intervals suspended — they only fire during travel() calls\n interval.timer = null;\n }\n\n await this.tick();\n }\n\n /**\n * Stop the time.\n */\n public pause(): DateTime {\n this.ref = this.ref || this.now();\n return this.ref;\n }\n\n /**\n * Reset the reference date.\n */\n public reset(): void {\n this.ref = null;\n }\n}\n\nconst unwrap = (value: DateTimeInput | null | undefined): any => {\n if (value instanceof DateTime) {\n return value.toDayjs();\n }\n return value;\n};\n\nexport interface Interval {\n timer?: any;\n duration: number;\n run: () => unknown;\n}\n\nexport interface Timeout {\n now: number;\n timer?: any;\n duration: number;\n callback: () => void;\n clear: () => void;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\n/**\n * Run a function periodically.\n * It uses the `setInterval` internally.\n * It starts by default when the context starts and stops when the context stops.\n */\nexport const $interval = (options: IntervalPrimitiveOptions) =>\n createPrimitive(IntervalPrimitive, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface IntervalPrimitiveOptions {\n /**\n * The interval handler.\n */\n handler: () => unknown;\n\n /**\n * The interval duration.\n */\n duration: DurationLike;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class IntervalPrimitive extends Primitive<IntervalPrimitiveOptions> {\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n public called = 0;\n\n protected onInit() {\n this.dateTimeProvider.createInterval(async () => {\n await this.options.handler();\n this.called += 1;\n }, this.options.duration);\n }\n}\n\n$interval[KIND] = IntervalPrimitive;\n","import { createMiddleware, type Middleware } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\nexport interface DebounceOptions {\n /**\n * Coalescing window. Concurrent calls within this window share one execution.\n */\n delay: DurationLike;\n\n /**\n * Key function to group calls. Calls with the same key are coalesced.\n * Defaults to `JSON.stringify(args)`.\n */\n key?: (...args: any[]) => string;\n}\n\n/**\n * Middleware that coalesces concurrent calls with the same key into a single handler execution.\n *\n * All callers within the delay window receive the same result. No storage —\n * once the handler finishes, the next call starts fresh. Process-local.\n *\n * **Use case**: thundering herd protection — cache expires, 100 requests\n * hit the same endpoint, debounce ensures one rebuild.\n *\n * ```typescript\n * class SearchController {\n * search = $action({\n * use: [$debounce({ delay: [200, \"ms\"], key: (req) => req.query.q })],\n * handler: async ({ query }) => this.searchService.search(query.q),\n * });\n * }\n * ```\n */\nexport const $debounce = (options: DebounceOptions): Middleware => {\n return createMiddleware({\n name: \"$debounce\",\n options: options as unknown as Record<string, unknown>,\n handler: ({ alepha, next }) => {\n const dateTimeProvider = alepha.inject(DateTimeProvider);\n const pending = new Map<string, Promise<any>>();\n\n return async (...args) => {\n const key = options.key?.(...args) ?? JSON.stringify(args);\n\n const existing = pending.get(key);\n if (existing) {\n return existing;\n }\n\n let resolve: (value: any) => void;\n let reject: (error: any) => void;\n const promise = new Promise<any>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n dateTimeProvider.createTimeout(async () => {\n try {\n const result = await next(...args);\n resolve!(result);\n } catch (error) {\n reject!(error);\n } finally {\n pending.delete(key);\n }\n }, options.delay);\n\n pending.set(key, promise);\n return promise;\n };\n },\n });\n};\n","import { createMiddleware, type Middleware } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\nexport interface ThrottleOptions {\n /**\n * Max calls per window.\n */\n rate: number;\n\n /**\n * Window duration.\n */\n per: DurationLike;\n}\n\n/**\n * Middleware that rate-controls handler execution using a token bucket.\n *\n * Excess calls are **delayed** until capacity is available — never rejected.\n * Process-local (not distributed). Use `$rateLimit` for distributed rate limiting.\n *\n * **Use case**: protect an external API from your own traffic.\n *\n * ```typescript\n * class PaymentController {\n * charge = $action({\n * use: [$throttle({ rate: 80, per: [1, \"second\"] })],\n * handler: async ({ body }) => this.stripe.charges.create(body),\n * });\n * }\n * ```\n */\nexport const $throttle = (options: ThrottleOptions): Middleware => {\n return createMiddleware({\n name: \"$throttle\",\n options: options as unknown as Record<string, unknown>,\n handler: ({ alepha, next }) => {\n const dateTimeProvider = alepha.inject(DateTimeProvider);\n const intervalMs = dateTimeProvider\n .duration(options.per)\n .asMilliseconds();\n\n let tokens = options.rate;\n let lastRefill = dateTimeProvider.nowMillis();\n\n return async (...args) => {\n const now = dateTimeProvider.nowMillis();\n const elapsed = now - lastRefill;\n const refill = Math.floor(elapsed / intervalMs) * options.rate;\n\n if (refill > 0) {\n tokens = Math.min(options.rate, tokens + refill);\n lastRefill += Math.floor(elapsed / intervalMs) * intervalMs;\n }\n\n if (tokens <= 0) {\n const waitMs = intervalMs - (now - lastRefill);\n await dateTimeProvider.wait(waitMs);\n tokens = options.rate;\n lastRefill = dateTimeProvider.nowMillis();\n }\n\n tokens--;\n return next(...args);\n };\n },\n });\n};\n","import { AlephaError, createMiddleware, type Middleware } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\n/**\n * Middleware that aborts handler execution if it exceeds a duration limit.\n *\n * Uses `Promise.race` with a managed timeout from `DateTimeProvider` —\n * if the handler doesn't resolve before the deadline, the promise rejects.\n * Uses managed timeouts so it works with `DateTimeProvider.travel()` in tests.\n *\n * ```typescript\n * class OrderService {\n * processOrder = $pipeline({\n * use: [$timeout([30, \"seconds\"])],\n * handler: async (orderId: string) => {\n * return await this.orders.updateById(orderId, { status: \"paid\" });\n * },\n * });\n * }\n * ```\n */\nexport const $timeout = (duration: DurationLike): Middleware => {\n return createMiddleware({\n name: \"$timeout\",\n options: { duration },\n handler: ({ alepha, next }) => {\n const dateTimeProvider = alepha.inject(DateTimeProvider);\n\n return async (...args) => {\n let rejectTimeout: (reason: Error) => void;\n const timeoutPromise = new Promise<never>((_, reject) => {\n rejectTimeout = reject;\n });\n\n const timer = dateTimeProvider.createTimeout(() => {\n rejectTimeout(new AlephaError(\"$timeout: handler exceeded deadline\"));\n }, duration);\n\n try {\n return await Promise.race([next(...args), timeoutPromise]);\n } finally {\n dateTimeProvider.clearTimeout(timer);\n }\n };\n },\n });\n};\n","import { $module } from \"alepha\";\nimport { $interval } from \"./primitives/$interval.ts\";\nimport { DateTimeProvider } from \"./providers/DateTimeProvider.ts\";\n\nexport * from \"./primitives/$debounce.ts\";\nexport * from \"./primitives/$interval.ts\";\nexport * from \"./primitives/$throttle.ts\";\nexport * from \"./primitives/$timeout.ts\";\nexport * from \"./providers/DateTimeProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Date and time operations.\n *\n * **Features:**\n * - Recurring interval definitions\n * - Duration parsing (ISO 8601, human-readable)\n * - Timezone support\n * - Dayjs integration\n *\n * @module alepha.datetime\n */\nexport const AlephaDateTime = $module({\n name: \"alepha.datetime\",\n primitives: [$interval],\n services: [DateTimeProvider],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/primitives/$debounce.ts","../../src/datetime/primitives/$throttle.ts","../../src/datetime/primitives/$timeout.ts","../../src/datetime/index.ts"],"sourcesContent":["import \"dayjs/plugin/relativeTime.js\";\nimport \"dayjs/plugin/duration.js\";\nimport \"dayjs/plugin/utc.js\";\nimport \"dayjs/plugin/timezone.js\";\nimport \"dayjs/plugin/localizedFormat.js\";\nimport \"dayjs/locale/ar.js\";\nimport \"dayjs/locale/fr.js\";\nimport { $hook, $inject, Alepha } from \"alepha\";\nimport DayjsApi, {\n type Dayjs,\n type ManipulateType,\n type OpUnitType,\n type PluginFunc,\n type QUnitType,\n} from \"dayjs\";\nimport dayjsDuration, { type DurationUnitType } from \"dayjs/plugin/duration.js\";\nimport dayjsLocalizedFormat from \"dayjs/plugin/localizedFormat.js\";\nimport dayjsRelativeTime from \"dayjs/plugin/relativeTime.js\";\nimport dayjsTimezone from \"dayjs/plugin/timezone.js\";\nimport dayjsUtc from \"dayjs/plugin/utc.js\";\n\nexport type { DurationUnitType, ManipulateType, OpUnitType, QUnitType };\n\nexport type DateTimeInput = string | number | Date | DateTime | Dayjs;\n\nexport type DurationLike = number | Duration | [number, ManipulateType];\n\n/**\n * Immutable wrapper around the underlying date-time engine.\n *\n * Designed to isolate consumers from the engine in use (currently dayjs).\n * Methods that produce a new value return a new `DateTime` instance.\n */\nexport class DateTime {\n protected readonly inner: Dayjs;\n\n constructor(inner: Dayjs) {\n this.inner = inner;\n }\n\n /**\n * Add a duration to this date-time.\n */\n add(amount: number, unit?: ManipulateType): DateTime;\n add(duration: Duration): DateTime;\n add(amount: number | Duration, unit?: ManipulateType): DateTime {\n if (amount instanceof Duration) {\n return new DateTime(this.inner.add(amount.toDayjs()));\n }\n return new DateTime(this.inner.add(amount, unit));\n }\n\n /**\n * Subtract a duration from this date-time.\n */\n subtract(amount: number, unit?: ManipulateType): DateTime;\n subtract(duration: Duration): DateTime;\n subtract(amount: number | Duration, unit?: ManipulateType): DateTime {\n if (amount instanceof Duration) {\n return new DateTime(this.inner.subtract(amount.toDayjs()));\n }\n return new DateTime(this.inner.subtract(amount, unit));\n }\n\n startOf(unit: OpUnitType): DateTime {\n return new DateTime(this.inner.startOf(unit));\n }\n\n endOf(unit: OpUnitType): DateTime {\n return new DateTime(this.inner.endOf(unit));\n }\n\n isAfter(other: DateTimeInput): boolean {\n return this.inner.isAfter(toDayjs(other));\n }\n\n isBefore(other: DateTimeInput): boolean {\n return this.inner.isBefore(toDayjs(other));\n }\n\n isSame(other: DateTimeInput, unit?: OpUnitType): boolean {\n return this.inner.isSame(toDayjs(other), unit);\n }\n\n diff(other: DateTimeInput, unit?: QUnitType | OpUnitType): number {\n return this.inner.diff(toDayjs(other), unit);\n }\n\n tz(timezone: string): DateTime {\n return new DateTime(this.inner.tz(timezone));\n }\n\n locale(lang: string): DateTime {\n return new DateTime(this.inner.locale(lang));\n }\n\n format(template?: string): string {\n return this.inner.format(template);\n }\n\n fromNow(withoutSuffix?: boolean): string {\n return this.inner.fromNow(withoutSuffix);\n }\n\n toISOString(): string {\n return this.inner.toISOString();\n }\n\n toDate(): Date {\n return this.inner.toDate();\n }\n\n valueOf(): number {\n return this.inner.valueOf();\n }\n\n unix(): number {\n return this.inner.unix();\n }\n\n toJSON(): string {\n return this.inner.toISOString();\n }\n\n toString(): string {\n return this.inner.toISOString();\n }\n\n /**\n * Escape hatch for the underlying dayjs instance.\n *\n * Use sparingly — anything calling this becomes coupled to dayjs and\n * will need to migrate when the engine is replaced.\n */\n toDayjs(): Dayjs {\n return this.inner;\n }\n}\n\n/**\n * Immutable wrapper around the underlying duration engine.\n */\nexport class Duration {\n protected readonly inner: dayjsDuration.Duration;\n\n constructor(inner: dayjsDuration.Duration) {\n this.inner = inner;\n }\n\n asMilliseconds(): number {\n return this.inner.asMilliseconds();\n }\n\n asSeconds(): number {\n return this.inner.asSeconds();\n }\n\n asMinutes(): number {\n return this.inner.asMinutes();\n }\n\n asHours(): number {\n return this.inner.asHours();\n }\n\n asDays(): number {\n return this.inner.asDays();\n }\n\n as(unit: DurationUnitType): number {\n return this.inner.as(unit);\n }\n\n toISOString(): string {\n return this.inner.toISOString();\n }\n\n /**\n * Escape hatch for the underlying dayjs duration.\n */\n toDayjs(): dayjsDuration.Duration {\n return this.inner;\n }\n}\n\nexport const isDateTime = (value: unknown): value is DateTime => {\n return value instanceof DateTime;\n};\n\nconst toDayjs = (value: DateTimeInput): Dayjs => {\n if (value instanceof DateTime) {\n return value.toDayjs();\n }\n return DayjsApi(value as any);\n};\n\nexport class DateTimeProvider {\n public static PLUGINS: Array<PluginFunc<any>> = [\n dayjsDuration,\n dayjsRelativeTime,\n dayjsUtc,\n dayjsTimezone,\n dayjsLocalizedFormat,\n ];\n\n protected alepha = $inject(Alepha);\n protected ref: DateTime | null = null;\n protected readonly timeouts: Timeout[] = [];\n protected readonly intervals: Interval[] = [];\n\n constructor() {\n for (const plugin of DateTimeProvider.PLUGINS) {\n DayjsApi.extend(plugin);\n }\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n // we start intervals now but first tick will be rejected as App is not ready yet\n await Promise.all(\n this.intervals.map(async (interval) => {\n if (interval.timer != null) {\n return;\n }\n await interval.run();\n interval.timer = setInterval(interval.run, interval.duration);\n }),\n );\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: () => {\n for (const timeout of [...this.timeouts]) {\n this.clearTimeout(timeout);\n }\n\n for (const interval of this.intervals) {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n },\n });\n\n public setLocale(locale: string): void {\n DayjsApi.locale(locale);\n }\n\n public isDateTime(value: unknown): value is DateTime {\n return value instanceof DateTime;\n }\n\n /**\n * Create a new UTC DateTime instance.\n */\n public utc(date: DateTimeInput | null | undefined): DateTime {\n return new DateTime(DayjsApi.utc(unwrap(date)));\n }\n\n /**\n * Create a new DateTime instance.\n */\n public of(date: DateTimeInput | null | undefined): DateTime {\n if (date instanceof DateTime) {\n return date;\n }\n return new DateTime(DayjsApi(date as any));\n }\n\n /**\n * Get the current date as a string.\n */\n public toISOString(date: DateTimeInput = this.now()): string {\n return this.of(date).toISOString();\n }\n\n /**\n * Get the current date.\n */\n public now(): DateTime {\n return this.getCurrentDate();\n }\n\n /**\n * Get the current date as a string.\n *\n * This is much faster than `DateTimeProvider.now().toISOString()` as it avoids creating a DateTime instance.\n */\n public nowISOString(): string {\n if (this.ref) {\n return this.ref.toISOString();\n }\n return new Date().toISOString();\n }\n\n /**\n * Get the current date as milliseconds since epoch.\n *\n * This is much faster than `DateTimeProvider.now().valueOf()` as it avoids creating a DateTime instance.\n */\n public nowMillis(): number {\n if (this.ref) {\n return this.ref.valueOf();\n }\n return Date.now();\n }\n\n /**\n * Get the current date as a string.\n *\n * @protected\n */\n protected getCurrentDate(): DateTime {\n if (this.ref) {\n return this.ref;\n }\n\n return new DateTime(DayjsApi());\n }\n\n /**\n * Create a new Duration instance.\n */\n public duration = (\n duration: DurationLike,\n unit?: ManipulateType,\n ): Duration => {\n if (duration instanceof Duration) {\n return duration;\n }\n\n if (Array.isArray(duration)) {\n return new Duration(DayjsApi.duration(duration[0], duration[1]));\n }\n\n if (typeof duration === \"number\") {\n return new Duration(DayjsApi.duration(duration, unit || \"milliseconds\"));\n }\n\n return duration;\n };\n\n public isDurationLike(value: unknown): value is DurationLike {\n try {\n return DayjsApi.isDuration(\n this.duration(value as DurationLike).toDayjs(),\n );\n } catch {\n return false;\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Timer Management\n\n /**\n * Return a promise that resolves after the next tick.\n * It uses `setTimeout` with 0 ms delay.\n */\n public async tick(): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n\n /**\n * Wait for a certain duration.\n *\n * You can clear the timeout by using the `AbortSignal` API.\n * Aborted signal will resolve the promise immediately, it does not reject it.\n */\n public wait(\n duration: DurationLike,\n options: {\n signal?: AbortSignal;\n now?: number;\n } = {},\n ): Promise<void> {\n return new Promise((resolve) => {\n let clearTimeout: any;\n let callback: any;\n\n const timeout = this.createTimeout(\n () => {\n if (options.signal && clearTimeout) {\n options.signal.removeEventListener(\"abort\", callback);\n }\n resolve();\n },\n duration,\n options.now,\n );\n\n if (options.signal) {\n clearTimeout = () => this.clearTimeout(timeout);\n callback = () => {\n clearTimeout();\n resolve();\n };\n options.signal.addEventListener(\"abort\", callback);\n }\n });\n }\n\n public createInterval(\n run: () => unknown,\n duration: DurationLike,\n start = false,\n ): Interval {\n const interval: Interval = {\n run,\n duration: this.duration(duration).asMilliseconds(),\n };\n\n this.intervals.push(interval);\n\n if (start) {\n interval.timer = setInterval(interval.run, interval.duration);\n }\n\n return interval;\n }\n\n /**\n * Run a callback after a certain duration.\n */\n public createTimeout(\n callback: () => void,\n duration: DurationLike,\n now?: number,\n ): Timeout {\n if (this.ref && now) {\n const next = this.of(now).add(this.duration(duration));\n if (next.valueOf() < this.now().valueOf()) {\n callback();\n }\n return {\n now,\n duration: 0,\n callback: () => {},\n clear: () => {},\n };\n }\n\n const timeout: Timeout = {\n now: now ?? this.now().valueOf(),\n duration: this.duration(duration).asMilliseconds(),\n callback,\n clear: () => this.clearTimeout(timeout),\n };\n\n timeout.timer = setTimeout(() => {\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n timeout.callback();\n }, timeout.duration);\n\n this.timeouts.push(timeout);\n\n return timeout;\n }\n\n public clearTimeout(timeout: Timeout): void {\n clearTimeout(timeout.timer);\n timeout.duration = 0;\n timeout.timer = null;\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n }\n\n public clearInterval(interval: Interval): void {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n\n /**\n * Run a function with a deadline.\n */\n public async deadline<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n duration: DurationLike,\n ): Promise<T> {\n const abort = new AbortController();\n const timeout = this.createTimeout(() => abort.abort(), duration);\n try {\n return await fn(abort.signal);\n } finally {\n this.clearTimeout(timeout);\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Testing\n\n /**\n * Add time to the current date.\n */\n public async travel(\n duration: DurationLike,\n unit?: ManipulateType,\n ): Promise<void> {\n this.ref = this.ref || this.now();\n const ms = this.duration(duration, unit).asMilliseconds();\n const now = this.nowMillis();\n this.ref = this.ref.add(this.duration(duration, unit));\n\n for (const timeout of [...this.timeouts]) {\n if (!timeout.timer) {\n continue;\n }\n\n clearTimeout(timeout.timer);\n timeout.timer = null;\n\n const spent = now - timeout.now;\n timeout.duration = timeout.duration - spent - ms;\n\n if (timeout.duration <= 0) {\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n timeout.callback();\n } else {\n timeout.timer = setTimeout(() => {\n const index = this.timeouts.indexOf(timeout);\n if (index !== -1) {\n this.timeouts.splice(index, 1);\n }\n timeout.callback();\n }, timeout.duration);\n }\n }\n\n for (const interval of this.intervals) {\n if (!interval.timer) {\n continue;\n }\n\n clearInterval(interval.timer);\n\n const repeat = Math.floor(ms / interval.duration);\n for (let i = 0; i < repeat; i++) {\n await interval.run();\n }\n\n // Keep intervals suspended — they only fire during travel() calls\n interval.timer = null;\n }\n\n await this.tick();\n }\n\n /**\n * Stop the time.\n */\n public pause(): DateTime {\n this.ref = this.ref || this.now();\n return this.ref;\n }\n\n /**\n * Reset the reference date.\n */\n public reset(): void {\n this.ref = null;\n }\n}\n\nconst unwrap = (value: DateTimeInput | null | undefined): any => {\n if (value instanceof DateTime) {\n return value.toDayjs();\n }\n return value;\n};\n\nexport interface Interval {\n timer?: any;\n duration: number;\n run: () => unknown;\n}\n\nexport interface Timeout {\n now: number;\n timer?: any;\n duration: number;\n callback: () => void;\n clear: () => void;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\n/**\n * Run a function periodically.\n * It uses the `setInterval` internally.\n * It starts by default when the context starts and stops when the context stops.\n */\nexport const $interval = (options: IntervalPrimitiveOptions) =>\n createPrimitive(IntervalPrimitive, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface IntervalPrimitiveOptions {\n /**\n * The interval handler.\n */\n handler: () => unknown;\n\n /**\n * The interval duration.\n */\n duration: DurationLike;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class IntervalPrimitive extends Primitive<IntervalPrimitiveOptions> {\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n public called = 0;\n\n protected onInit() {\n this.dateTimeProvider.createInterval(async () => {\n await this.options.handler();\n this.called += 1;\n }, this.options.duration);\n }\n}\n\n$interval[KIND] = IntervalPrimitive;\n","import { createMiddleware, type Middleware } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\nexport interface DebounceOptions {\n /**\n * Coalescing window. Concurrent calls within this window share one execution.\n */\n delay: DurationLike;\n\n /**\n * Key function to group calls. Calls with the same key are coalesced.\n * Defaults to `JSON.stringify(args)`.\n */\n key?: (...args: any[]) => string;\n}\n\n/**\n * Middleware that coalesces concurrent calls with the same key into a single handler execution.\n *\n * All callers within the delay window receive the same result. No storage —\n * once the handler finishes, the next call starts fresh. Process-local.\n *\n * **Use case**: thundering herd protection — cache expires, 100 requests\n * hit the same endpoint, debounce ensures one rebuild.\n *\n * ```typescript\n * class SearchController {\n * search = $action({\n * use: [$debounce({ delay: [200, \"ms\"], key: (req) => req.query.q })],\n * handler: async ({ query }) => this.searchService.search(query.q),\n * });\n * }\n * ```\n */\nexport const $debounce = (options: DebounceOptions): Middleware => {\n return createMiddleware({\n name: \"$debounce\",\n options: options as unknown as Record<string, unknown>,\n handler: ({ alepha, next }) => {\n const dateTimeProvider = alepha.inject(DateTimeProvider);\n const pending = new Map<string, Promise<any>>();\n\n return async (...args) => {\n const key = options.key?.(...args) ?? JSON.stringify(args);\n\n const existing = pending.get(key);\n if (existing) {\n return existing;\n }\n\n let resolve: (value: any) => void;\n let reject: (error: any) => void;\n const promise = new Promise<any>((res, rej) => {\n resolve = res;\n reject = rej;\n });\n\n dateTimeProvider.createTimeout(async () => {\n try {\n const result = await next(...args);\n resolve!(result);\n } catch (error) {\n reject!(error);\n } finally {\n pending.delete(key);\n }\n }, options.delay);\n\n pending.set(key, promise);\n return promise;\n };\n },\n });\n};\n","import { createMiddleware, type Middleware } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\nexport interface ThrottleOptions {\n /**\n * Max calls per window.\n */\n rate: number;\n\n /**\n * Window duration.\n */\n per: DurationLike;\n}\n\n/**\n * Middleware that rate-controls handler execution using a token bucket.\n *\n * Excess calls are **delayed** until capacity is available — never rejected.\n * Process-local (not distributed). Use `$rateLimit` for distributed rate limiting.\n *\n * **Use case**: protect an external API from your own traffic.\n *\n * ```typescript\n * class PaymentController {\n * charge = $action({\n * use: [$throttle({ rate: 80, per: [1, \"second\"] })],\n * handler: async ({ body }) => this.stripe.charges.create(body),\n * });\n * }\n * ```\n */\nexport const $throttle = (options: ThrottleOptions): Middleware => {\n return createMiddleware({\n name: \"$throttle\",\n options: options as unknown as Record<string, unknown>,\n handler: ({ alepha, next }) => {\n const dateTimeProvider = alepha.inject(DateTimeProvider);\n const intervalMs = dateTimeProvider\n .duration(options.per)\n .asMilliseconds();\n\n let tokens = options.rate;\n let lastRefill = dateTimeProvider.nowMillis();\n\n return async (...args) => {\n const now = dateTimeProvider.nowMillis();\n const elapsed = now - lastRefill;\n const refill = Math.floor(elapsed / intervalMs) * options.rate;\n\n if (refill > 0) {\n tokens = Math.min(options.rate, tokens + refill);\n lastRefill += Math.floor(elapsed / intervalMs) * intervalMs;\n }\n\n if (tokens <= 0) {\n const waitMs = intervalMs - (now - lastRefill);\n await dateTimeProvider.wait(waitMs);\n tokens = options.rate;\n lastRefill = dateTimeProvider.nowMillis();\n }\n\n tokens--;\n return next(...args);\n };\n },\n });\n};\n","import { AlephaError, createMiddleware, type Middleware } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\n/**\n * Middleware that aborts handler execution if it exceeds a duration limit.\n *\n * Uses `Promise.race` with a managed timeout from `DateTimeProvider` —\n * if the handler doesn't resolve before the deadline, the promise rejects.\n * Uses managed timeouts so it works with `DateTimeProvider.travel()` in tests.\n *\n * ```typescript\n * class OrderService {\n * processOrder = $pipeline({\n * use: [$timeout([30, \"seconds\"])],\n * handler: async (orderId: string) => {\n * return await this.orders.updateById(orderId, { status: \"paid\" });\n * },\n * });\n * }\n * ```\n */\nexport const $timeout = (duration: DurationLike): Middleware => {\n return createMiddleware({\n name: \"$timeout\",\n options: { duration },\n handler: ({ alepha, next }) => {\n const dateTimeProvider = alepha.inject(DateTimeProvider);\n\n return async (...args) => {\n let rejectTimeout: (reason: Error) => void;\n const timeoutPromise = new Promise<never>((_, reject) => {\n rejectTimeout = reject;\n });\n\n const timer = dateTimeProvider.createTimeout(() => {\n rejectTimeout(new AlephaError(\"$timeout: handler exceeded deadline\"));\n }, duration);\n\n try {\n return await Promise.race([next(...args), timeoutPromise]);\n } finally {\n dateTimeProvider.clearTimeout(timer);\n }\n };\n },\n });\n};\n","import { $module } from \"alepha\";\nimport { $interval } from \"./primitives/$interval.ts\";\nimport { DateTimeProvider } from \"./providers/DateTimeProvider.ts\";\n\nexport * from \"./primitives/$debounce.ts\";\nexport * from \"./primitives/$interval.ts\";\nexport * from \"./primitives/$throttle.ts\";\nexport * from \"./primitives/$timeout.ts\";\nexport * from \"./providers/DateTimeProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Date and time operations.\n *\n * **Features:**\n * - Recurring interval definitions\n * - Duration parsing (ISO 8601, human-readable)\n * - Timezone support\n * - Dayjs integration\n *\n * @module alepha.datetime\n */\nexport const AlephaDateTime = $module({\n name: \"alepha.datetime\",\n primitives: [$interval],\n services: [DateTimeProvider],\n});\n"],"mappings":"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"}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import * as _$alepha from "alepha";
|
|
2
1
|
import { EmailProvider, EmailSendOptions } from "alepha/email";
|
|
3
|
-
import * as _$alepha_logger0 from "alepha/logger";
|
|
4
2
|
|
|
5
3
|
//#region ../../src/email/brevo/providers/BrevoEmailProvider.d.ts
|
|
6
4
|
/**
|
|
@@ -29,7 +27,7 @@ declare class BrevoEmailProvider implements EmailProvider {
|
|
|
29
27
|
BREVO_API_KEY: string;
|
|
30
28
|
EMAIL_FROM: string;
|
|
31
29
|
};
|
|
32
|
-
protected readonly log:
|
|
30
|
+
protected readonly log: import("alepha/logger").Logger;
|
|
33
31
|
send(options: EmailSendOptions): Promise<void>;
|
|
34
32
|
}
|
|
35
33
|
//#endregion
|
|
@@ -40,7 +38,7 @@ declare class BrevoEmailProvider implements EmailProvider {
|
|
|
40
38
|
* @see {@link BrevoEmailProvider}
|
|
41
39
|
* @module alepha.email.brevo
|
|
42
40
|
*/
|
|
43
|
-
declare const AlephaEmailBrevo:
|
|
41
|
+
declare const AlephaEmailBrevo: import("alepha").Service<import("alepha").Module>;
|
|
44
42
|
//#endregion
|
|
45
43
|
export { AlephaEmailBrevo, BrevoEmailProvider };
|
|
46
44
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/email/brevo/providers/BrevoEmailProvider.ts","../../../src/email/brevo/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/email/brevo/providers/BrevoEmailProvider.ts","../../../src/email/brevo/index.ts"],"mappings":";;;;;AAyCA;;;;;;;;;;;;;;;;;;;cAAa,kBAAA,YAA8B,aAAA;EAAA,mBACtB,GAAA;;;;qBACA,GAAA,0BAAG,MAAA;EAET,IAAA,CAAK,OAAA,EAAS,gBAAA,GAAmB,OAAA;AAAA;;;;;AAJhD;;;;cC5Ba,gBAAA,mBAAgB,OAAA,kBAAA,MAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/email/brevo/providers/BrevoEmailProvider.ts","../../../src/email/brevo/index.ts"],"sourcesContent":["import { $env, t } from \"alepha\";\nimport {\n EmailError,\n type EmailProvider,\n type EmailSendOptions,\n} from \"alepha/email\";\nimport { $logger } from \"alepha/logger\";\n\n/**\n * Environment variables for Brevo configuration.\n */\nconst envSchema = t.object({\n BREVO_API_KEY: t.text({\n description: \"Brevo API key for transactional email\",\n }),\n EMAIL_FROM: t.text({\n description: \"Default sender email address\",\n }),\n});\n\n/**\n * Email provider using Brevo (formerly Sendinblue) transactional email API.\n *\n * Sends emails via `POST https://api.brevo.com/v3/smtp/email`.\n *\n * Configuration is provided via environment variables:\n * - `BREVO_API_KEY`: Brevo API key\n * - `EMAIL_FROM`: Default sender email address\n *\n * @example\n * ```typescript\n * // .env\n * // BREVO_API_KEY=xkeysib-xxx\n * // EMAIL_FROM=noreply@example.com\n *\n * // app.ts\n * import { AlephaEmailBrevo } from \"alepha/email/brevo\";\n *\n * const app = Alepha.create().with(AlephaEmailBrevo);\n * ```\n */\nexport class BrevoEmailProvider implements EmailProvider {\n protected readonly env = $env(envSchema);\n protected readonly log = $logger();\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n this.log.info(\"Sending email via Brevo\", { to, subject });\n\n const recipients = Array.isArray(to) ? to : [to];\n\n try {\n const response = await fetch(\"https://api.brevo.com/v3/smtp/email\", {\n method: \"POST\",\n headers: {\n \"api-key\": this.env.BREVO_API_KEY,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n sender: { email: this.env.EMAIL_FROM },\n to: recipients.map((email) => ({ email })),\n subject,\n htmlContent: body,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new EmailError(`Brevo API returned ${response.status}: ${text}`);\n }\n\n this.log.info(\"Email sent successfully via Brevo\", {\n to,\n subject,\n });\n } catch (error) {\n if (error instanceof EmailError) {\n throw error;\n }\n const message = `Failed to send email via Brevo: ${error instanceof Error ? error.message : String(error)}`;\n this.log.error(message, { to, subject });\n throw new EmailError(message, error instanceof Error ? error : undefined);\n }\n }\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { AlephaEmail, EmailProvider } from \"alepha/email\";\nimport { BrevoEmailProvider } from \"./providers/BrevoEmailProvider.ts\";\n\n// Exports\nexport * from \"./providers/BrevoEmailProvider.ts\";\n\n/**\n * Plugin for Alepha Email that provides Brevo transactional email capabilities.\n *\n * @see {@link BrevoEmailProvider}\n * @module alepha.email.brevo\n */\nexport const AlephaEmailBrevo = $module({\n name: \"alepha.email.brevo\",\n services: [BrevoEmailProvider],\n register: (alepha: Alepha) =>\n alepha\n .with({\n optional: true,\n provide: EmailProvider,\n use: BrevoEmailProvider,\n })\n .with(AlephaEmail),\n});\n"],"mappings":";;;;;;;AAWA,MAAM,YAAY,EAAE,OAAO;CACzB,eAAe,EAAE,KAAK,EACpB,aAAa,
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/email/brevo/providers/BrevoEmailProvider.ts","../../../src/email/brevo/index.ts"],"sourcesContent":["import { $env, t } from \"alepha\";\nimport {\n EmailError,\n type EmailProvider,\n type EmailSendOptions,\n} from \"alepha/email\";\nimport { $logger } from \"alepha/logger\";\n\n/**\n * Environment variables for Brevo configuration.\n */\nconst envSchema = t.object({\n BREVO_API_KEY: t.text({\n description: \"Brevo API key for transactional email\",\n }),\n EMAIL_FROM: t.text({\n description: \"Default sender email address\",\n }),\n});\n\n/**\n * Email provider using Brevo (formerly Sendinblue) transactional email API.\n *\n * Sends emails via `POST https://api.brevo.com/v3/smtp/email`.\n *\n * Configuration is provided via environment variables:\n * - `BREVO_API_KEY`: Brevo API key\n * - `EMAIL_FROM`: Default sender email address\n *\n * @example\n * ```typescript\n * // .env\n * // BREVO_API_KEY=xkeysib-xxx\n * // EMAIL_FROM=noreply@example.com\n *\n * // app.ts\n * import { AlephaEmailBrevo } from \"alepha/email/brevo\";\n *\n * const app = Alepha.create().with(AlephaEmailBrevo);\n * ```\n */\nexport class BrevoEmailProvider implements EmailProvider {\n protected readonly env = $env(envSchema);\n protected readonly log = $logger();\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n this.log.info(\"Sending email via Brevo\", { to, subject });\n\n const recipients = Array.isArray(to) ? to : [to];\n\n try {\n const response = await fetch(\"https://api.brevo.com/v3/smtp/email\", {\n method: \"POST\",\n headers: {\n \"api-key\": this.env.BREVO_API_KEY,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: JSON.stringify({\n sender: { email: this.env.EMAIL_FROM },\n to: recipients.map((email) => ({ email })),\n subject,\n htmlContent: body,\n }),\n });\n\n if (!response.ok) {\n const text = await response.text();\n throw new EmailError(`Brevo API returned ${response.status}: ${text}`);\n }\n\n this.log.info(\"Email sent successfully via Brevo\", {\n to,\n subject,\n });\n } catch (error) {\n if (error instanceof EmailError) {\n throw error;\n }\n const message = `Failed to send email via Brevo: ${error instanceof Error ? error.message : String(error)}`;\n this.log.error(message, { to, subject });\n throw new EmailError(message, error instanceof Error ? error : undefined);\n }\n }\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { AlephaEmail, EmailProvider } from \"alepha/email\";\nimport { BrevoEmailProvider } from \"./providers/BrevoEmailProvider.ts\";\n\n// Exports\nexport * from \"./providers/BrevoEmailProvider.ts\";\n\n/**\n * Plugin for Alepha Email that provides Brevo transactional email capabilities.\n *\n * @see {@link BrevoEmailProvider}\n * @module alepha.email.brevo\n */\nexport const AlephaEmailBrevo = $module({\n name: \"alepha.email.brevo\",\n services: [BrevoEmailProvider],\n register: (alepha: Alepha) =>\n alepha\n .with({\n optional: true,\n provide: EmailProvider,\n use: BrevoEmailProvider,\n })\n .with(AlephaEmail),\n});\n"],"mappings":";;;;;;;AAWA,MAAM,YAAY,EAAE,OAAO;CACzB,eAAe,EAAE,KAAK,EACpB,aAAa,wCACf,CAAC;CACD,YAAY,EAAE,KAAK,EACjB,aAAa,+BACf,CAAC;AACH,CAAC;;;;;;;;;;;;;;;;;;;;;;AAuBD,IAAa,qBAAb,MAAyD;CACvD,MAAyB,KAAK,SAAS;CACvC,MAAyB,QAAQ;CAEjC,MAAa,KAAK,SAA0C;EAC1D,MAAM,EAAE,IAAI,SAAS,SAAS;EAC9B,KAAK,IAAI,KAAK,2BAA2B;GAAE;GAAI;EAAQ,CAAC;EAExD,MAAM,aAAa,MAAM,QAAQ,EAAE,IAAI,KAAK,CAAC,EAAE;EAE/C,IAAI;GACF,MAAM,WAAW,MAAM,MAAM,uCAAuC;IAClE,QAAQ;IACR,SAAS;KACP,WAAW,KAAK,IAAI;KACpB,gBAAgB;KAChB,QAAQ;IACV;IACA,MAAM,KAAK,UAAU;KACnB,QAAQ,EAAE,OAAO,KAAK,IAAI,WAAW;KACrC,IAAI,WAAW,KAAK,WAAW,EAAE,MAAM,EAAE;KACzC;KACA,aAAa;IACf,CAAC;GACH,CAAC;GAED,IAAI,CAAC,SAAS,IAAI;IAChB,MAAM,OAAO,MAAM,SAAS,KAAK;IACjC,MAAM,IAAI,WAAW,sBAAsB,SAAS,OAAO,IAAI,MAAM;GACvE;GAEA,KAAK,IAAI,KAAK,qCAAqC;IACjD;IACA;GACF,CAAC;EACH,SAAS,OAAO;GACd,IAAI,iBAAiB,YACnB,MAAM;GAER,MAAM,UAAU,mCAAmC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;GACxG,KAAK,IAAI,MAAM,SAAS;IAAE;IAAI;GAAQ,CAAC;GACvC,MAAM,IAAI,WAAW,SAAS,iBAAiB,QAAQ,QAAQ,KAAA,CAAS;EAC1E;CACF;AACF;;;;;;;;;ACxEA,MAAa,mBAAmB,QAAQ;CACtC,MAAM;CACN,UAAU,CAAC,kBAAkB;CAC7B,WAAW,WACT,OACG,KAAK;EACJ,UAAU;EACV,SAAS;EACT,KAAK;CACP,CAAC,EACA,KAAK,WAAW;AACvB,CAAC"}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import * as _$alepha from "alepha";
|
|
2
1
|
import { Alepha } from "alepha";
|
|
3
2
|
import { EmailProvider, EmailSendOptions } from "alepha/email";
|
|
4
|
-
import * as _$alepha_logger0 from "alepha/logger";
|
|
5
3
|
|
|
6
4
|
//#region ../../src/email/cloudflare/providers/CloudflareEmailProvider.d.ts
|
|
7
5
|
/**
|
|
@@ -22,7 +20,7 @@ interface CloudflareEmailBinding {
|
|
|
22
20
|
interface CloudflareEmailSendMessage {
|
|
23
21
|
to: string | string[];
|
|
24
22
|
from: string | {
|
|
25
|
-
|
|
23
|
+
email: string;
|
|
26
24
|
name?: string;
|
|
27
25
|
};
|
|
28
26
|
subject: string;
|
|
@@ -67,12 +65,27 @@ interface CloudflareEmailSendResult {
|
|
|
67
65
|
declare class CloudflareEmailProvider implements EmailProvider {
|
|
68
66
|
protected readonly alepha: Alepha;
|
|
69
67
|
protected readonly env: {
|
|
70
|
-
EMAIL_FROM
|
|
68
|
+
EMAIL_FROM?: string | undefined;
|
|
71
69
|
};
|
|
72
|
-
protected readonly log:
|
|
70
|
+
protected readonly log: import("alepha/logger").Logger;
|
|
73
71
|
protected binding?: CloudflareEmailBinding;
|
|
74
|
-
protected readonly onStart:
|
|
72
|
+
protected readonly onStart: import("alepha").HookPrimitive<"start">;
|
|
75
73
|
send(options: EmailSendOptions): Promise<void>;
|
|
74
|
+
/**
|
|
75
|
+
* Map the configured `EMAIL_FROM` to Cloudflare's `from` shape. An RFC 5322
|
|
76
|
+
* display-name form — `Name <addr@host>` (the name may be quoted) — is split
|
|
77
|
+
* into `{ email, name }` so Cloudflare renders the sender's display name
|
|
78
|
+
* (e.g. `Lore <noreply@lore.alepha.dev>` → "Lore"). A bare address is passed
|
|
79
|
+
* through unchanged.
|
|
80
|
+
*
|
|
81
|
+
* The object key is `email` (not `address`) — that is the field the
|
|
82
|
+
* Cloudflare Email Service Workers API expects. Sending `{ address, name }`
|
|
83
|
+
* makes the API reject the message with an opaque "internal error".
|
|
84
|
+
*/
|
|
85
|
+
protected resolveFrom(value: string): string | {
|
|
86
|
+
email: string;
|
|
87
|
+
name?: string;
|
|
88
|
+
};
|
|
76
89
|
protected getBinding(): CloudflareEmailBinding;
|
|
77
90
|
}
|
|
78
91
|
//#endregion
|
|
@@ -84,7 +97,7 @@ declare class CloudflareEmailProvider implements EmailProvider {
|
|
|
84
97
|
* @see {@link CloudflareEmailProvider}
|
|
85
98
|
* @module alepha.email.cloudflare
|
|
86
99
|
*/
|
|
87
|
-
declare const AlephaEmailCloudflare:
|
|
100
|
+
declare const AlephaEmailCloudflare: import("alepha").Service<import("alepha").Module>;
|
|
88
101
|
//#endregion
|
|
89
102
|
export { AlephaEmailCloudflare, CloudflareEmailBinding, CloudflareEmailProvider, CloudflareEmailSendMessage, CloudflareEmailSendResult, SEND_EMAIL_DEFAULT_BINDING };
|
|
90
103
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/email/cloudflare/providers/CloudflareEmailProvider.ts","../../../src/email/cloudflare/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/email/cloudflare/providers/CloudflareEmailProvider.ts","../../../src/email/cloudflare/index.ts"],"mappings":";;;;;;AAcA;;;;cAAa,0BAAA;AAyBb;;;;;AAAA,UAAiB,sBAAA;EACf,IAAA,CAAK,OAAA,EAAS,0BAAA,GAA6B,OAAA,CAAQ,yBAAA;AAAA;AAAA,UAGpC,0BAAA;EACf,EAAA;EACA,IAAA;IAAiB,KAAA;IAAe,IAAA;EAAA;EAChC,OAAA;EACA,IAAA;EACA,IAAA;EACA,EAAA;EACA,GAAA;EACA,QAAA;EACA,OAAA,GAAU,MAAM;AAAA;AAAA,UAGD,yBAAA;EACf,EAAA;EACA,MAAM;AAAA;;;;;;;AALU;AAGlB;;;;AAEQ;AA8BR;;;;;;;;;;;;;;;cAAa,uBAAA,YAAmC,aAAA;EAAA,mBAC3B,MAAA,EAAM,MAAA;EAAA,mBACN,GAAA;;;qBACA,GAAA,0BAAG,MAAA;EAAA,UAEZ,OAAA,GAAU,sBAAA;EAAA,mBAED,OAAA,mBAAO,aAAA;EAkCb,IAAA,CAAK,OAAA,EAAS,gBAAA,GAAmB,OAAA;EAA5B;;;;;;;;;AAoE4B;;EApE5B,UAwDR,WAAA,CACR,KAAA;IACY,KAAA;IAAe,IAAA;EAAA;EAAA,UAUnB,UAAA,IAAc,sBAAA;AAAA;;;;;;AAtL1B;;;;cCAa,qBAAA,mBAAqB,OAAA,kBAAA,MAAA"}
|