alepha 0.23.0 → 0.24.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/assets/swagger-ui/swagger-ui-bundle.js +1 -1
- package/assets/swagger-ui/swagger-ui-standalone-preset.js +1 -1
- package/dist/api/audits/index.browser.js +49 -52
- package/dist/api/audits/index.browser.js.map +1 -1
- package/dist/api/audits/index.d.ts +629 -565
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +206 -98
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.browser.js +44 -44
- package/dist/api/files/index.browser.js.map +1 -1
- package/dist/api/files/index.d.ts +292 -293
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +61 -64
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.browser.js +61 -59
- package/dist/api/jobs/index.browser.js.map +1 -1
- package/dist/api/jobs/index.d.ts +546 -347
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +165 -86
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +247 -235
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/keys/index.js +63 -66
- package/dist/api/keys/index.js.map +1 -1
- package/dist/api/notifications/index.browser.js +40 -38
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +339 -209
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +108 -60
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/oauth/index.d.ts +190 -78
- package/dist/api/oauth/index.d.ts.map +1 -1
- package/dist/api/oauth/index.js +290 -68
- package/dist/api/oauth/index.js.map +1 -1
- package/dist/api/organizations/index.browser.js +14 -14
- package/dist/api/organizations/index.browser.js.map +1 -1
- package/dist/api/organizations/index.d.ts +158 -134
- package/dist/api/organizations/index.d.ts.map +1 -1
- package/dist/api/organizations/index.js +18 -18
- package/dist/api/organizations/index.js.map +1 -1
- package/dist/api/parameters/index.browser.js +74 -53
- package/dist/api/parameters/index.browser.js.map +1 -1
- package/dist/api/parameters/index.d.ts +607 -513
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +205 -127
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/payments/index.d.ts +652 -449
- package/dist/api/payments/index.d.ts.map +1 -1
- package/dist/api/payments/index.js +159 -93
- package/dist/api/payments/index.js.map +1 -1
- package/dist/api/subscriptions/index.d.ts +1032 -762
- package/dist/api/subscriptions/index.d.ts.map +1 -1
- package/dist/api/subscriptions/index.js +166 -185
- package/dist/api/subscriptions/index.js.map +1 -1
- package/dist/api/users/index.browser.js +48 -71
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +1297 -1143
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +456 -392
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.browser.js +17 -17
- package/dist/api/verifications/index.browser.js.map +1 -1
- package/dist/api/verifications/index.d.ts +167 -155
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +47 -95
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/background/index.d.ts +0 -1
- package/dist/background/index.d.ts.map +1 -1
- package/dist/background/index.js.map +1 -1
- package/dist/background/index.workerd.js.map +1 -1
- package/dist/batch/index.d.ts +0 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js.map +1 -1
- package/dist/bin/index.js +1 -1
- package/dist/bin/index.js.map +1 -1
- package/dist/bucket/index.d.ts +27 -32
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +56 -26
- package/dist/bucket/index.js.map +1 -1
- package/dist/bucket/index.workerd.js +52 -24
- package/dist/bucket/index.workerd.js.map +1 -1
- package/dist/cache/core/index.d.ts +4 -6
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js +4 -10
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js +4 -10
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/cache/database/index.d.ts +22 -23
- package/dist/cache/database/index.d.ts.map +1 -1
- package/dist/cache/database/index.js +11 -20
- package/dist/cache/database/index.js.map +1 -1
- package/dist/cache/redis/index.d.ts +3 -4
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cache/redis/index.js +2 -2
- package/dist/cache/redis/index.js.map +1 -1
- package/dist/captcha/index.d.ts.map +1 -1
- package/dist/captcha/index.js +4 -4
- package/dist/captcha/index.js.map +1 -1
- package/dist/cli/config/index.d.ts +0 -1
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/core/index.d.ts +205 -442
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +259 -284
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +3 -9
- package/dist/cli/devtools/index.d.ts.map +1 -1
- package/dist/cli/devtools/index.js +3 -3
- package/dist/cli/devtools/index.js.map +1 -1
- package/dist/cli/i18n/index.d.ts +8 -34
- package/dist/cli/i18n/index.d.ts.map +1 -1
- package/dist/cli/i18n/index.js +6 -6
- package/dist/cli/i18n/index.js.map +1 -1
- package/dist/cli/platform/index.d.ts +89 -82
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +27 -33
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/platform-lib/index.d.ts +351 -404
- package/dist/cli/platform-lib/index.d.ts.map +1 -1
- package/dist/cli/platform-lib/index.js +218 -239
- package/dist/cli/platform-lib/index.js.map +1 -1
- package/dist/cli/vendor/index.d.ts +17 -41
- package/dist/cli/vendor/index.d.ts.map +1 -1
- package/dist/cli/vendor/index.js +10 -13
- package/dist/cli/vendor/index.js.map +1 -1
- package/dist/command/index.d.ts +83 -195
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +160 -563
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +845 -859
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +787 -527
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +845 -859
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +845 -859
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +845 -859
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.browser.js +1 -1
- package/dist/crypto/index.browser.js.map +1 -1
- package/dist/crypto/index.d.ts +3 -4
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/crypto/index.js +6 -3
- package/dist/crypto/index.js.map +1 -1
- package/dist/datetime/index.d.ts +12 -2
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +6 -1
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/brevo/index.d.ts +0 -1
- package/dist/email/brevo/index.d.ts.map +1 -1
- package/dist/email/brevo/index.js +4 -4
- package/dist/email/brevo/index.js.map +1 -1
- package/dist/email/cloudflare/index.d.ts +0 -1
- package/dist/email/cloudflare/index.d.ts.map +1 -1
- package/dist/email/cloudflare/index.js +2 -2
- package/dist/email/cloudflare/index.js.map +1 -1
- package/dist/email/core/index.d.ts +15 -7
- package/dist/email/core/index.d.ts.map +1 -1
- package/dist/email/core/index.js +14 -5
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/core/index.workerd.js +5 -1
- package/dist/email/core/index.workerd.js.map +1 -1
- package/dist/email/smtp/index.d.ts +8 -9
- package/dist/email/smtp/index.d.ts.map +1 -1
- package/dist/email/smtp/index.js +702 -479
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +1580 -1238
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +11728 -32131
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +13 -9
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +5 -5
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.d.ts +0 -1
- 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 +81 -69
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +123 -56
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +27 -90
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +42 -70
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +54 -40
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +140 -106
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +145 -150
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +144 -109
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.bun.js +64 -54
- package/dist/orm/postgres/index.bun.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +36 -76
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/orm/postgres/index.js +67 -57
- package/dist/orm/postgres/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +62 -75
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/core/index.js +48 -71
- package/dist/queue/core/index.js.map +1 -1
- package/dist/queue/core/index.workerd.js +48 -71
- package/dist/queue/core/index.workerd.js.map +1 -1
- package/dist/queue/redis/index.d.ts +3 -4
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/queue/redis/index.js +2 -2
- package/dist/queue/redis/index.js.map +1 -1
- package/dist/react/auth/index.browser.js.map +1 -1
- package/dist/react/auth/index.d.ts +7 -4
- package/dist/react/auth/index.d.ts.map +1 -1
- package/dist/react/auth/index.js.map +1 -1
- package/dist/react/core/index.d.ts +87 -5
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +170 -23
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +4 -5
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/form/index.js +91 -56
- 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 +0 -1
- 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 +4 -5
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/i18n/index.js +2 -2
- package/dist/react/i18n/index.js.map +1 -1
- package/dist/react/intro/index.d.ts +1 -4
- package/dist/react/intro/index.d.ts.map +1 -1
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +60 -24
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +378 -377
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +77 -41
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/sitemap/index.d.ts +0 -1
- package/dist/react/sitemap/index.d.ts.map +1 -1
- package/dist/react/sitemap/index.js.map +1 -1
- package/dist/react/testing/index.d.ts +4 -5
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +41 -15
- package/dist/react/testing/index.js.map +1 -1
- package/dist/react/testing/{chunk-BpyX8vjI.js → rolldown-runtime-Bl3dcgcQ.js} +1 -1
- package/dist/react/ui/index.d.ts +35 -34
- package/dist/react/ui/index.d.ts.map +1 -1
- package/dist/react/ui/index.js +12 -17
- package/dist/react/ui/index.js.map +1 -1
- package/dist/redis/index.bun.js +5 -5
- package/dist/redis/index.bun.js.map +1 -1
- package/dist/redis/index.d.ts +6 -7
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +6 -6
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts +0 -1
- 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 +4 -12
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +9 -4
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +9 -4
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js +30 -28
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +113 -44
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +452 -37
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.browser.js +19 -19
- package/dist/server/auth/index.browser.js.map +1 -1
- package/dist/server/auth/index.d.ts +198 -274
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +83 -621
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.browser.js +103 -5
- package/dist/server/cookies/index.browser.js.map +1 -1
- package/dist/server/cookies/index.d.ts +72 -5
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +103 -9
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.browser.js +22 -27
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +116 -85
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +105 -118
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +9 -10
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/cors/index.js +14 -26
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/etag/index.d.ts +2 -3
- 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 -19
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/health/index.js +6 -6
- package/dist/server/health/index.js.map +1 -1
- package/dist/server/links/index.browser.js +15 -18
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +66 -67
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +29 -32
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +0 -1
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +10 -3
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/proxy/index.d.ts +0 -1
- 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 +8 -9
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.js +6 -12
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +0 -1
- 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 +4 -4
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +37 -25
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +0 -1
- 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 +0 -1
- package/dist/system/index.d.ts.map +1 -1
- package/dist/system/index.js +2 -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 +19 -20
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/core/index.js +8 -8
- package/dist/topic/core/index.js.map +1 -1
- package/dist/topic/redis/index.d.ts +3 -4
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/topic/redis/index.js +2 -2
- package/dist/topic/redis/index.js.map +1 -1
- package/package.json +22 -35
- package/src/api/audits/__tests__/AuditJobs.spec.ts +83 -0
- package/src/api/audits/__tests__/AuditService.spec.ts +139 -1
- package/src/api/audits/controllers/AdminAuditController.ts +41 -41
- package/src/api/audits/entities/audits.ts +22 -22
- package/src/api/audits/index.ts +6 -1
- package/src/api/audits/jobs/AuditJobs.ts +29 -0
- package/src/api/audits/parameters/AuditParameters.ts +51 -0
- package/src/api/audits/primitives/$audit.ts +24 -0
- package/src/api/audits/schemas/auditQuerySchema.ts +13 -13
- package/src/api/audits/schemas/createAuditSchema.ts +18 -18
- package/src/api/audits/services/AuditService.ts +79 -7
- package/src/api/files/__tests__/FileController.spec.ts +5 -5
- package/src/api/files/__tests__/FileJobs.spec.ts +6 -0
- package/src/api/files/controllers/FileController.ts +25 -25
- package/src/api/files/entities/files.ts +15 -15
- package/src/api/files/schemas/fileCreatorSummarySchema.ts +7 -7
- package/src/api/files/schemas/fileQuerySchema.ts +9 -9
- package/src/api/files/schemas/fileResourceSchema.ts +7 -9
- package/src/api/files/schemas/storageStatsSchema.ts +13 -13
- package/src/api/jobs/__tests__/$job-hardening.spec.ts +289 -0
- package/src/api/jobs/__tests__/$job.spec.ts +18 -18
- package/src/api/jobs/controllers/AdminJobController.ts +8 -8
- package/src/api/jobs/entities/jobExecutionEntity.ts +29 -19
- package/src/api/jobs/providers/JobProvider.ts +128 -12
- package/src/api/jobs/providers/JobQueueProvider.ts +2 -2
- package/src/api/jobs/schemas/jobConfigAtom.ts +22 -22
- package/src/api/jobs/schemas/jobExecutionQuerySchema.ts +6 -6
- package/src/api/jobs/schemas/jobExecutionResourceSchema.ts +11 -15
- package/src/api/jobs/schemas/jobRegistrationSchema.ts +20 -19
- package/src/api/jobs/schemas/triggerJobSchema.ts +3 -3
- package/src/api/jobs/services/JobService.ts +6 -6
- package/src/api/keys/__tests__/ApiKeyService.spec.ts +2 -2
- package/src/api/keys/controllers/AdminApiKeyController.ts +10 -10
- package/src/api/keys/entities/apiKeyEntity.ts +15 -15
- package/src/api/keys/schemas/adminApiKeyQuerySchema.ts +4 -4
- package/src/api/keys/schemas/adminApiKeyResourceSchema.ts +15 -15
- package/src/api/keys/schemas/createApiKeyBodySchema.ts +5 -5
- package/src/api/keys/schemas/createApiKeyResponseSchema.ts +9 -9
- package/src/api/keys/schemas/listApiKeyResponseSchema.ts +13 -13
- package/src/api/keys/schemas/revokeApiKeyParamsSchema.ts +3 -3
- package/src/api/keys/schemas/revokeApiKeyResponseSchema.ts +3 -3
- package/src/api/notifications/__tests__/AlephaApiNotifications.spec.ts +2 -2
- package/src/api/notifications/controllers/AdminNotificationController.ts +38 -14
- package/src/api/notifications/jobs/NotificationJobs.ts +7 -6
- package/src/api/notifications/primitives/$notification.ts +43 -4
- package/src/api/notifications/schemas/notificationContactPreferencesSchema.ts +4 -4
- package/src/api/notifications/schemas/notificationContactSchema.ts +7 -7
- package/src/api/notifications/schemas/notificationDetailResourceSchema.ts +9 -11
- package/src/api/notifications/schemas/notificationPayloadSchema.ts +11 -9
- package/src/api/notifications/schemas/notificationQuerySchema.ts +6 -6
- package/src/api/notifications/schemas/notificationResourceSchema.ts +14 -14
- package/src/api/notifications/services/NotificationSenderService.ts +38 -2
- package/src/api/oauth/__tests__/OAuthClientService.spec.ts +42 -0
- package/src/api/oauth/__tests__/OAuthController.spec.ts +128 -0
- package/src/api/oauth/controllers/OAuthController.ts +132 -12
- package/src/api/oauth/entities/oauthClientEntity.ts +29 -12
- package/src/api/oauth/helpers/oauthMetadata.ts +1 -0
- package/src/api/oauth/helpers/oidcMetadata.ts +19 -0
- package/src/api/oauth/index.ts +1 -0
- package/src/api/oauth/schemas/authorizeDecisionBodySchema.ts +12 -11
- package/src/api/oauth/schemas/authorizeQuerySchema.ts +12 -10
- package/src/api/oauth/schemas/registerClientBodySchema.ts +10 -11
- package/src/api/oauth/schemas/tokenRequestBodySchema.ts +9 -8
- package/src/api/oauth/services/OAuthClientService.ts +228 -15
- package/src/api/organizations/controllers/AdminOrganizationController.ts +8 -8
- package/src/api/organizations/entities/organizations.ts +6 -6
- package/src/api/organizations/schemas/createOrganizationSchema.ts +5 -5
- package/src/api/organizations/schemas/organizationQuerySchema.ts +4 -4
- package/src/api/organizations/schemas/updateOrganizationSchema.ts +1 -2
- package/src/api/parameters/__tests__/$parameter.spec.ts +229 -50
- package/src/api/parameters/controllers/AdminParameterController.ts +9 -12
- package/src/api/parameters/entities/parameters.ts +29 -16
- package/src/api/parameters/primitives/$parameter.ts +3 -3
- package/src/api/parameters/schemas/activateParameterBodySchema.ts +4 -4
- package/src/api/parameters/schemas/createParameterVersionBodySchema.ts +15 -15
- package/src/api/parameters/schemas/parameterCreatorSummarySchema.ts +7 -7
- package/src/api/parameters/schemas/parameterCurrentResponseSchema.ts +7 -7
- package/src/api/parameters/schemas/parameterHistoryResponseSchema.ts +3 -3
- package/src/api/parameters/schemas/parameterNameParamSchema.ts +2 -3
- package/src/api/parameters/schemas/parameterNamesResponseSchema.ts +3 -3
- package/src/api/parameters/schemas/parameterResponseSchema.ts +3 -3
- package/src/api/parameters/schemas/parameterStatusSchema.ts +2 -2
- package/src/api/parameters/schemas/parameterTreeNodeSchema.ts +6 -6
- package/src/api/parameters/schemas/parameterVersionParamSchema.ts +5 -6
- package/src/api/parameters/schemas/parameterVersionResponseSchema.ts +3 -3
- package/src/api/parameters/schemas/rollbackParameterBodySchema.ts +6 -9
- package/src/api/parameters/services/ParameterProvider.ts +152 -65
- package/src/api/payments/controllers/AdminPaymentController.ts +7 -7
- package/src/api/payments/controllers/MockCheckoutController.ts +79 -28
- package/src/api/payments/controllers/PaymentController.ts +4 -4
- package/src/api/payments/entities/paymentIntents.ts +11 -11
- package/src/api/payments/entities/paymentMethods.ts +11 -11
- package/src/api/payments/entities/refunds.ts +9 -9
- package/src/api/payments/providers/PaymentProvider.ts +18 -0
- package/src/api/payments/schemas/intentSchemas.ts +25 -25
- package/src/api/payments/schemas/paymentMethodSchemas.ts +3 -3
- package/src/api/payments/services/PaymentService.ts +60 -3
- package/src/api/subscriptions/__tests__/SubscriptionService.spec.ts +14 -0
- package/src/api/subscriptions/controllers/AdminSubscriptionController.ts +11 -11
- package/src/api/subscriptions/controllers/SubscriptionController.ts +5 -4
- package/src/api/subscriptions/entities/subscriptionEvents.ts +15 -15
- package/src/api/subscriptions/entities/subscriptions.ts +22 -22
- package/src/api/subscriptions/notifications/SubscriptionNotifications.ts +22 -22
- package/src/api/subscriptions/schemas/cancelSubscriptionSchema.ts +4 -4
- package/src/api/subscriptions/schemas/changePlanSchema.ts +5 -5
- package/src/api/subscriptions/schemas/createSubscriptionSchema.ts +14 -7
- package/src/api/subscriptions/schemas/entitlementsSchema.ts +10 -10
- package/src/api/subscriptions/schemas/mrrSchema.ts +9 -9
- package/src/api/subscriptions/schemas/planDefinitionSchema.ts +21 -21
- package/src/api/subscriptions/schemas/planResourceSchema.ts +19 -19
- package/src/api/subscriptions/schemas/subscriptionQuerySchema.ts +8 -8
- package/src/api/subscriptions/schemas/subscriptionSettingsSchema.ts +7 -7
- package/src/api/subscriptions/schemas/subscriptionStatsSchema.ts +17 -17
- package/src/api/subscriptions/services/SubscriptionConfig.ts +2 -2
- package/src/api/users/__tests__/ApiKeys-integration.spec.ts +11 -11
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +111 -119
- package/src/api/users/controllers/AdminIdentityController.ts +29 -19
- package/src/api/users/controllers/AdminSessionController.ts +37 -27
- package/src/api/users/controllers/AdminUserController.ts +75 -53
- package/src/api/users/controllers/MySessionController.ts +125 -0
- package/src/api/users/controllers/RealmController.ts +9 -10
- package/src/api/users/controllers/UserController.ts +55 -55
- package/src/api/users/entities/identities.ts +8 -8
- package/src/api/users/entities/sessions.ts +17 -17
- package/src/api/users/entities/users.ts +17 -17
- package/src/api/users/index.ts +3 -0
- package/src/api/users/notifications/UserNotifications.ts +76 -24
- package/src/api/users/primitives/$realm.ts +12 -26
- package/src/api/users/providers/RealmProvider.ts +0 -15
- package/src/api/users/schemas/completePasswordResetRequestSchema.ts +8 -12
- package/src/api/users/schemas/completeRegistrationRequestSchema.ts +17 -20
- package/src/api/users/schemas/createUserSchema.ts +2 -2
- package/src/api/users/schemas/identityQuerySchema.ts +4 -4
- package/src/api/users/schemas/identityResourceSchema.ts +3 -2
- package/src/api/users/schemas/loginSchema.ts +4 -4
- package/src/api/users/schemas/passwordResetIntentResponseSchema.ts +6 -8
- package/src/api/users/schemas/realmConfigSchema.ts +10 -24
- package/src/api/users/schemas/registerQuerySchema.ts +6 -6
- package/src/api/users/schemas/registerRequestSchema.ts +21 -43
- package/src/api/users/schemas/registerResponseSchema.ts +2 -2
- package/src/api/users/schemas/registerSchema.ts +13 -31
- package/src/api/users/schemas/registrationIntentResponseSchema.ts +19 -23
- package/src/api/users/schemas/resetPasswordSchema.ts +10 -17
- package/src/api/users/schemas/sessionQuerySchema.ts +3 -3
- package/src/api/users/schemas/sessionResourceSchema.ts +25 -25
- package/src/api/users/schemas/updateUserSchema.ts +3 -4
- package/src/api/users/schemas/userQuerySchema.ts +7 -7
- package/src/api/users/services/RegistrationService.ts +25 -11
- package/src/api/users/services/UserService.ts +12 -6
- package/src/api/verifications/__tests__/CodeVerification.spec.ts +63 -101
- package/src/api/verifications/__tests__/LinkVerification.spec.ts +23 -92
- package/src/api/verifications/controllers/VerificationController.ts +13 -27
- package/src/api/verifications/entities/verifications.ts +13 -14
- package/src/api/verifications/schemas/requestVerificationCodeResponseSchema.ts +17 -14
- package/src/api/verifications/schemas/validateVerificationCodeResponseSchema.ts +9 -10
- package/src/api/verifications/schemas/verificationSettingsSchema.ts +65 -66
- package/src/api/verifications/schemas/verificationTypeEnumSchema.ts +2 -2
- package/src/api/verifications/services/VerificationService.ts +12 -0
- package/src/background/__tests__/BackgroundTaskProvider.spec.ts +36 -0
- package/src/batch/__tests__/$batch.spec.ts +22 -22
- package/src/batch/__tests__/startup-buffering.spec.ts +9 -9
- package/src/bin/index.ts +1 -1
- package/src/bucket/__tests__/TenantScopedBucket.spec.ts +60 -0
- package/src/bucket/providers/LocalFileStorageProvider.ts +14 -6
- package/src/bucket/providers/MemoryFileStorageProvider.ts +18 -7
- package/src/bucket/providers/R2FileStorageProvider.ts +14 -6
- package/src/bucket/providers/S3FileStorageProvider.ts +31 -15
- package/src/cache/core/primitives/$cache.ts +7 -10
- package/src/cache/database/entities/cacheEntries.ts +16 -27
- package/src/cache/database/providers/DatabaseCacheProvider.ts +15 -13
- package/src/cache/redis/providers/RedisCacheProvider.ts +6 -6
- package/src/captcha/providers/TurnstileCaptchaProvider.ts +4 -4
- package/src/cli/core/__tests__/BuildCloudflareTask.spec.ts +178 -0
- package/src/cli/core/__tests__/BuildDockerTask.spec.ts +0 -2
- package/src/cli/core/__tests__/DbCommand.spec.ts +108 -0
- package/src/cli/core/atoms/appEntryOptions.ts +5 -5
- package/src/cli/core/atoms/buildOptions.ts +76 -76
- package/src/cli/core/atoms/changelogOptions.ts +3 -3
- package/src/cli/core/atoms/devOptions.ts +3 -3
- package/src/cli/core/commands/build.ts +36 -39
- package/src/cli/core/commands/db.ts +171 -83
- package/src/cli/core/commands/dev.ts +8 -8
- package/src/cli/core/commands/gen/changelog.ts +12 -14
- package/src/cli/core/commands/gen/env.ts +6 -6
- package/src/cli/core/commands/gen/openapi.ts +6 -6
- package/src/cli/core/commands/init.ts +28 -33
- package/src/cli/core/commands/pack.ts +10 -10
- package/src/cli/core/commands/root.ts +7 -8
- package/src/cli/core/commands/test.ts +17 -20
- package/src/cli/core/tasks/BuildCloudflareTask.ts +103 -230
- package/src/cli/core/templates/apiHelloResponseSchemaTs.ts +4 -4
- package/src/cli/devtools/atoms/devtoolsOptions.ts +6 -6
- package/src/cli/i18n/atoms/i18nOptions.ts +8 -8
- package/src/cli/platform/commands/SecretsCommand.ts +24 -25
- package/src/cli/platform/commands/platform.ts +40 -46
- package/src/cli/platform/index.ts +1 -1
- package/src/cli/platform-lib/__tests__/CloudflareAdapter.spec.ts +0 -4
- package/src/cli/platform-lib/__tests__/PlatformInspector.spec.ts +10 -3
- package/src/cli/platform-lib/__tests__/VercelAdapter.spec.ts +0 -2
- package/src/cli/platform-lib/adapters/CloudflareAdapter.ts +13 -14
- package/src/cli/platform-lib/adapters/VercelAdapter.ts +6 -11
- package/src/cli/platform-lib/atoms/platformOptions.ts +46 -25
- package/src/cli/platform-lib/schemas/cloudflare.ts +87 -87
- package/src/cli/platform-lib/schemas/platform.ts +51 -51
- package/src/cli/platform-lib/schemas/vercel.ts +28 -28
- package/src/cli/platform-lib/services/CloudflareApi.ts +5 -5
- package/src/cli/platform-lib/services/VercelApi.ts +4 -4
- package/src/cli/platform-lib/services/VercelCli.ts +6 -15
- package/src/cli/platform-lib/services/WranglerApi.ts +6 -15
- package/src/cli/vendor/atoms/vendorOptions.ts +9 -9
- package/src/cli/vendor/commands/VendorCommand.ts +11 -12
- package/src/command/__tests__/$command.spec.ts +82 -83
- package/src/command/__tests__/Asker.spec.ts +6 -13
- package/src/command/__tests__/CliProvider.spec.ts +136 -149
- package/src/command/__tests__/Runner.spec.ts +86 -110
- package/src/command/helpers/Asker.ts +23 -58
- package/src/command/helpers/Runner.ts +34 -110
- package/src/command/index.ts +4 -9
- package/src/command/primitives/$command.ts +10 -10
- package/src/command/providers/CliProvider.ts +183 -161
- package/src/core/Alepha.ts +62 -13
- package/src/core/__tests__/$atom.spec.ts +52 -3
- package/src/core/__tests__/$computed.spec.ts +129 -0
- package/src/core/__tests__/$env.spec.ts +13 -13
- package/src/core/__tests__/$inject.spec.ts +4 -4
- package/src/core/__tests__/$module.spec.ts +1 -1
- package/src/core/__tests__/Alepha-graph.spec.ts +1 -1
- package/src/core/__tests__/Alepha-parseEnv.spec.ts +32 -32
- package/src/core/__tests__/Alepha-start.spec.ts +3 -3
- package/src/core/__tests__/CodecManager.spec.ts +113 -94
- package/src/core/__tests__/KeylessJsonSchemaCodec.spec.ts +138 -138
- package/src/core/__tests__/SchemaValidator.spec.ts +43 -44
- package/src/core/__tests__/StateManager.persist.browser.spec.ts +87 -0
- package/src/core/__tests__/StateManager.spec.ts +423 -0
- package/src/core/__tests__/TypeBox-usecases.spec.ts +8 -8
- package/src/core/__tests__/TypeProvider.spec.ts +314 -309
- package/src/core/__tests__/dump.spec.ts +6 -6
- package/src/core/__tests__/pagination.spec.ts +4 -4
- package/src/core/__tests__/scoped-after-start.spec.ts +43 -0
- package/src/core/errors/TypeBoxError.ts +10 -4
- package/src/core/helpers/FileLike.ts +5 -5
- package/src/core/helpers/coerceStrings.ts +70 -0
- package/src/core/helpers/jsonSchemaToZod.ts +112 -0
- package/src/core/index.shared.ts +4 -1
- package/src/core/primitives/$atom.ts +95 -27
- package/src/core/primitives/$computed.ts +148 -0
- package/src/core/primitives/$env.ts +5 -5
- package/src/core/primitives/$state.ts +1 -1
- package/src/core/providers/AlsProvider.ts +26 -0
- package/src/core/providers/CodecManager.ts +1 -2
- package/src/core/providers/JsonSchemaCodec.ts +1 -2
- package/src/core/providers/KeylessJsonSchemaCodec.ts +82 -57
- package/src/core/providers/SchemaValidator.ts +48 -158
- package/src/core/providers/StateManager.ts +383 -9
- package/src/core/providers/TypeProvider.ts +80 -734
- package/src/core/providers/ZodProvider.ts +380 -0
- package/src/core/providers/zodAugment.ts +69 -0
- package/src/core/schemas/pageQuerySchema.ts +19 -21
- package/src/core/schemas/pageSchema.ts +47 -57
- package/src/crypto/__tests__/SecretProvider.spec.ts +31 -0
- package/src/crypto/providers/SecretProvider.ts +16 -10
- package/src/datetime/primitives/$throttle.ts +6 -1
- package/src/email/brevo/providers/BrevoEmailProvider.ts +4 -4
- package/src/email/cloudflare/providers/CloudflareEmailProvider.ts +6 -6
- package/src/email/core/index.ts +7 -2
- package/src/email/core/primitives/$email.ts +5 -1
- package/src/email/core/providers/LocalEmailProvider.ts +5 -5
- package/src/email/smtp/providers/NodemailerEmailProvider.ts +41 -52
- package/src/fake/__tests__/FakeProvider.spec.ts +110 -110
- package/src/fake/__tests__/keyName.example.ts +21 -21
- package/src/fake/__tests__/keyName.spec.ts +41 -41
- package/src/fake/__tests__/module.example.ts +8 -8
- package/src/fake/providers/FakeProvider.ts +122 -121
- package/src/lock/core/__tests__/lock-mutual-exclusion.spec.ts +44 -0
- package/src/lock/core/index.ts +1 -0
- package/src/lock/core/primitives/$lock.ts +13 -6
- package/src/logger/__tests__/CliFormatterProvider.spec.ts +76 -0
- package/src/logger/__tests__/Logger.spec.ts +49 -0
- package/src/logger/index.ts +25 -18
- package/src/logger/providers/CliFormatterProvider.ts +75 -0
- package/src/logger/schemas/logEntrySchema.ts +10 -10
- package/src/logger/services/Logger.ts +18 -0
- package/src/mcp/__tests__/$prompt.spec.ts +21 -23
- package/src/mcp/__tests__/$tool.spec.ts +22 -22
- package/src/mcp/__tests__/McpServerProvider.spec.ts +11 -11
- package/src/mcp/__tests__/StreamableHttpMcpTransport.spec.ts +2 -2
- package/src/mcp/__tests__/integration.spec.ts +33 -33
- package/src/mcp/primitives/$prompt.ts +11 -9
- package/src/mcp/primitives/$tool.ts +27 -86
- package/src/mcp/transports/StreamableHttpMcpTransport.ts +7 -7
- package/src/orm/__tests__/$repository-tests.ts +133 -27
- package/src/orm/__tests__/$repository.spec.ts +23 -0
- package/src/orm/__tests__/$transactional-tests.ts +4 -4
- package/src/orm/__tests__/ModelBuilder-tests.ts +28 -28
- package/src/orm/__tests__/ModelBuilder.spec.ts +124 -106
- package/src/orm/__tests__/QueryManager.spec.ts +5 -5
- package/src/orm/__tests__/delete-returning-tests.ts +11 -11
- package/src/orm/__tests__/deletedAt-tests.ts +3 -3
- package/src/orm/__tests__/enums.spec.ts +29 -25
- package/src/orm/__tests__/execute-tests.ts +8 -8
- package/src/orm/__tests__/fixtures/bigEntitySchema.ts +48 -48
- package/src/orm/__tests__/fixtures/userEntitySchema.ts +6 -6
- package/src/orm/__tests__/joins-tests.ts +30 -30
- package/src/orm/__tests__/organization-tests.ts +105 -3
- package/src/orm/__tests__/organization.spec.ts +46 -0
- package/src/orm/__tests__/orm-errors.spec.ts +10 -10
- package/src/orm/__tests__/orm-next-tests.ts +29 -29
- package/src/orm/__tests__/orm-showcase-tests.ts +9 -9
- package/src/orm/__tests__/primaryKey.spec.ts +4 -4
- package/src/orm/__tests__/query-date-encoding-tests.ts +17 -17
- package/src/orm/__tests__/ref-auto-onDelete.spec.ts +14 -14
- package/src/orm/__tests__/references.spec.ts +7 -7
- package/src/orm/__tests__/security.spec.ts +17 -17
- package/src/orm/__tests__/string-operators-tests.ts +5 -5
- package/src/orm/__tests__/timestamps-tests.ts +14 -14
- package/src/orm/__tests__/validation-tests.ts +5 -5
- package/src/orm/core/__tests__/BunSqliteProvider.bun.spec.ts +8 -8
- package/src/orm/core/constants/PG_SYMBOLS.ts +13 -1
- package/src/orm/core/entities/alephaSequences.ts +8 -8
- package/src/orm/core/helpers/pgAttr.ts +4 -4
- package/src/orm/core/primitives/$entity.ts +10 -6
- package/src/orm/core/providers/DatabaseTypeProvider.ts +46 -53
- package/src/orm/core/providers/drivers/BunSqliteProvider.ts +8 -8
- package/src/orm/core/providers/drivers/CloudflareD1Provider.ts +3 -5
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +8 -8
- package/src/orm/core/schemas/databaseEnvSchema.ts +4 -4
- package/src/orm/core/schemas/insertSchema.ts +14 -18
- package/src/orm/core/schemas/legacyIdSchema.ts +2 -2
- package/src/orm/core/schemas/updateSchema.ts +10 -16
- package/src/orm/core/services/PgRelationManager.ts +2 -2
- package/src/orm/core/services/QueryManager.ts +13 -2
- package/src/orm/core/services/Repository.ts +88 -33
- package/src/orm/core/services/SqliteModelBuilder.ts +38 -45
- package/src/orm/postgres/__tests__/BunPostgresProvider.bun.spec.ts +4 -4
- package/src/orm/postgres/providers/CloudflareHyperdriveProvider.ts +4 -6
- package/src/orm/postgres/schemas/postgresEnvSchema.ts +6 -6
- package/src/orm/postgres/services/PostgresModelBuilder.ts +127 -114
- package/src/queue/core/__tests__/$consumer.spec.ts +4 -4
- package/src/queue/core/__tests__/WorkerProvider.spec.ts +4 -4
- package/src/queue/core/__tests__/shared.ts +6 -6
- package/src/queue/core/primitives/$consumer.ts +5 -5
- package/src/queue/core/primitives/$queue.ts +44 -61
- package/src/queue/core/providers/CloudflareQueueProvider.ts +6 -0
- package/src/queue/core/providers/WorkerProvider.ts +17 -14
- package/src/queue/redis/providers/RedisQueueProvider.ts +3 -3
- package/src/react/core/__tests__/ErrorBoundary.browser.spec.tsx +92 -0
- package/src/react/core/__tests__/Router.spec.tsx +4 -4
- package/src/react/core/__tests__/useComputed.browser.spec.tsx +192 -0
- package/src/react/core/__tests__/useQuery.browser.spec.tsx +48 -0
- package/src/react/core/__tests__/useSelector.browser.spec.tsx +105 -0
- package/src/react/core/__tests__/useStore.browser.spec.tsx +113 -0
- package/src/react/core/components/ErrorBoundary.tsx +42 -0
- package/src/react/core/hooks/useAction.ts +56 -19
- package/src/react/core/hooks/useComputed.ts +91 -0
- package/src/react/core/hooks/useSelector.ts +67 -0
- package/src/react/core/hooks/useStore.ts +36 -17
- package/src/react/core/index.ts +3 -0
- package/src/react/core/utils/shallowEqual.ts +36 -0
- package/src/react/form/__tests__/FormModel-submit-loading.spec.ts +2 -2
- package/src/react/form/__tests__/form-submitting-reactive.browser.spec.tsx +5 -5
- package/src/react/form/__tests__/useForm.browser.spec.tsx +54 -54
- package/src/react/form/errors/FormValidationError.ts +0 -2
- package/src/react/form/hooks/useForm.ts +19 -4
- package/src/react/form/hooks/useFormQuerySync.ts +0 -0
- package/src/react/form/services/FormModel.ts +67 -47
- package/src/react/form/services/parseField.ts +66 -27
- package/src/react/i18n/__tests__/Localize.spec.tsx +1 -1
- package/src/react/i18n/providers/I18nProvider.ts +2 -2
- package/src/react/router/__tests__/$page.browser.spec.tsx +19 -19
- package/src/react/router/__tests__/$page.spec.tsx +21 -21
- package/src/react/router/__tests__/ReactBrowserProvider.browser.spec.ts +87 -1
- package/src/react/router/atoms/ssrManifestAtom.ts +16 -16
- package/src/react/router/components/NestedView.tsx +11 -3
- package/src/react/router/hooks/useQueryParams.ts +1 -1
- package/src/react/router/primitives/$page.ts +2 -2
- package/src/react/router/providers/ReactBrowserProvider.ts +64 -13
- package/src/react/router/providers/ReactPageProvider.ts +26 -12
- package/src/react/router/providers/ReactServerProvider.ts +13 -15
- package/src/react/sitemap/__tests__/$sitemap.spec.ts +2 -2
- package/src/react/ui/atoms/uiAtom.ts +6 -6
- package/src/react/ui/atoms/uiThemeListAtom.ts +7 -7
- package/src/react/ui/hooks/useColorMode.ts +11 -4
- package/src/react/ui/services/SchemaControl.ts +4 -4
- package/src/redis/providers/BunRedisProvider.ts +19 -11
- package/src/redis/providers/NodeRedisProvider.ts +3 -3
- package/src/scheduler/primitives/$scheduler.ts +21 -8
- package/src/security/__tests__/assertRealmScope.spec.ts +29 -0
- package/src/security/atoms/currentTenantAtom.ts +6 -6
- package/src/security/atoms/currentUserAtom.ts +2 -2
- package/src/security/primitives/$issuer.ts +24 -2
- package/src/security/providers/JwtProvider.ts +100 -0
- package/src/security/providers/SecurityProvider.ts +43 -2
- package/src/security/schemas/permissionSchema.ts +19 -19
- package/src/security/schemas/roleSchema.ts +22 -28
- package/src/security/schemas/userAccountInfoSchema.ts +47 -37
- package/src/server/auth/index.ts +0 -3
- package/src/server/auth/primitives/$auth.ts +6 -6
- package/src/server/auth/primitives/$authApple.ts +10 -10
- package/src/server/auth/primitives/$authFacebook.ts +10 -10
- package/src/server/auth/primitives/$authFranceConnect.ts +10 -10
- package/src/server/auth/primitives/$authGithub.ts +10 -10
- package/src/server/auth/primitives/$authGoogle.ts +10 -10
- package/src/server/auth/primitives/$authMicrosoft.ts +14 -14
- package/src/server/auth/providers/ServerAuthProvider.ts +49 -48
- package/src/server/auth/schemas/authenticationProviderSchema.ts +9 -12
- package/src/server/auth/schemas/tokenResponseSchema.ts +2 -2
- package/src/server/auth/schemas/tokensSchema.ts +16 -16
- package/src/server/auth/schemas/userinfoResponseSchema.ts +3 -3
- package/src/server/cookies/__tests__/AtomCookieBinding.spec.ts +80 -0
- package/src/server/cookies/__tests__/AtomCookiePersistence.browser.spec.ts +169 -0
- package/src/server/cookies/__tests__/AtomCookiePersistence.spec.ts +294 -0
- package/src/server/cookies/__tests__/ServerCookiesProvider.spec.ts +14 -14
- package/src/server/cookies/index.browser.ts +4 -1
- package/src/server/cookies/index.ts +8 -1
- package/src/server/cookies/primitives/$cookie.browser.ts +1 -1
- package/src/server/cookies/primitives/$cookie.ts +16 -0
- package/src/server/cookies/providers/AtomCookiePersistence.browser.ts +133 -0
- package/src/server/cookies/providers/AtomCookiePersistence.ts +148 -0
- package/src/server/cookies/providers/ServerCookiesProvider.ts +13 -5
- package/src/server/cookies/services/CookieParser.ts +6 -1
- package/src/server/core/__tests__/$action.spec.ts +13 -13
- package/src/server/core/__tests__/$middleware.spec.ts +10 -10
- package/src/server/core/__tests__/$route.spec.ts +9 -9
- package/src/server/core/__tests__/$sse.spec.ts +26 -26
- package/src/server/core/__tests__/BunHttpServerProvider.bun.spec.ts +6 -6
- package/src/server/core/__tests__/HttpClient.spec.ts +2 -2
- package/src/server/core/__tests__/NodeHttpServerProvider.spec.ts +15 -3
- package/src/server/core/__tests__/ServerBodyParserProvider.spec.ts +14 -14
- package/src/server/core/__tests__/ServerMultipartProvider.spec.ts +33 -33
- package/src/server/core/__tests__/ServerRouterProvider-errorHandler.spec.ts +5 -1
- package/src/server/core/__tests__/ServerRouterProvider-getRoutes.spec.ts +25 -25
- package/src/server/core/__tests__/ServerRouterProvider-serializationError.spec.ts +9 -5
- package/src/server/core/__tests__/ServerRouterProvider-validationError.spec.ts +56 -24
- package/src/server/core/errors/ValidationError.ts +6 -3
- package/src/server/core/helpers/isMultipart.ts +2 -1
- package/src/server/core/index.ts +5 -2
- package/src/server/core/interfaces/ServerRequest.ts +6 -14
- package/src/server/core/primitives/$action.ts +26 -36
- package/src/server/core/primitives/$sse.ts +3 -3
- package/src/server/core/providers/BunHttpServerProvider.ts +8 -9
- package/src/server/core/providers/NodeHttpServerProvider.ts +8 -9
- package/src/server/core/providers/ServerBodyParserProvider.ts +20 -12
- package/src/server/core/providers/ServerCompressProvider.ts +9 -10
- package/src/server/core/providers/ServerHelmetProvider.ts +26 -27
- package/src/server/core/providers/ServerMultipartProvider.ts +19 -19
- package/src/server/core/providers/ServerRouterProvider.ts +44 -15
- package/src/server/core/schemas/errorSchema.ts +20 -25
- package/src/server/core/schemas/okSchema.ts +9 -14
- package/src/server/core/services/HttpClient.ts +13 -1
- package/src/server/core/services/ServerRequestParser.ts +6 -6
- package/src/server/cors/providers/ServerCorsProvider.ts +26 -28
- package/src/server/health/schemas/healthSchema.ts +6 -6
- package/src/server/links/__tests__/$remote.spec.ts +3 -3
- package/src/server/links/__tests__/BatchEndpoint.spec.ts +9 -9
- package/src/server/links/__tests__/LinkProvider.spec.ts +9 -9
- package/src/server/links/__tests__/ServerLinksProvider.spec.ts +23 -23
- package/src/server/links/__tests__/fixtures/CrudApp.ts +21 -21
- package/src/server/links/atoms/apiLinksAtom.ts +2 -2
- package/src/server/links/atoms/linkOptionsAtom.ts +6 -6
- package/src/server/links/primitives/$remote.ts +3 -3
- package/src/server/links/providers/LinkProvider.ts +3 -3
- package/src/server/links/providers/ServerLinksProvider.ts +20 -20
- package/src/server/links/schemas/apiLinksResponseSchema.ts +23 -23
- package/src/server/proxy/__tests__/$proxy.spec.ts +9 -9
- package/src/server/proxy/providers/ServerProxyProvider.ts +5 -0
- package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +18 -20
- package/src/server/swagger/__tests__/$swagger.spec.ts +91 -94
- package/src/server/swagger/__tests__/ui.spec.ts +3 -3
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +66 -43
- package/src/system/__tests__/NodeShellProvider.spec.ts +46 -0
- package/src/system/providers/NodeShellProvider.ts +4 -1
- package/src/topic/core/__tests__/$subscriber.spec.ts +4 -4
- package/src/topic/core/__tests__/shared.ts +8 -8
- package/src/topic/core/primitives/$subscriber.ts +5 -5
- package/src/topic/core/primitives/$topic.ts +14 -14
- package/src/topic/redis/providers/RedisTopicProvider.ts +3 -3
- package/dist/container/core/index.d.ts +0 -236
- package/dist/container/core/index.d.ts.map +0 -1
- package/dist/container/core/index.js +0 -231
- package/dist/container/core/index.js.map +0 -1
- package/dist/container/core/index.workerd.js +0 -192
- package/dist/container/core/index.workerd.js.map +0 -1
- package/src/command/helpers/PrettyAsker.ts +0 -256
- package/src/command/helpers/PrettyPrint.ts +0 -332
- package/src/container/core/__tests__/$container.spec.ts +0 -83
- package/src/container/core/index.ts +0 -50
- package/src/container/core/index.workerd.ts +0 -53
- package/src/container/core/interfaces/ContainerOptions.ts +0 -69
- package/src/container/core/primitives/$container.ts +0 -100
- package/src/container/core/providers/CloudflareContainerProvider.ts +0 -70
- package/src/container/core/providers/ContainerProvider.ts +0 -92
- package/src/container/core/providers/MockContainerProvider.ts +0 -62
- package/src/container/core/providers/NodeContainerProvider.ts +0 -53
- package/src/core/__tests__/jsonSchemaToTypeBox.spec.ts +0 -771
- package/src/core/helpers/jsonSchemaToTypeBox.ts +0 -359
- package/src/server/auth/__tests__/authFederationClient.spec.ts +0 -40
- package/src/server/auth/__tests__/federationAssertion.spec.ts +0 -146
- package/src/server/auth/helpers/federationAssertion.ts +0 -74
- package/src/server/auth/primitives/$authFederationBroker.ts +0 -273
- package/src/server/auth/primitives/$authFederationClient.ts +0 -89
- /package/dist/orm/core/{chunk-B4FMCO8f.js → rolldown-runtime-B4FMCO8f.js} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.workerd.js","names":[],"sources":["../../../src/queue/core/primitives/$consumer.ts","../../../src/queue/core/providers/MemoryQueueProvider.ts","../../../src/queue/core/providers/QueueProvider.ts","../../../src/queue/core/providers/WorkerProvider.ts","../../../src/queue/core/primitives/$queue.ts","../../../src/queue/core/providers/CloudflareQueueProvider.ts","../../../src/queue/core/providers/WorkerdWorkerProvider.ts","../../../src/queue/core/index.workerd.ts"],"sourcesContent":["import {\n createPrimitive,\n KIND,\n PipelinePrimitive,\n type PipelinePrimitiveOptions,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport type { QueuePrimitive } from \"./$queue.ts\";\n\n/**\n * Creates a consumer primitive to process messages from a specific queue.\n *\n * Provides a dedicated message consumer that connects to a queue and processes messages\n * with custom handler logic, enabling scalable architectures where multiple consumers\n * can process messages from the same queue.\n *\n * **Key Features**\n * - Seamless integration with any $queue primitive\n * - Full type safety inherited from queue schema\n * - Automatic worker management for background processing\n * - Built-in error handling and retry mechanisms\n * - Support for multiple consumers per queue for horizontal scaling\n *\n * **Common Use Cases**\n * - Email sending and notification services\n * - Image and media processing workers\n * - Data synchronization and background jobs\n *\n * @example\n * ```ts\n * class EmailService {\n * emailQueue = $queue({\n * name: \"emails\",\n * schema: t.object({\n * to: t.text(),\n * subject: t.text(),\n * body: t.text()\n * })\n * });\n *\n * emailConsumer = $consumer({\n * queue: this.emailQueue,\n * handler: async (message) => {\n * const { to, subject, body } = message.payload;\n * await this.sendEmail(to, subject, body);\n * }\n * });\n *\n * async sendWelcomeEmail(userEmail: string) {\n * await this.emailQueue.push({\n * to: userEmail,\n * subject: \"Welcome!\",\n * body: \"Thanks for joining.\"\n * });\n * }\n * }\n * ```\n */\nexport const $consumer = <T extends TSchema>(\n options: ConsumerPrimitiveOptions<T>,\n): ConsumerPrimitive<T> => {\n return createPrimitive(ConsumerPrimitive<T>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface ConsumerPrimitiveOptions<T extends TSchema>\n extends PipelinePrimitiveOptions {\n /**\n * The queue primitive that this consumer will process messages from.\n *\n * This establishes the connection between the consumer and its source queue:\n * - The consumer inherits the queue's message schema for type safety\n * - Messages pushed to the queue will be automatically routed to this consumer\n * - Multiple consumers can be attached to the same queue for parallel processing\n * - The consumer will use the queue's provider and configuration settings\n *\n * **Queue Integration Benefits**:\n * - Type safety: Consumer handler gets fully typed message payloads\n * - Schema validation: Messages are validated before reaching the consumer\n * - Error handling: Failed messages can be retried or moved to dead letter queues\n * - Monitoring: Queue metrics include consumer processing statistics\n *\n * @example\n * ```ts\n * // First, define a queue\n * emailQueue = $queue({\n * name: \"emails\",\n * schema: t.object({ to: t.text(), subject: t.text() })\n * });\n *\n * // Then, create a consumer for that queue\n * emailConsumer = $consumer({\n * queue: this.emailQueue, // Reference the queue primitive\n * handler: async (message) => { } // process email\n * });\n * ```\n */\n queue: QueuePrimitive<T>;\n\n /**\n * Message handler function that processes individual messages from the queue.\n *\n * This function:\n * - Receives fully typed and validated message payloads from the connected queue\n * - Runs in the background worker system for non-blocking operation\n * - Should implement the core business logic for processing this message type\n * - Can throw errors to trigger the queue's retry mechanisms\n * - Has access to the full Alepha dependency injection container\n * - Should be idempotent to handle potential duplicate deliveries\n *\n * **Handler Design Guidelines**:\n * - Keep handlers focused on a single responsibility\n * - Use proper error handling and meaningful error messages\n * - Log important processing steps for debugging and monitoring\n * - Consider transaction boundaries for data consistency\n * - Make operations idempotent when possible\n * - Validate business rules within the handler logic\n *\n * **Error Handling Strategy**:\n * - Throw errors for temporary failures that should be retried\n * - Log and handle permanent failures gracefully\n * - Use specific error types to control retry behavior\n * - Consider implementing circuit breakers for external service calls\n *\n * @param message - The queue message containing the validated payload\n * @param message.payload - The typed message data based on the queue's schema\n * @returns Promise that resolves when processing is complete\n *\n * @example\n * ```ts\n * handler: async (message) => {\n * const { userId, action, data } = message.payload;\n *\n * try {\n * // Log processing start\n * this.logger.info(`Processing ${action} for user ${userId}`);\n *\n * // Validate business rules\n * if (!await this.userService.exists(userId)) {\n * throw new Error(`User ${userId} not found`);\n * }\n *\n * // Perform the main processing logic\n * switch (action) {\n * case \"create\":\n * await this.processCreation(userId, data);\n * break;\n * case \"update\":\n * await this.processUpdate(userId, data);\n * break;\n * default:\n * throw new Error(`Unknown action: ${action}`);\n * }\n *\n * // Log successful completion\n * this.logger.info(`Successfully processed ${action} for user ${userId}`);\n *\n * } catch (error) {\n * // Log error with context\n * this.logger.error(`Failed to process ${action} for user ${userId}`, {\n * error: error.message,\n * userId,\n * action,\n * data\n * });\n *\n * // Re-throw to trigger queue retry mechanism\n * throw error;\n * }\n * }\n * ```\n */\n handler: (message: { payload: Static<T> }) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class ConsumerPrimitive<T extends TSchema> extends PipelinePrimitive<\n ConsumerPrimitiveOptions<T>\n> {}\n\n$consumer[KIND] = ConsumerPrimitive;\n","import { $logger } from \"alepha/logger\";\nimport type { QueueProvider } from \"./QueueProvider.ts\";\n\nexport class MemoryQueueProvider implements QueueProvider {\n protected readonly log = $logger();\n protected queueList: Record<string, string[]> = {};\n\n public async push(queue: string, ...messages: string[]): Promise<void> {\n if (this.queueList[queue] == null) {\n this.queueList[queue] = [];\n }\n\n this.queueList[queue].push(...messages);\n }\n\n public async pop(queue: string): Promise<string | undefined> {\n return this.queueList[queue]?.shift();\n }\n}\n","/**\n * Minimalist Queue interface.\n *\n * Will be probably enhanced in the future to support more advanced features. But for now, it's enough!\n */\nexport abstract class QueueProvider {\n /**\n * Push a message to the queue.\n *\n * @param queue Name of the queue to push the message to.\n * @param message String message to be pushed to the queue. Buffer messages are not supported for now.\n */\n public abstract push(queue: string, message: string): Promise<void>;\n\n /**\n * Pop a message from the queue.\n *\n * @param queue Name of the queue to pop the message from.\n *\n * @returns The message popped or `undefined` if the queue is empty.\n */\n public abstract pop(queue: string): Promise<string | undefined>;\n}\n","import {\n $atom,\n $hook,\n $inject,\n $state,\n Alepha,\n type Static,\n type TSchema,\n t,\n} from \"alepha\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $consumer } from \"../primitives/$consumer.ts\";\nimport {\n $queue,\n type QueueMessage,\n type QueuePrimitive,\n} from \"../primitives/$queue.ts\";\nimport { QueueProvider } from \"./QueueProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Queue worker configuration atom.\n */\nexport const queueWorkerOptions = $atom({\n name: \"alepha.queue.worker.options\",\n schema: t.object({\n interval: t.integer({\n default: 1000,\n description:\n \"Interval in milliseconds to wait before checking for new messages.\",\n }),\n maxInterval: t.integer({\n default: 32000,\n description:\n \"Maximum interval in milliseconds to wait before checking for new messages.\",\n }),\n concurrency: t.integer({\n default: 1,\n description:\n \"Number of workers to run concurrently. Useful only if you are doing a lot of I/O.\",\n }),\n }),\n default: {\n interval: 1000,\n maxInterval: 32000,\n concurrency: 1,\n },\n});\n\nexport type QueueWorkerOptions = Static<typeof queueWorkerOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [queueWorkerOptions.key]: QueueWorkerOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class WorkerProvider {\n protected readonly log = $logger();\n protected readonly options = $state(queueWorkerOptions);\n protected readonly alepha = $inject(Alepha);\n protected readonly queueProvider = $inject(QueueProvider);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n protected workerPromises: Array<Promise<void>> = [];\n protected workersRunning = 0;\n protected abortController: AbortController | undefined;\n protected workerIntervals: Record<number, number> = {};\n protected consumers: Array<Consumer> = [];\n protected nextConsumerIndex = 0;\n\n public get isRunning(): boolean {\n return this.workersRunning > 0;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n priority: \"last\",\n handler: () => {\n for (const queue of this.alepha.primitives($queue)) {\n const handler = queue.options.handler;\n if (handler) {\n this.consumers.push({\n handler,\n queue,\n });\n }\n }\n\n for (const consumer of this.alepha.primitives($consumer)) {\n this.consumers.push({\n queue: consumer.options.queue,\n handler: (msg) => consumer.handler.run(msg),\n });\n }\n\n if (this.consumers.length > 0) {\n this.startWorkers();\n this.log.debug(\n `Watching for ${this.consumers.length} queue${this.consumers.length > 1 ? \"s\" : \"\"} with ${this.options.concurrency} worker${\n this.options.concurrency > 1 ? \"s\" : \"\"\n }.`,\n );\n }\n },\n });\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Engine part - this is the part that will run the workers and process the messages\n\n /**\n * Start the workers.\n * This method will create an endless loop that will check for new messages!\n */\n protected startWorkers(): void {\n this.abortController ??= new AbortController();\n const workerToStart = this.options.concurrency - this.workersRunning;\n\n for (let i = 0; i < workerToStart; i++) {\n this.workersRunning += 1;\n this.log.debug(`Starting worker n-${i}`);\n\n const workerLoop = async () => {\n while (this.workersRunning > 0) {\n this.log.trace(`Worker n-${i} is checking for new messages`);\n const next = await this.getNextMessage();\n if (next) {\n this.workerIntervals[i] = 0;\n await this.processMessage(next);\n } else {\n await this.waitForNextMessage(i);\n }\n }\n this.log.info(`Worker n-${i} has stopped`);\n // Only decrement if we're not already at 0 (shutdown case)\n if (this.workersRunning > 0) {\n this.workersRunning -= 1;\n }\n };\n\n this.workerPromises.push(\n workerLoop().catch((e) => {\n this.log.error(`Worker n-${i} has crashed`, e);\n // Always decrement on crash, regardless of shutdown state\n this.workersRunning = Math.max(0, this.workersRunning - 1);\n }),\n );\n }\n }\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: async () => {\n if (this.consumers.length > 0) {\n await this.stopWorkers();\n }\n },\n });\n\n /**\n * Wait for the next message, where `n` is the worker number.\n *\n * This method will wait for a certain amount of time, increasing the wait time again if no message is found.\n */\n protected async waitForNextMessage(n: number): Promise<void> {\n const intervals = this.workerIntervals;\n const milliseconds = intervals[n] || this.options.interval;\n\n this.log.trace(`Worker n-${n} is waiting for ${milliseconds}ms.`);\n\n if (this.abortController?.signal.aborted) {\n this.log.warn(`Worker n-${n} aborted.`);\n return;\n }\n\n await this.dateTimeProvider.wait(milliseconds, {\n signal: this.abortController?.signal,\n });\n\n if (intervals[n]) {\n if (intervals[n] < this.options.maxInterval) {\n intervals[n] = intervals[n] * 2;\n }\n } else {\n intervals[n] = milliseconds;\n }\n }\n\n /**\n * Get the next message.\n */\n protected async getNextMessage(): Promise<undefined | NextMessage> {\n const len = this.consumers.length;\n for (let i = 0; i < len; i++) {\n const idx = (this.nextConsumerIndex + i) % len;\n const consumer = this.consumers[idx];\n const provider = consumer.queue.provider;\n const message = await provider.pop(consumer.queue.name);\n if (message) {\n this.nextConsumerIndex = (idx + 1) % len;\n return { message, consumer };\n }\n }\n }\n\n /**\n * Process a message from a queue.\n */\n protected async processMessage(response: {\n message: any;\n consumer: Consumer;\n }) {\n const { message, consumer } = response;\n\n try {\n const json = JSON.parse(message);\n const payload = this.alepha.codec.decode(\n consumer.queue.options.schema,\n json.payload,\n );\n await this.alepha.context.run(() => consumer.handler({ payload }));\n } catch (e) {\n this.log.error(\"Failed to process message\", e);\n }\n }\n\n /**\n * Stop the workers.\n *\n * This method will stop the workers and wait for them to finish processing.\n */\n protected async stopWorkers() {\n this.workersRunning = 0;\n\n this.log.trace(\"Stopping workers...\");\n this.abortController?.abort();\n\n this.log.trace(\"Waiting for workers to finish...\");\n await Promise.all(this.workerPromises);\n }\n\n /**\n * Force the workers to get back to work.\n */\n public wakeUp(): void {\n this.log.debug(\"Waking up workers...\");\n this.abortController?.abort();\n this.abortController = new AbortController();\n\n // if no workers are running, start them, (should not happen, but just in case)\n this.startWorkers();\n }\n}\n\nexport interface Consumer<T extends TSchema = TSchema> {\n queue: QueuePrimitive<T>;\n handler: (message: QueueMessage<T>) => Promise<void>;\n}\n\nexport interface NextMessage {\n consumer: Consumer;\n message: string;\n}\n","import {\n $inject,\n createPrimitive,\n KIND,\n Primitive,\n type Service,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { MemoryQueueProvider } from \"../providers/MemoryQueueProvider.ts\";\nimport { QueueProvider } from \"../providers/QueueProvider.ts\";\nimport { WorkerProvider } from \"../providers/WorkerProvider.ts\";\n\n/**\n * Creates a queue primitive for asynchronous message processing with background workers.\n *\n * The $queue primitive enables powerful asynchronous communication patterns in your application.\n * It provides type-safe message queuing with automatic worker processing, making it perfect for\n * decoupling components and handling background tasks efficiently.\n *\n * **Background Processing**\n * - Automatic worker threads for non-blocking message processing\n * - Built-in retry mechanisms and error handling\n * - Dead letter queues for failed message handling\n * - Graceful shutdown and worker lifecycle management\n *\n * **Type Safety**\n * - Full TypeScript support with schema validation using TypeBox\n * - Type-safe message payloads with automatic inference\n * - Runtime validation of all queued messages\n * - Compile-time errors for invalid message structures\n *\n * **Storage Flexibility**\n * - Memory provider for development and testing\n * - Redis provider for production scalability and persistence\n * - Custom provider support for specialized backends\n * - Automatic failover and connection pooling\n *\n * **Performance & Scalability**\n * - Batch processing support for high-throughput scenarios\n * - Horizontal scaling with distributed queue backends\n * - Configurable concurrency and worker pools\n * - Efficient serialization and message routing\n *\n * **Reliability**\n * - Message persistence across application restarts\n * - Automatic retry with exponential backoff\n * - Dead letter handling for permanently failed messages\n * - Comprehensive logging and monitoring integration\n *\n * @example Basic notification queue\n * ```typescript\n * const emailQueue = $queue({\n * name: \"email-notifications\",\n * schema: t.object({\n * to: t.text(),\n * subject: t.text(),\n * body: t.text(),\n * priority: t.optional(t.enum([\"high\", \"normal\"]))\n * }),\n * handler: async (message) => {\n * await emailService.send(message.payload);\n * console.log(`Email sent to ${message.payload.to}`);\n * }\n * });\n *\n * // Push messages for background processing\n * await emailQueue.push({\n * to: \"user@example.com\",\n * subject: \"Welcome!\",\n * body: \"Welcome to our platform\",\n * priority: \"high\"\n * });\n * ```\n *\n * @example Batch processing with Redis\n * ```typescript\n * const imageQueue = $queue({\n * name: \"image-processing\",\n * provider: RedisQueueProvider,\n * schema: t.object({\n * imageId: t.text(),\n * operations: t.array(t.enum([\"resize\", \"compress\", \"thumbnail\"]))\n * }),\n * handler: async (message) => {\n * for (const op of message.payload.operations) {\n * await processImage(message.payload.imageId, op);\n * }\n * }\n * });\n *\n * // Batch processing multiple images\n * await imageQueue.push(\n * { imageId: \"img1\", operations: [\"resize\", \"thumbnail\"] },\n * { imageId: \"img2\", operations: [\"compress\"] },\n * { imageId: \"img3\", operations: [\"resize\", \"compress\", \"thumbnail\"] }\n * );\n * ```\n *\n * @example Development with memory provider\n * ```typescript\n * const taskQueue = $queue({\n * name: \"dev-tasks\",\n * provider: \"memory\",\n * schema: t.object({\n * taskType: t.enum([\"cleanup\", \"backup\", \"report\"]),\n * data: t.record(t.text(), t.any())\n * }),\n * handler: async (message) => {\n * switch (message.payload.taskType) {\n * case \"cleanup\":\n * await performCleanup(message.payload.data);\n * break;\n * case \"backup\":\n * await createBackup(message.payload.data);\n * break;\n * case \"report\":\n * await generateReport(message.payload.data);\n * break;\n * }\n * }\n * });\n * ```\n */\nexport const $queue = <T extends TSchema>(\n options: QueuePrimitiveOptions<T>,\n): QueuePrimitive<T> => {\n return createPrimitive(QueuePrimitive<T>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface QueuePrimitiveOptions<T extends TSchema> {\n /**\n * Unique name for the queue.\n *\n * This name is used for:\n * - Queue identification across the system\n * - Storage backend key generation\n * - Logging and monitoring\n * - Worker assignment and routing\n *\n * If not provided, defaults to the property key where the queue is declared.\n *\n * @example \"email-notifications\"\n * @example \"image-processing\"\n * @example \"order-fulfillment\"\n */\n name?: string;\n\n /**\n * Human-readable description of the queue's purpose.\n *\n * Used for:\n * - Documentation generation\n * - Monitoring dashboards\n * - Development team communication\n * - Queue management interfaces\n *\n * @example \"Process user registration emails and welcome sequences\"\n * @example \"Handle image uploads, resizing, and thumbnail generation\"\n * @example \"Manage order processing, payment, and shipping workflows\"\n */\n description?: string;\n\n /**\n * Queue storage provider configuration.\n *\n * Options:\n * - **\"memory\"**: In-memory queue (default for development, lost on restart)\n * - **Service<QueueProvider>**: Custom provider class (e.g., RedisQueueProvider)\n * - **undefined**: Uses the default queue provider from dependency injection\n *\n * **Provider Selection Guidelines**:\n * - Development: Use \"memory\" for fast, simple testing\n * - Production: Use Redis or database-backed providers for persistence\n * - High-throughput: Use specialized providers with connection pooling\n * - Distributed systems: Use Redis or message brokers for scalability\n *\n * @default Uses injected QueueProvider\n * @example \"memory\"\n * @example RedisQueueProvider\n * @example DatabaseQueueProvider\n */\n provider?: \"memory\" | Service<QueueProvider>;\n\n /**\n * TypeBox schema defining the structure of messages in this queue.\n *\n * This schema:\n * - Validates all messages pushed to the queue\n * - Provides full TypeScript type inference\n * - Ensures type safety between producers and consumers\n * - Enables automatic serialization/deserialization\n *\n * **Schema Design Best Practices**:\n * - Keep schemas simple and focused on the specific task\n * - Use optional fields for data that might not always be available\n * - Include version fields for schema evolution\n * - Use union types for different message types in the same queue\n *\n * @example\n * ```ts\n * t.object({\n * userId: t.text(),\n * action: t.enum([\"create\", \"update\"]),\n * data: t.record(t.text(), t.any()),\n * timestamp: t.optional(t.number())\n * })\n * ```\n */\n schema: T;\n\n /**\n * Message handler function that processes queue messages.\n *\n * This function:\n * - Runs in background worker threads for non-blocking processing\n * - Receives type-safe message payloads based on the schema\n * - Should be idempotent to handle potential retries\n * - Can throw errors to trigger retry mechanisms\n * - Has access to the full Alepha dependency injection container\n *\n * **Handler Best Practices**:\n * - Keep handlers focused on a single responsibility\n * - Use proper error handling and logging\n * - Make operations idempotent when possible\n * - Validate critical business logic within handlers\n * - Consider using transactions for data consistency\n *\n * @param message - The queue message with validated payload\n * @returns Promise that resolves when processing is complete\n *\n * @example\n * ```ts\n * handler: async (message) => {\n * const { userId, email, template } = message.payload;\n *\n * try {\n * await this.emailService.send({\n * to: email,\n * template,\n * data: { userId }\n * });\n *\n * await this.userService.markEmailSent(userId, template);\n * } catch (error) {\n * // Log error and let the queue system handle retries\n * this.logger.error(`Failed to send email to ${email}`, error);\n * throw error;\n * }\n * }\n * ```\n */\n handler?: (message: QueueMessage<T>) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class QueuePrimitive<T extends TSchema> extends Primitive<\n QueuePrimitiveOptions<T>\n> {\n protected readonly log = $logger();\n protected readonly workerProvider = $inject(WorkerProvider);\n public readonly provider = this.$provider();\n\n public async push(...payloads: Array<Static<T>>) {\n await Promise.all(\n payloads.map((payload) =>\n this.provider.push(\n this.name,\n JSON.stringify({\n headers: {},\n payload: this.alepha.codec.decode(this.options.schema, payload),\n }),\n ),\n ),\n );\n\n this.log.debug(`Pushed to queue ${this.name}`, payloads);\n this.workerProvider.wakeUp();\n }\n\n public get name() {\n return this.options.name || this.config.propertyKey;\n }\n\n protected $provider() {\n if (!this.options.provider) {\n return this.alepha.inject(QueueProvider);\n }\n if (this.options.provider === \"memory\") {\n return this.alepha.inject(MemoryQueueProvider);\n }\n return this.alepha.inject(this.options.provider);\n }\n}\n\n$queue[KIND] = QueuePrimitive;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface QueueMessageSchema {\n payload: TSchema;\n}\n\nexport interface QueueMessage<T extends TSchema> {\n payload: Static<T>;\n}\n","import { $hook, $inject, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { QueueProvider } from \"./QueueProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare Queue interface matching the CF Workers Queue API.\n */\nexport interface CloudflareQueue {\n send(message: unknown): Promise<void>;\n sendBatch(messages: Array<{ body: unknown }>): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Default queue binding name used in wrangler configuration.\n */\nexport const QUEUE_DEFAULT_BINDING = \"JOBS_QUEUE\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare Queue provider.\n *\n * Uses a Queue binding for message dispatch. Messages are wrapped with the\n * logical queue name so the consumer can route them to the correct handler.\n *\n * **Required Cloudflare binding:**\n * - `JOBS_QUEUE` - A Queue binding in wrangler configuration\n *\n * @example\n * ```toml\n * # wrangler.toml - automatically generated by alepha build\n * [[queues.producers]]\n * binding = \"JOBS_QUEUE\"\n * queue = \"my-app-queue\"\n * ```\n */\nexport class CloudflareQueueProvider extends QueueProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n\n protected queue?: CloudflareQueue;\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n const cloudflareEnv = this.alepha.store.get(\"cloudflare.env\") as\n | Record<string, unknown>\n | undefined;\n if (!cloudflareEnv) {\n throw new AlephaError(\n \"Cloudflare Workers environment not found in Alepha store under 'cloudflare.env'.\",\n );\n }\n\n const binding = cloudflareEnv[QUEUE_DEFAULT_BINDING] as\n | CloudflareQueue\n | undefined;\n if (!binding) {\n throw new AlephaError(\n `Queue binding '${QUEUE_DEFAULT_BINDING}' not found in Cloudflare Workers environment.`,\n );\n }\n\n this.queue = binding;\n this.log.info(\"Cloudflare Queue ready\");\n },\n });\n\n public async push(queue: string, message: string): Promise<void> {\n await this.getQueue().send({ queue, message });\n }\n\n /**\n * Not used on Cloudflare — queue consumption is push-based via the `queue` handler.\n */\n public async pop(_queue: string): Promise<string | undefined> {\n return undefined;\n }\n\n protected getQueue(): CloudflareQueue {\n if (!this.queue) {\n throw new AlephaError(\n \"Queue binding not initialized. Call start() first.\",\n );\n }\n return this.queue;\n }\n}\n","import { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $consumer } from \"../primitives/$consumer.ts\";\nimport { $queue } from \"../primitives/$queue.ts\";\nimport { WorkerProvider } from \"./WorkerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare Workers queue consumer provider.\n *\n * Replaces the polling-based `WorkerProvider` in Cloudflare Workers.\n * Instead of running a polling loop, this provider hooks into `cloudflare:queue`\n * events emitted by the CF Workers `queue` handler.\n *\n * @see https://developers.cloudflare.com/queues/\n */\nexport class WorkerdWorkerProvider extends WorkerProvider {\n protected override readonly alepha = $inject(Alepha);\n protected override readonly log = $logger();\n\n /**\n * Override start hook — collect consumers but do NOT start polling workers.\n */\n protected override readonly start = $hook({\n on: \"start\",\n priority: \"last\",\n handler: () => {\n for (const queue of this.alepha.primitives($queue)) {\n const handler = queue.options.handler;\n if (handler) {\n this.consumers.push({ handler, queue });\n }\n }\n\n for (const consumer of this.alepha.primitives($consumer)) {\n this.consumers.push(consumer.options);\n }\n\n if (this.consumers.length > 0) {\n this.log.debug(\n `Registered ${this.consumers.length} queue consumer${this.consumers.length > 1 ? \"s\" : \"\"} for Cloudflare Queue.`,\n );\n }\n },\n });\n\n /**\n * Override stop hook — no workers to stop on Cloudflare.\n */\n protected override readonly stop = $hook({\n on: \"stop\",\n handler: () => {},\n });\n\n /**\n * Handle incoming messages from Cloudflare Queue.\n */\n protected readonly onQueueMessage = $hook({\n on: \"cloudflare:queue\",\n handler: async (event: { queue: string; message: string }) => {\n const consumer = this.consumers.find((c) => c.queue.name === event.queue);\n\n if (!consumer) {\n this.log.warn(\n `No consumer found for queue '${event.queue}', skipping message.`,\n );\n return;\n }\n\n await this.processMessage({ message: event.message, consumer });\n },\n });\n\n /**\n * No-op on Cloudflare — no workers to wake.\n */\n public override wakeUp(): void {}\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { $consumer } from \"./primitives/$consumer.ts\";\nimport { $queue } from \"./primitives/$queue.ts\";\nimport { CloudflareQueueProvider } from \"./providers/CloudflareQueueProvider.ts\";\nimport { MemoryQueueProvider } from \"./providers/MemoryQueueProvider.ts\";\nimport { QueueProvider } from \"./providers/QueueProvider.ts\";\nimport { WorkerdWorkerProvider } from \"./providers/WorkerdWorkerProvider.ts\";\nimport { WorkerProvider } from \"./providers/WorkerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$consumer.ts\";\nexport * from \"./primitives/$queue.ts\";\nexport * from \"./providers/CloudflareQueueProvider.ts\";\nexport * from \"./providers/MemoryQueueProvider.ts\";\nexport * from \"./providers/QueueProvider.ts\";\nexport * from \"./providers/WorkerdWorkerProvider.ts\";\nexport * from \"./providers/WorkerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Cloudflare Workers queue message event.\n *\n * Emitted when a queue consumer receives a message in Cloudflare Workers.\n */\n \"cloudflare:queue\": {\n queue: string;\n message: string;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Asynchronous message processing with automatic worker management.\n *\n * **Features:**\n * - Background job queues with type-safe payloads\n * - Queue consumer handlers\n * - Automatic worker threads for non-blocking processing\n * - Retry mechanisms with exponential backoff\n * - Dead letter queues for failed messages\n * - Batch processing support\n * - Configurable concurrency and worker pools\n * - Providers: Memory (dev), Redis (production), Cloudflare Queue (workerd)\n *\n * @module alepha.queue\n */\nexport const AlephaQueue = $module({\n name: \"alepha.queue\",\n primitives: [$queue, $consumer],\n services: [QueueProvider, WorkerProvider],\n variants: [\n MemoryQueueProvider,\n CloudflareQueueProvider,\n WorkerdWorkerProvider,\n ],\n register: (alepha: Alepha) =>\n alepha\n .with({\n optional: true,\n provide: QueueProvider,\n use: alepha.isTest() ? MemoryQueueProvider : CloudflareQueueProvider,\n })\n .with({\n provide: WorkerProvider,\n use: alepha.isTest() ? WorkerProvider : WorkerdWorkerProvider,\n }),\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.workerd.js","names":[],"sources":["../../../src/queue/core/primitives/$consumer.ts","../../../src/queue/core/providers/MemoryQueueProvider.ts","../../../src/queue/core/providers/QueueProvider.ts","../../../src/queue/core/providers/WorkerProvider.ts","../../../src/queue/core/primitives/$queue.ts","../../../src/queue/core/providers/CloudflareQueueProvider.ts","../../../src/queue/core/providers/WorkerdWorkerProvider.ts","../../../src/queue/core/index.workerd.ts"],"sourcesContent":["import {\n createPrimitive,\n KIND,\n PipelinePrimitive,\n type PipelinePrimitiveOptions,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport type { QueuePrimitive } from \"./$queue.ts\";\n\n/**\n * Creates a consumer primitive to process messages from a specific queue.\n *\n * Provides a dedicated message consumer that connects to a queue and processes messages\n * with custom handler logic, enabling scalable architectures where multiple consumers\n * can process messages from the same queue.\n *\n * **Key Features**\n * - Seamless integration with any $queue primitive\n * - Full type safety inherited from queue schema\n * - Automatic worker management for background processing\n * - Built-in error handling and retry mechanisms\n * - Support for multiple consumers per queue for horizontal scaling\n *\n * **Common Use Cases**\n * - Email sending and notification services\n * - Image and media processing workers\n * - Data synchronization and background jobs\n *\n * @example\n * ```ts\n * class EmailService {\n * emailQueue = $queue({\n * name: \"emails\",\n * schema: z.object({\n * to: z.text(),\n * subject: z.text(),\n * body: z.text()\n * })\n * });\n *\n * emailConsumer = $consumer({\n * queue: this.emailQueue,\n * handler: async (message) => {\n * const { to, subject, body } = message.payload;\n * await this.sendEmail(to, subject, body);\n * }\n * });\n *\n * async sendWelcomeEmail(userEmail: string) {\n * await this.emailQueue.push({\n * to: userEmail,\n * subject: \"Welcome!\",\n * body: \"Thanks for joining.\"\n * });\n * }\n * }\n * ```\n */\nexport const $consumer = <T extends TSchema>(\n options: ConsumerPrimitiveOptions<T>,\n): ConsumerPrimitive<T> => {\n return createPrimitive(ConsumerPrimitive<T>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface ConsumerPrimitiveOptions<T extends TSchema>\n extends PipelinePrimitiveOptions {\n /**\n * The queue primitive that this consumer will process messages from.\n *\n * This establishes the connection between the consumer and its source queue:\n * - The consumer inherits the queue's message schema for type safety\n * - Messages pushed to the queue will be automatically routed to this consumer\n * - Multiple consumers can be attached to the same queue for parallel processing\n * - The consumer will use the queue's provider and configuration settings\n *\n * **Queue Integration Benefits**:\n * - Type safety: Consumer handler gets fully typed message payloads\n * - Schema validation: Messages are validated before reaching the consumer\n * - Error handling: Failed messages can be retried or moved to dead letter queues\n * - Monitoring: Queue metrics include consumer processing statistics\n *\n * @example\n * ```ts\n * // First, define a queue\n * emailQueue = $queue({\n * name: \"emails\",\n * schema: z.object({ to: z.text(), subject: z.text() })\n * });\n *\n * // Then, create a consumer for that queue\n * emailConsumer = $consumer({\n * queue: this.emailQueue, // Reference the queue primitive\n * handler: async (message) => { } // process email\n * });\n * ```\n */\n queue: QueuePrimitive<T>;\n\n /**\n * Message handler function that processes individual messages from the queue.\n *\n * This function:\n * - Receives fully typed and validated message payloads from the connected queue\n * - Runs in the background worker system for non-blocking operation\n * - Should implement the core business logic for processing this message type\n * - Can throw errors to trigger the queue's retry mechanisms\n * - Has access to the full Alepha dependency injection container\n * - Should be idempotent to handle potential duplicate deliveries\n *\n * **Handler Design Guidelines**:\n * - Keep handlers focused on a single responsibility\n * - Use proper error handling and meaningful error messages\n * - Log important processing steps for debugging and monitoring\n * - Consider transaction boundaries for data consistency\n * - Make operations idempotent when possible\n * - Validate business rules within the handler logic\n *\n * **Error Handling Strategy**:\n * - Throw errors for temporary failures that should be retried\n * - Log and handle permanent failures gracefully\n * - Use specific error types to control retry behavior\n * - Consider implementing circuit breakers for external service calls\n *\n * @param message - The queue message containing the validated payload\n * @param message.payload - The typed message data based on the queue's schema\n * @returns Promise that resolves when processing is complete\n *\n * @example\n * ```ts\n * handler: async (message) => {\n * const { userId, action, data } = message.payload;\n *\n * try {\n * // Log processing start\n * this.logger.info(`Processing ${action} for user ${userId}`);\n *\n * // Validate business rules\n * if (!await this.userService.exists(userId)) {\n * throw new Error(`User ${userId} not found`);\n * }\n *\n * // Perform the main processing logic\n * switch (action) {\n * case \"create\":\n * await this.processCreation(userId, data);\n * break;\n * case \"update\":\n * await this.processUpdate(userId, data);\n * break;\n * default:\n * throw new Error(`Unknown action: ${action}`);\n * }\n *\n * // Log successful completion\n * this.logger.info(`Successfully processed ${action} for user ${userId}`);\n *\n * } catch (error) {\n * // Log error with context\n * this.logger.error(`Failed to process ${action} for user ${userId}`, {\n * error: error.message,\n * userId,\n * action,\n * data\n * });\n *\n * // Re-throw to trigger queue retry mechanism\n * throw error;\n * }\n * }\n * ```\n */\n handler: (message: { payload: Static<T> }) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class ConsumerPrimitive<T extends TSchema> extends PipelinePrimitive<\n ConsumerPrimitiveOptions<T>\n> {}\n\n$consumer[KIND] = ConsumerPrimitive;\n","import { $logger } from \"alepha/logger\";\nimport type { QueueProvider } from \"./QueueProvider.ts\";\n\nexport class MemoryQueueProvider implements QueueProvider {\n protected readonly log = $logger();\n protected queueList: Record<string, string[]> = {};\n\n public async push(queue: string, ...messages: string[]): Promise<void> {\n if (this.queueList[queue] == null) {\n this.queueList[queue] = [];\n }\n\n this.queueList[queue].push(...messages);\n }\n\n public async pop(queue: string): Promise<string | undefined> {\n return this.queueList[queue]?.shift();\n }\n}\n","/**\n * Minimalist Queue interface.\n *\n * Will be probably enhanced in the future to support more advanced features. But for now, it's enough!\n */\nexport abstract class QueueProvider {\n /**\n * Push a message to the queue.\n *\n * @param queue Name of the queue to push the message to.\n * @param message String message to be pushed to the queue. Buffer messages are not supported for now.\n */\n public abstract push(queue: string, message: string): Promise<void>;\n\n /**\n * Pop a message from the queue.\n *\n * @param queue Name of the queue to pop the message from.\n *\n * @returns The message popped or `undefined` if the queue is empty.\n */\n public abstract pop(queue: string): Promise<string | undefined>;\n}\n","import {\n $atom,\n $hook,\n $inject,\n $state,\n Alepha,\n type Static,\n type TSchema,\n z,\n} from \"alepha\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $consumer } from \"../primitives/$consumer.ts\";\nimport {\n $queue,\n type QueueMessage,\n type QueuePrimitive,\n} from \"../primitives/$queue.ts\";\nimport { QueueProvider } from \"./QueueProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Queue worker configuration atom.\n */\nexport const queueWorkerOptions = $atom({\n name: \"alepha.queue.worker.options\",\n schema: z.object({\n interval: z\n .integer()\n .describe(\n \"Interval in milliseconds to wait before checking for new messages.\",\n )\n .default(1000),\n maxInterval: z\n .integer()\n .describe(\n \"Maximum interval in milliseconds to wait before checking for new messages.\",\n )\n .default(32000),\n concurrency: z\n .integer()\n .describe(\n \"Number of workers to run concurrently. Useful only if you are doing a lot of I/O.\",\n )\n .default(1),\n }),\n default: {\n interval: 1000,\n maxInterval: 32000,\n concurrency: 1,\n },\n});\n\nexport type QueueWorkerOptions = Static<typeof queueWorkerOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [queueWorkerOptions.key]: QueueWorkerOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class WorkerProvider {\n protected readonly log = $logger();\n protected readonly options = $state(queueWorkerOptions);\n protected readonly alepha = $inject(Alepha);\n protected readonly queueProvider = $inject(QueueProvider);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n protected workerPromises: Array<Promise<void>> = [];\n protected workersRunning = 0;\n protected abortController: AbortController | undefined;\n protected workerIntervals: Record<number, number> = {};\n protected consumers: Array<Consumer> = [];\n protected nextConsumerIndex = 0;\n\n public get isRunning(): boolean {\n return this.workersRunning > 0;\n }\n\n protected readonly start = $hook({\n on: \"start\",\n priority: \"last\",\n handler: () => {\n for (const queue of this.alepha.primitives($queue)) {\n const handler = queue.options.handler;\n if (handler) {\n this.consumers.push({\n handler,\n queue,\n });\n }\n }\n\n for (const consumer of this.alepha.primitives($consumer)) {\n this.consumers.push({\n queue: consumer.options.queue,\n handler: (msg) => consumer.handler.run(msg),\n });\n }\n\n if (this.consumers.length > 0) {\n this.startWorkers();\n this.log.debug(\n `Watching for ${this.consumers.length} queue${this.consumers.length > 1 ? \"s\" : \"\"} with ${this.options.concurrency} worker${\n this.options.concurrency > 1 ? \"s\" : \"\"\n }.`,\n );\n }\n },\n });\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Engine part - this is the part that will run the workers and process the messages\n\n /**\n * Start the workers.\n * This method will create an endless loop that will check for new messages!\n */\n protected startWorkers(): void {\n this.abortController ??= new AbortController();\n const workerToStart = this.options.concurrency - this.workersRunning;\n\n for (let i = 0; i < workerToStart; i++) {\n this.workersRunning += 1;\n this.log.debug(`Starting worker n-${i}`);\n\n const workerLoop = async () => {\n while (this.workersRunning > 0) {\n this.log.trace(`Worker n-${i} is checking for new messages`);\n const next = await this.getNextMessage();\n if (next) {\n this.workerIntervals[i] = 0;\n await this.processMessage(next);\n } else {\n await this.waitForNextMessage(i);\n }\n }\n this.log.info(`Worker n-${i} has stopped`);\n // Only decrement if we're not already at 0 (shutdown case)\n if (this.workersRunning > 0) {\n this.workersRunning -= 1;\n }\n };\n\n this.workerPromises.push(\n workerLoop().catch((e) => {\n this.log.error(`Worker n-${i} has crashed`, e);\n // Always decrement on crash, regardless of shutdown state\n this.workersRunning = Math.max(0, this.workersRunning - 1);\n }),\n );\n }\n }\n\n protected readonly stop = $hook({\n on: \"stop\",\n handler: async () => {\n if (this.consumers.length > 0) {\n await this.stopWorkers();\n }\n },\n });\n\n /**\n * Wait for the next message, where `n` is the worker number.\n *\n * This method will wait for a certain amount of time, increasing the wait time again if no message is found.\n */\n protected async waitForNextMessage(n: number): Promise<void> {\n const intervals = this.workerIntervals;\n const milliseconds = intervals[n] || this.options.interval;\n\n this.log.trace(`Worker n-${n} is waiting for ${milliseconds}ms.`);\n\n if (this.abortController?.signal.aborted) {\n this.log.warn(`Worker n-${n} aborted.`);\n return;\n }\n\n await this.dateTimeProvider.wait(milliseconds, {\n signal: this.abortController?.signal,\n });\n\n if (intervals[n]) {\n if (intervals[n] < this.options.maxInterval) {\n intervals[n] = intervals[n] * 2;\n }\n } else {\n intervals[n] = milliseconds;\n }\n }\n\n /**\n * Get the next message.\n */\n protected async getNextMessage(): Promise<undefined | NextMessage> {\n const len = this.consumers.length;\n for (let i = 0; i < len; i++) {\n const idx = (this.nextConsumerIndex + i) % len;\n const consumer = this.consumers[idx];\n const provider = consumer.queue.provider;\n const message = await provider.pop(consumer.queue.name);\n if (message) {\n this.nextConsumerIndex = (idx + 1) % len;\n return { message, consumer };\n }\n }\n }\n\n /**\n * Process a message from a queue.\n */\n protected async processMessage(response: {\n message: any;\n consumer: Consumer;\n }) {\n const { message, consumer } = response;\n\n try {\n const json = JSON.parse(message);\n const payload = this.alepha.codec.decode(\n consumer.queue.options.schema,\n json.payload,\n );\n await this.alepha.context.run(() => consumer.handler({ payload }));\n } catch (e) {\n this.log.error(\"Failed to process message\", e);\n }\n }\n\n /**\n * Stop the workers.\n *\n * This method will stop the workers and wait for them to finish processing.\n */\n protected async stopWorkers() {\n this.workersRunning = 0;\n\n this.log.trace(\"Stopping workers...\");\n this.abortController?.abort();\n\n this.log.trace(\"Waiting for workers to finish...\");\n await Promise.all(this.workerPromises);\n }\n\n /**\n * Force the workers to get back to work.\n */\n public wakeUp(): void {\n this.log.debug(\"Waking up workers...\");\n this.abortController?.abort();\n this.abortController = new AbortController();\n\n // if no workers are running, start them, (should not happen, but just in case)\n this.startWorkers();\n }\n}\n\nexport interface Consumer<T extends TSchema = TSchema> {\n queue: QueuePrimitive<T>;\n handler: (message: QueueMessage<T>) => Promise<void>;\n}\n\nexport interface NextMessage {\n consumer: Consumer;\n message: string;\n}\n","import {\n $inject,\n createPrimitive,\n KIND,\n Primitive,\n type Service,\n type Static,\n type TSchema,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { MemoryQueueProvider } from \"../providers/MemoryQueueProvider.ts\";\nimport { QueueProvider } from \"../providers/QueueProvider.ts\";\nimport { WorkerProvider } from \"../providers/WorkerProvider.ts\";\n\n/**\n * Creates a queue primitive for asynchronous message processing with background workers.\n *\n * `$queue` is the **raw transport layer**: it fans messages out to background\n * workers over the configured backend with type-safe payloads. Delivery is\n * **at-most-once** — a message is popped from the backend before the handler\n * runs, so a handler error or a process crash loses it. There is no retry,\n * no dead-letter queue, and no delivery guarantee at this layer.\n *\n * **For work that must not be lost, use `$job` (alepha/api/jobs) instead.**\n * It layers a durable, DB-backed outbox over this transport: at-least-once\n * delivery, retries, idempotency keys, priorities, crash recovery via a\n * reconciliation sweep, and failure records.\n *\n * **What $queue gives you**\n * - Type-safe payloads with schema validation at push and receive\n * - Background workers with graceful shutdown and lifecycle management\n * - Pluggable backends: memory (dev/test), Redis, Cloudflare Queues\n * - Cheap fire-and-forget fan-out where occasional loss is acceptable\n * (cache invalidation, presence pings, metrics, live notifications)\n *\n * @example Loss-tolerant event fan-out\n * ```typescript\n * const activityQueue = $queue({\n * name: \"activity-events\",\n * schema: z.object({\n * userId: z.text(),\n * event: z.text(),\n * at: z.number()\n * }),\n * handler: async (message) => {\n * await metrics.track(message.payload);\n * }\n * });\n *\n * // Push messages for background processing\n * await activityQueue.push({\n * userId: \"u1\",\n * event: \"page-view\",\n * at: 1700000000000\n * });\n * ```\n *\n * @example Batch processing with Redis\n * ```typescript\n * const imageQueue = $queue({\n * name: \"image-processing\",\n * provider: RedisQueueProvider,\n * schema: z.object({\n * imageId: z.text(),\n * operations: z.array(z.enum([\"resize\", \"compress\", \"thumbnail\"]))\n * }),\n * handler: async (message) => {\n * for (const op of message.payload.operations) {\n * await processImage(message.payload.imageId, op);\n * }\n * }\n * });\n *\n * // Batch processing multiple images\n * await imageQueue.push(\n * { imageId: \"img1\", operations: [\"resize\", \"thumbnail\"] },\n * { imageId: \"img2\", operations: [\"compress\"] },\n * { imageId: \"img3\", operations: [\"resize\", \"compress\", \"thumbnail\"] }\n * );\n * ```\n *\n * @example Development with memory provider\n * ```typescript\n * const taskQueue = $queue({\n * name: \"dev-tasks\",\n * provider: \"memory\",\n * schema: z.object({\n * taskType: z.enum([\"cleanup\", \"backup\", \"report\"]),\n * data: z.record(z.text(), z.any())\n * }),\n * handler: async (message) => {\n * switch (message.payload.taskType) {\n * case \"cleanup\":\n * await performCleanup(message.payload.data);\n * break;\n * case \"backup\":\n * await createBackup(message.payload.data);\n * break;\n * case \"report\":\n * await generateReport(message.payload.data);\n * break;\n * }\n * }\n * });\n * ```\n */\nexport const $queue = <T extends TSchema>(\n options: QueuePrimitiveOptions<T>,\n): QueuePrimitive<T> => {\n return createPrimitive(QueuePrimitive<T>, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface QueuePrimitiveOptions<T extends TSchema> {\n /**\n * Unique name for the queue.\n *\n * This name is used for:\n * - Queue identification across the system\n * - Storage backend key generation\n * - Logging and monitoring\n * - Worker assignment and routing\n *\n * If not provided, defaults to the property key where the queue is declared.\n *\n * @example \"email-notifications\"\n * @example \"image-processing\"\n * @example \"order-fulfillment\"\n */\n name?: string;\n\n /**\n * Human-readable description of the queue's purpose.\n *\n * Used for:\n * - Documentation generation\n * - Monitoring dashboards\n * - Development team communication\n * - Queue management interfaces\n *\n * @example \"Process user registration emails and welcome sequences\"\n * @example \"Handle image uploads, resizing, and thumbnail generation\"\n * @example \"Manage order processing, payment, and shipping workflows\"\n */\n description?: string;\n\n /**\n * Queue storage provider configuration.\n *\n * Options:\n * - **\"memory\"**: In-memory queue (default for development, lost on restart)\n * - **Service<QueueProvider>**: Custom provider class (e.g., RedisQueueProvider)\n * - **undefined**: Uses the default queue provider from dependency injection\n *\n * **Provider Selection Guidelines**:\n * - Development: Use \"memory\" for fast, simple testing\n * - Production: Use Redis so multiple instances share one queue (note:\n * a popped message is gone — the at-most-once caveat above applies)\n * - High-throughput: Use specialized providers with connection pooling\n * - Distributed systems: Use Redis or message brokers for scalability\n *\n * @default Uses injected QueueProvider\n * @example \"memory\"\n * @example RedisQueueProvider\n * @example DatabaseQueueProvider\n */\n provider?: \"memory\" | Service<QueueProvider>;\n\n /**\n * TypeBox schema defining the structure of messages in this queue.\n *\n * This schema:\n * - Validates all messages pushed to the queue\n * - Provides full TypeScript type inference\n * - Ensures type safety between producers and consumers\n * - Enables automatic serialization/deserialization\n *\n * **Schema Design Best Practices**:\n * - Keep schemas simple and focused on the specific task\n * - Use optional fields for data that might not always be available\n * - Include version fields for schema evolution\n * - Use union types for different message types in the same queue\n *\n * @example\n * ```ts\n * z.object({\n * userId: z.text(),\n * action: z.enum([\"create\", \"update\"]),\n * data: z.record(z.text(), z.any()),\n * timestamp: z.number().optional()\n * })\n * ```\n */\n schema: T;\n\n /**\n * Message handler function that processes queue messages.\n *\n * This function:\n * - Runs in background worker threads for non-blocking processing\n * - Receives type-safe message payloads based on the schema\n * - Has access to the full Alepha dependency injection container\n * - **Loses the message if it throws** — errors are logged, not retried.\n * Use `$job` when failed work must be retried or recorded.\n *\n * **Handler Best Practices**:\n * - Keep handlers focused on a single responsibility\n * - Use proper error handling and logging\n * - Make operations idempotent when possible\n * - Validate critical business logic within handlers\n * - Consider using transactions for data consistency\n *\n * @param message - The queue message with validated payload\n * @returns Promise that resolves when processing is complete\n *\n * @example\n * ```ts\n * handler: async (message) => {\n * const { userId, email, template } = message.payload;\n *\n * try {\n * await this.emailService.send({\n * to: email,\n * template,\n * data: { userId }\n * });\n *\n * await this.userService.markEmailSent(userId, template);\n * } catch (error) {\n * // The message is NOT redelivered after a throw — record the\n * // failure yourself, or use $job for retryable work.\n * this.logger.error(`Failed to send email to ${email}`, error);\n * throw error;\n * }\n * }\n * ```\n */\n handler?: (message: QueueMessage<T>) => Promise<void>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class QueuePrimitive<T extends TSchema> extends Primitive<\n QueuePrimitiveOptions<T>\n> {\n protected readonly log = $logger();\n protected readonly workerProvider = $inject(WorkerProvider);\n public readonly provider = this.$provider();\n\n public async push(...payloads: Array<Static<T>>) {\n await Promise.all(\n payloads.map((payload) =>\n this.provider.push(\n this.name,\n JSON.stringify({\n headers: {},\n payload: this.alepha.codec.decode(this.options.schema, payload),\n }),\n ),\n ),\n );\n\n this.log.debug(`Pushed to queue ${this.name}`, payloads);\n this.workerProvider.wakeUp();\n }\n\n public get name() {\n return this.options.name || this.config.propertyKey;\n }\n\n protected $provider() {\n if (!this.options.provider) {\n return this.alepha.inject(QueueProvider);\n }\n if (this.options.provider === \"memory\") {\n return this.alepha.inject(MemoryQueueProvider);\n }\n return this.alepha.inject(this.options.provider);\n }\n}\n\n$queue[KIND] = QueuePrimitive;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface QueueMessageSchema {\n payload: TSchema;\n}\n\nexport interface QueueMessage<T extends TSchema> {\n payload: Static<T>;\n}\n","import { $hook, $inject, Alepha, AlephaError } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { QueueProvider } from \"./QueueProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare Queue interface matching the CF Workers Queue API.\n */\nexport interface CloudflareQueue {\n send(message: unknown): Promise<void>;\n sendBatch(messages: Array<{ body: unknown }>): Promise<void>;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Default queue binding name used in wrangler configuration.\n */\nexport const QUEUE_DEFAULT_BINDING = \"JOBS_QUEUE\";\n\n/**\n * How many times Cloudflare redelivers a message before routing it to the\n * consumer's dead-letter queue. Matches Cloudflare's own default.\n */\nexport const QUEUE_DEFAULT_MAX_RETRIES = 3;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare Queue provider.\n *\n * Uses a Queue binding for message dispatch. Messages are wrapped with the\n * logical queue name so the consumer can route them to the correct handler.\n *\n * **Required Cloudflare binding:**\n * - `JOBS_QUEUE` - A Queue binding in wrangler configuration\n *\n * @example\n * ```toml\n * # wrangler.toml - automatically generated by alepha build\n * [[queues.producers]]\n * binding = \"JOBS_QUEUE\"\n * queue = \"my-app-queue\"\n * ```\n */\nexport class CloudflareQueueProvider extends QueueProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n\n protected queue?: CloudflareQueue;\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n const cloudflareEnv = this.alepha.store.get(\"cloudflare.env\") as\n | Record<string, unknown>\n | undefined;\n if (!cloudflareEnv) {\n throw new AlephaError(\n \"Cloudflare Workers environment not found in Alepha store under 'cloudflare.env'.\",\n );\n }\n\n const binding = cloudflareEnv[QUEUE_DEFAULT_BINDING] as\n | CloudflareQueue\n | undefined;\n if (!binding) {\n throw new AlephaError(\n `Queue binding '${QUEUE_DEFAULT_BINDING}' not found in Cloudflare Workers environment.`,\n );\n }\n\n this.queue = binding;\n this.log.info(\"Cloudflare Queue ready\");\n },\n });\n\n public async push(queue: string, message: string): Promise<void> {\n await this.getQueue().send({ queue, message });\n }\n\n /**\n * Not used on Cloudflare — queue consumption is push-based via the `queue` handler.\n */\n public async pop(_queue: string): Promise<string | undefined> {\n return undefined;\n }\n\n protected getQueue(): CloudflareQueue {\n if (!this.queue) {\n throw new AlephaError(\n \"Queue binding not initialized. Call start() first.\",\n );\n }\n return this.queue;\n }\n}\n","import { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $consumer } from \"../primitives/$consumer.ts\";\nimport { $queue } from \"../primitives/$queue.ts\";\nimport { WorkerProvider } from \"./WorkerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare Workers queue consumer provider.\n *\n * Replaces the polling-based `WorkerProvider` in Cloudflare Workers.\n * Instead of running a polling loop, this provider hooks into `cloudflare:queue`\n * events emitted by the CF Workers `queue` handler.\n *\n * @see https://developers.cloudflare.com/queues/\n */\nexport class WorkerdWorkerProvider extends WorkerProvider {\n protected override readonly alepha = $inject(Alepha);\n protected override readonly log = $logger();\n\n /**\n * Override start hook — collect consumers but do NOT start polling workers.\n */\n protected override readonly start = $hook({\n on: \"start\",\n priority: \"last\",\n handler: () => {\n for (const queue of this.alepha.primitives($queue)) {\n const handler = queue.options.handler;\n if (handler) {\n this.consumers.push({ handler, queue });\n }\n }\n\n for (const consumer of this.alepha.primitives($consumer)) {\n this.consumers.push(consumer.options);\n }\n\n if (this.consumers.length > 0) {\n this.log.debug(\n `Registered ${this.consumers.length} queue consumer${this.consumers.length > 1 ? \"s\" : \"\"} for Cloudflare Queue.`,\n );\n }\n },\n });\n\n /**\n * Override stop hook — no workers to stop on Cloudflare.\n */\n protected override readonly stop = $hook({\n on: \"stop\",\n handler: () => {},\n });\n\n /**\n * Handle incoming messages from Cloudflare Queue.\n */\n protected readonly onQueueMessage = $hook({\n on: \"cloudflare:queue\",\n handler: async (event: { queue: string; message: string }) => {\n const consumer = this.consumers.find((c) => c.queue.name === event.queue);\n\n if (!consumer) {\n this.log.warn(\n `No consumer found for queue '${event.queue}', skipping message.`,\n );\n return;\n }\n\n await this.processMessage({ message: event.message, consumer });\n },\n });\n\n /**\n * No-op on Cloudflare — no workers to wake.\n */\n public override wakeUp(): void {}\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { $consumer } from \"./primitives/$consumer.ts\";\nimport { $queue } from \"./primitives/$queue.ts\";\nimport { CloudflareQueueProvider } from \"./providers/CloudflareQueueProvider.ts\";\nimport { MemoryQueueProvider } from \"./providers/MemoryQueueProvider.ts\";\nimport { QueueProvider } from \"./providers/QueueProvider.ts\";\nimport { WorkerdWorkerProvider } from \"./providers/WorkerdWorkerProvider.ts\";\nimport { WorkerProvider } from \"./providers/WorkerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./primitives/$consumer.ts\";\nexport * from \"./primitives/$queue.ts\";\nexport * from \"./providers/CloudflareQueueProvider.ts\";\nexport * from \"./providers/MemoryQueueProvider.ts\";\nexport * from \"./providers/QueueProvider.ts\";\nexport * from \"./providers/WorkerdWorkerProvider.ts\";\nexport * from \"./providers/WorkerProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Cloudflare Workers queue message event.\n *\n * Emitted when a queue consumer receives a message in Cloudflare Workers.\n */\n \"cloudflare:queue\": {\n queue: string;\n message: string;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Asynchronous message processing with automatic worker management.\n *\n * **Features:**\n * - Background job queues with type-safe payloads\n * - Queue consumer handlers\n * - Automatic worker threads for non-blocking processing\n * - Retry mechanisms with exponential backoff\n * - Dead letter queues for failed messages\n * - Batch processing support\n * - Configurable concurrency and worker pools\n * - Providers: Memory (dev), Redis (production), Cloudflare Queue (workerd)\n *\n * @module alepha.queue\n */\nexport const AlephaQueue = $module({\n name: \"alepha.queue\",\n primitives: [$queue, $consumer],\n services: [QueueProvider, WorkerProvider],\n variants: [\n MemoryQueueProvider,\n CloudflareQueueProvider,\n WorkerdWorkerProvider,\n ],\n register: (alepha: Alepha) =>\n alepha\n .with({\n optional: true,\n provide: QueueProvider,\n use: alepha.isTest() ? MemoryQueueProvider : CloudflareQueueProvider,\n })\n .with({\n provide: WorkerProvider,\n use: alepha.isTest() ? WorkerProvider : WorkerdWorkerProvider,\n }),\n});\n"],"mappings":"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"}
|
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
import { Static } from "alepha";
|
|
2
2
|
import { QueueProvider } from "alepha/queue";
|
|
3
3
|
import { RedisProvider } from "alepha/redis";
|
|
4
|
-
|
|
5
4
|
//#region ../../src/queue/redis/providers/RedisQueueProvider.d.ts
|
|
6
5
|
/**
|
|
7
6
|
* Redis queue configuration atom.
|
|
8
7
|
*/
|
|
9
|
-
declare const redisQueueOptions: import("alepha").Atom<import("
|
|
10
|
-
prefix: import("
|
|
11
|
-
}>, "alepha.queue.redis.options">;
|
|
8
|
+
declare const redisQueueOptions: import("alepha").Atom<import("zod").ZodObject<{
|
|
9
|
+
prefix: import("zod").ZodString;
|
|
10
|
+
}, import("zod/v4/core").$strip>, "alepha.queue.redis.options">;
|
|
12
11
|
type RedisQueueOptions = Static<typeof redisQueueOptions.schema>;
|
|
13
12
|
declare module "alepha" {
|
|
14
13
|
interface State {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/queue/redis/providers/RedisQueueProvider.ts","../../../src/queue/redis/index.ts"],"mappings":";;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/queue/redis/providers/RedisQueueProvider.ts","../../../src/queue/redis/index.ts"],"mappings":";;;;;;;cASa,oCAAiB,mBAAA;;;KAalB,oBAAoB,cAAc,kBAAkB;;YAGpD;KACP,kBAAkB,MAAM;;;cAMhB,8BAA8B;qBACtB,SAAO;;;qBACP,eAAe;EAE3B,OAAO;EAID,KAAK,eAAe,kBAAkB;EAItC,IAAI,gBAAgB;;;;;;;;;;cC5BtB,mCAAgB,yBAAA"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $atom, $inject, $module, $state,
|
|
1
|
+
import { $atom, $inject, $module, $state, z } from "alepha";
|
|
2
2
|
import { AlephaQueue, QueueProvider } from "alepha/queue";
|
|
3
3
|
import { RedisProvider } from "alepha/redis";
|
|
4
4
|
//#region ../../src/queue/redis/providers/RedisQueueProvider.ts
|
|
@@ -7,7 +7,7 @@ import { RedisProvider } from "alepha/redis";
|
|
|
7
7
|
*/
|
|
8
8
|
const redisQueueOptions = $atom({
|
|
9
9
|
name: "alepha.queue.redis.options",
|
|
10
|
-
schema:
|
|
10
|
+
schema: z.object({ prefix: z.text({
|
|
11
11
|
default: "queue",
|
|
12
12
|
description: "Prefix for all queue keys in Redis."
|
|
13
13
|
}) }),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/queue/redis/providers/RedisQueueProvider.ts","../../../src/queue/redis/index.ts"],"sourcesContent":["import { $atom, $inject, $state, type Static,
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/queue/redis/providers/RedisQueueProvider.ts","../../../src/queue/redis/index.ts"],"sourcesContent":["import { $atom, $inject, $state, type Static, z } from \"alepha\";\nimport type { QueueProvider } from \"alepha/queue\";\nimport { RedisProvider } from \"alepha/redis\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Redis queue configuration atom.\n */\nexport const redisQueueOptions = $atom({\n name: \"alepha.queue.redis.options\",\n schema: z.object({\n prefix: z.text({\n default: \"queue\",\n description: \"Prefix for all queue keys in Redis.\",\n }),\n }),\n default: {\n prefix: \"queue\",\n },\n});\n\nexport type RedisQueueOptions = Static<typeof redisQueueOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [redisQueueOptions.key]: RedisQueueOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class RedisQueueProvider implements QueueProvider {\n protected readonly options = $state(redisQueueOptions);\n protected readonly redisProvider: RedisProvider = $inject(RedisProvider);\n\n public prefix(queue: string): string {\n return `${this.options.prefix}:${queue}`;\n }\n\n public async push(queue: string, message: string): Promise<void> {\n await this.redisProvider.lpush(this.prefix(queue), message);\n }\n\n public async pop(queue: string): Promise<string | undefined> {\n return this.redisProvider.rpop(this.prefix(queue));\n }\n}\n","import { $module, type Alepha } from \"alepha\";\nimport { AlephaQueue, QueueProvider } from \"alepha/queue\";\nimport { RedisQueueProvider } from \"./providers/RedisQueueProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./providers/RedisQueueProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Plugin for Alepha Queue that provides Redis queue capabilities.\n *\n * @see {@link RedisQueueProvider}\n * @module alepha.queue.redis\n */\nexport const AlephaQueueRedis = $module({\n name: \"alepha.queue.redis\",\n services: [RedisQueueProvider],\n register: (alepha: Alepha) =>\n alepha\n .with({\n optional: true,\n provide: QueueProvider,\n use: RedisQueueProvider,\n })\n .with(AlephaQueue),\n});\n"],"mappings":";;;;;;;AASA,MAAa,oBAAoB,MAAM;CACrC,MAAM;CACN,QAAQ,EAAE,OAAO,EACf,QAAQ,EAAE,KAAK;EACb,SAAS;EACT,aAAa;CACf,CAAC,EACH,CAAC;CACD,SAAS,EACP,QAAQ,QACV;AACF,CAAC;AAYD,IAAa,qBAAb,MAAyD;CACvD,UAA6B,OAAO,iBAAiB;CACrD,gBAAkD,QAAQ,aAAa;CAEvE,OAAc,OAAuB;EACnC,OAAO,GAAG,KAAK,QAAQ,OAAO,GAAG;CACnC;CAEA,MAAa,KAAK,OAAe,SAAgC;EAC/D,MAAM,KAAK,cAAc,MAAM,KAAK,OAAO,KAAK,GAAG,OAAO;CAC5D;CAEA,MAAa,IAAI,OAA4C;EAC3D,OAAO,KAAK,cAAc,KAAK,KAAK,OAAO,KAAK,CAAC;CACnD;AACF;;;;;;;;;AC/BA,MAAa,mBAAmB,QAAQ;CACtC,MAAM;CACN,UAAU,CAAC,kBAAkB;CAC7B,WAAW,WACT,OACG,KAAK;EACJ,UAAU;EACV,SAAS;EACT,KAAK;CACP,CAAC,CAAC,CACD,KAAK,WAAW;AACvB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.browser.js","names":[],"sources":["../../../src/react/auth/services/ReactAuth.ts","../../../src/react/auth/hooks/useAuth.ts","../../../src/react/auth/index.browser.ts"],"sourcesContent":["import { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { ReactBrowserProvider, Redirection } from \"alepha/react/router\";\nimport { currentUserAtom, type UserAccountToken } from \"alepha/security\";\nimport { HttpClient } from \"alepha/server\";\nimport {\n alephaServerAuthRoutes,\n type Tokens,\n tokenResponseSchema,\n userinfoResponseSchema,\n} from \"alepha/server/auth\";\nimport { LinkProvider } from \"alepha/server/links\";\n\n/**\n * Browser, SSR friendly, service to handle authentication.\n */\nexport class ReactAuth {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n protected readonly linkProvider = $inject(LinkProvider);\n\n protected readonly onBeginTransition = $hook({\n on: \"react:transition:begin\",\n handler: async (event) => {\n if (this.alepha.isBrowser()) {\n Object.defineProperty(event.state, \"user\", {\n get: () => this.user,\n });\n }\n },\n });\n\n protected readonly onFetchRequest = $hook({\n on: \"client:onRequest\",\n handler: async ({ request }) => {\n if (this.alepha.isBrowser() && this.user) {\n // ensure cookies are sent with requests and refresh-able\n request.credentials ??= \"include\";\n }\n },\n });\n\n /**\n * Get the current authenticated user.\n *\n * Alias for `alepha.state.get(\"user\")`\n */\n public get user(): UserAccountToken | undefined {\n return this.alepha.store.get(currentUserAtom) as\n | UserAccountToken\n | undefined;\n }\n\n public async ping() {\n const { data } = await this.httpClient.fetch(\n alephaServerAuthRoutes.userinfo,\n {\n schema: { response: userinfoResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data.user;\n }\n\n public can(action: string): boolean {\n if (!this.user) {\n return false;\n }\n\n return this.linkProvider.can(action);\n }\n\n public async login(\n provider: string,\n options: {\n hostname?: string;\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n },\n ): Promise<Tokens> {\n const realmParam = options.realm\n ? `&realm=${encodeURIComponent(options.realm)}`\n : \"\";\n\n if (options.username || options.password) {\n const { data } = await this.httpClient.fetch(\n `${options.hostname || \"\"}${alephaServerAuthRoutes.token}?provider=${provider}${realmParam}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n username: options.username,\n password: options.password,\n }),\n schema: { response: tokenResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data;\n }\n\n if (this.alepha.isBrowser()) {\n const browser = this.alepha.inject(ReactBrowserProvider);\n const redirect =\n options.redirect ||\n (browser.transitioning\n ? window.location.origin + browser.transitioning.to\n : window.location.href);\n\n const href = `${window.location.origin}${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${encodeURIComponent(redirect)}`;\n\n if (browser.transitioning) {\n throw new Redirection(href);\n } else {\n window.location.href = href;\n return {} as Tokens;\n }\n }\n\n throw new Redirection(\n `${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${options.redirect || \"/\"}`,\n );\n }\n\n public logout() {\n const form = document.createElement(\"form\");\n form.method = \"POST\";\n form.action = `${alephaServerAuthRoutes.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;\n form.style.display = \"none\";\n document.body.appendChild(form);\n form.submit();\n }\n}\n","import { useAlepha, useStore } from \"alepha/react\";\nimport { currentUserAtom } from \"alepha/security\";\nimport { LinkProvider } from \"alepha/server/links\";\nimport { ReactAuth } from \"../services/ReactAuth.ts\";\n\nexport const useAuth = <T extends object = any>() => {\n const alepha = useAlepha();\n const [user] = useStore(currentUserAtom);\n\n return {\n user,\n logout: () => {\n alepha.inject(ReactAuth).logout();\n },\n login: async (\n provider: keyof T,\n options: {\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n } = {},\n ) => {\n await alepha.inject(ReactAuth).login(provider as string, options);\n },\n /**\n * UI permission check — does the current user hold this permission?\n * Supports exact and wildcard names (e.g. `\"admin:*\"`, `\"admin:user:read\"`).\n *\n * UI affordance only (show/hide/disable). Real access control is enforced\n * server-side via `$secure` on the route/action.\n */\n has: (permission: string): boolean => {\n return alepha.inject(LinkProvider).can(permission);\n },\n };\n};\n","import { $module } from \"alepha\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n services: [ReactAuth],\n});\n"],"mappings":";;;;;;;;;;;;AAgBA,IAAa,YAAb,MAAuB;CACrB,MAAyB,QAAQ;CACjC,SAA4B,QAAQ,MAAM;CAC1C,aAAgC,QAAQ,UAAU;CAClD,eAAkC,QAAQ,YAAY;CAEtD,oBAAuC,MAAM;EAC3C,IAAI;EACJ,SAAS,OAAO,UAAU;GACxB,IAAI,KAAK,OAAO,UAAU,GACxB,OAAO,eAAe,MAAM,OAAO,QAAQ,EACzC,WAAW,KAAK,KAClB,CAAC;EAEL;CACF,CAAC;CAED,iBAAoC,MAAM;EACxC,IAAI;EACJ,SAAS,OAAO,EAAE,cAAc;GAC9B,IAAI,KAAK,OAAO,UAAU,KAAK,KAAK,MAElC,QAAQ,gBAAgB;EAE5B;CACF,CAAC;;;;;;CAOD,IAAW,OAAqC;EAC9C,OAAO,KAAK,OAAO,MAAM,IAAI,eAAe;CAG9C;CAEA,MAAa,OAAO;EAClB,MAAM,EAAE,SAAS,MAAM,KAAK,WAAW,MACrC,uBAAuB,UACvB,EACE,QAAQ,EAAE,UAAU,uBAAuB,EAC7C,CACF;EAEA,KAAK,OAAO,MAAM,IAAI,kCAAkC,KAAK,GAAG;EAChE,KAAK,OAAO,MAAM,IAAI,iBAAiB,KAAK,IAAI;EAEhD,OAAO,KAAK;CACd;CAEA,IAAW,QAAyB;EAClC,IAAI,CAAC,KAAK,MACR,OAAO;EAGT,OAAO,KAAK,aAAa,IAAI,MAAM;CACrC;CAEA,MAAa,MACX,UACA,SAQiB;EACjB,MAAM,aAAa,QAAQ,QACvB,UAAU,mBAAmB,QAAQ,KAAK,MAC1C;EAEJ,IAAI,QAAQ,YAAY,QAAQ,UAAU;GACxC,MAAM,EAAE,SAAS,MAAM,KAAK,WAAW,MACrC,GAAG,QAAQ,YAAY,KAAK,uBAAuB,MAAM,YAAY,WAAW,cAChF;IACE,QAAQ;IACR,MAAM,KAAK,UAAU;KACnB,UAAU,QAAQ;KAClB,UAAU,QAAQ;IACpB,CAAC;IACD,QAAQ,EAAE,UAAU,oBAAoB;GAC1C,CACF;GAEA,KAAK,OAAO,MAAM,IAAI,kCAAkC,KAAK,GAAG;GAChE,KAAK,OAAO,MAAM,IAAI,iBAAiB,KAAK,IAAI;GAEhD,OAAO;EACT;EAEA,IAAI,KAAK,OAAO,UAAU,GAAG;GAC3B,MAAM,UAAU,KAAK,OAAO,OAAO,oBAAoB;GACvD,MAAM,WACJ,QAAQ,aACP,QAAQ,gBACL,OAAO,SAAS,SAAS,QAAQ,cAAc,KAC/C,OAAO,SAAS;GAEtB,MAAM,OAAO,GAAG,OAAO,SAAS,SAAS,uBAAuB,MAAM,YAAY,WAAW,WAAW,gBAAgB,mBAAmB,QAAQ;GAEnJ,IAAI,QAAQ,eACV,MAAM,IAAI,YAAY,IAAI;QACrB;IACL,OAAO,SAAS,OAAO;IACvB,OAAO,CAAC;GACV;EACF;EAEA,MAAM,IAAI,YACR,GAAG,uBAAuB,MAAM,YAAY,WAAW,WAAW,gBAAgB,QAAQ,YAAY,KACxG;CACF;CAEA,SAAgB;EACd,MAAM,OAAO,SAAS,cAAc,MAAM;EAC1C,KAAK,SAAS;EACd,KAAK,SAAS,GAAG,uBAAuB,OAAO,4BAA4B,mBAAmB,OAAO,SAAS,MAAM;EACpH,KAAK,MAAM,UAAU;EACrB,SAAS,KAAK,YAAY,IAAI;EAC9B,KAAK,OAAO;CACd;AACF;;;ACxIA,MAAa,gBAAwC;CACnD,MAAM,SAAS,UAAU;CACzB,MAAM,CAAC,QAAQ,SAAS,eAAe;CAEvC,OAAO;EACL;EACA,cAAc;GACZ,OAAO,OAAO,SAAS,
|
|
1
|
+
{"version":3,"file":"index.browser.js","names":[],"sources":["../../../src/react/auth/services/ReactAuth.ts","../../../src/react/auth/hooks/useAuth.ts","../../../src/react/auth/index.browser.ts"],"sourcesContent":["import { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { ReactBrowserProvider, Redirection } from \"alepha/react/router\";\nimport { currentUserAtom, type UserAccountToken } from \"alepha/security\";\nimport { HttpClient } from \"alepha/server\";\nimport {\n alephaServerAuthRoutes,\n type Tokens,\n tokenResponseSchema,\n userinfoResponseSchema,\n} from \"alepha/server/auth\";\nimport { LinkProvider } from \"alepha/server/links\";\n\n/**\n * Browser, SSR friendly, service to handle authentication.\n */\nexport class ReactAuth {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n protected readonly linkProvider = $inject(LinkProvider);\n\n protected readonly onBeginTransition = $hook({\n on: \"react:transition:begin\",\n handler: async (event) => {\n if (this.alepha.isBrowser()) {\n Object.defineProperty(event.state, \"user\", {\n get: () => this.user,\n });\n }\n },\n });\n\n protected readonly onFetchRequest = $hook({\n on: \"client:onRequest\",\n handler: async ({ request }) => {\n if (this.alepha.isBrowser() && this.user) {\n // ensure cookies are sent with requests and refresh-able\n request.credentials ??= \"include\";\n }\n },\n });\n\n /**\n * Get the current authenticated user.\n *\n * Alias for `alepha.state.get(\"user\")`\n */\n public get user(): UserAccountToken | undefined {\n return this.alepha.store.get(currentUserAtom) as\n | UserAccountToken\n | undefined;\n }\n\n public async ping() {\n const { data } = await this.httpClient.fetch(\n alephaServerAuthRoutes.userinfo,\n {\n schema: { response: userinfoResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data.user;\n }\n\n public can(action: string): boolean {\n if (!this.user) {\n return false;\n }\n\n return this.linkProvider.can(action);\n }\n\n public async login(\n provider: string,\n options: {\n hostname?: string;\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n },\n ): Promise<Tokens> {\n const realmParam = options.realm\n ? `&realm=${encodeURIComponent(options.realm)}`\n : \"\";\n\n if (options.username || options.password) {\n const { data } = await this.httpClient.fetch(\n `${options.hostname || \"\"}${alephaServerAuthRoutes.token}?provider=${provider}${realmParam}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n username: options.username,\n password: options.password,\n }),\n schema: { response: tokenResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data;\n }\n\n if (this.alepha.isBrowser()) {\n const browser = this.alepha.inject(ReactBrowserProvider);\n const redirect =\n options.redirect ||\n (browser.transitioning\n ? window.location.origin + browser.transitioning.to\n : window.location.href);\n\n const href = `${window.location.origin}${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${encodeURIComponent(redirect)}`;\n\n if (browser.transitioning) {\n throw new Redirection(href);\n } else {\n window.location.href = href;\n return {} as Tokens;\n }\n }\n\n throw new Redirection(\n `${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${options.redirect || \"/\"}`,\n );\n }\n\n public logout() {\n const form = document.createElement(\"form\");\n form.method = \"POST\";\n form.action = `${alephaServerAuthRoutes.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;\n form.style.display = \"none\";\n document.body.appendChild(form);\n form.submit();\n }\n}\n","import { useAlepha, useStore } from \"alepha/react\";\nimport { currentUserAtom } from \"alepha/security\";\nimport { LinkProvider } from \"alepha/server/links\";\nimport { ReactAuth } from \"../services/ReactAuth.ts\";\n\nexport const useAuth = <T extends object = any>() => {\n const alepha = useAlepha();\n const [user] = useStore(currentUserAtom);\n\n return {\n user,\n logout: () => {\n alepha.inject(ReactAuth).logout();\n },\n login: async (\n provider: keyof T,\n options: {\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n } = {},\n ) => {\n await alepha.inject(ReactAuth).login(provider as string, options);\n },\n /**\n * UI permission check — does the current user hold this permission?\n * Supports exact and wildcard names (e.g. `\"admin:*\"`, `\"admin:user:read\"`).\n *\n * UI affordance only (show/hide/disable). Real access control is enforced\n * server-side via `$secure` on the route/action.\n */\n has: (permission: string): boolean => {\n return alepha.inject(LinkProvider).can(permission);\n },\n };\n};\n","import { $module } from \"alepha\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n services: [ReactAuth],\n});\n"],"mappings":"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"}
|
|
@@ -3,11 +3,13 @@ import { Tokens } from "alepha/server/auth";
|
|
|
3
3
|
import { LinkProvider } from "alepha/server/links";
|
|
4
4
|
import { UserAccount, UserAccountToken } from "alepha/security";
|
|
5
5
|
import { HttpClient } from "alepha/server";
|
|
6
|
-
|
|
7
6
|
//#region ../../src/react/auth/hooks/useAuth.d.ts
|
|
8
7
|
declare const useAuth: <T extends object = any>() => {
|
|
9
8
|
user: {
|
|
9
|
+
id: string;
|
|
10
10
|
name?: string | undefined;
|
|
11
|
+
firstName?: string | undefined;
|
|
12
|
+
lastName?: string | undefined;
|
|
11
13
|
email?: string | undefined;
|
|
12
14
|
username?: string | undefined;
|
|
13
15
|
picture?: string | undefined;
|
|
@@ -15,8 +17,7 @@ declare const useAuth: <T extends object = any>() => {
|
|
|
15
17
|
organization?: string | undefined;
|
|
16
18
|
roles?: string[] | undefined;
|
|
17
19
|
realm?: string | undefined;
|
|
18
|
-
|
|
19
|
-
};
|
|
20
|
+
} | undefined;
|
|
20
21
|
logout: () => void;
|
|
21
22
|
login: (provider: keyof T, options?: {
|
|
22
23
|
username?: string;
|
|
@@ -53,7 +54,10 @@ declare class ReactAuth {
|
|
|
53
54
|
*/
|
|
54
55
|
get user(): UserAccountToken | undefined;
|
|
55
56
|
ping(): Promise<{
|
|
57
|
+
id: string;
|
|
56
58
|
name?: string | undefined;
|
|
59
|
+
firstName?: string | undefined;
|
|
60
|
+
lastName?: string | undefined;
|
|
57
61
|
email?: string | undefined;
|
|
58
62
|
username?: string | undefined;
|
|
59
63
|
picture?: string | undefined;
|
|
@@ -61,7 +65,6 @@ declare class ReactAuth {
|
|
|
61
65
|
organization?: string | undefined;
|
|
62
66
|
roles?: string[] | undefined;
|
|
63
67
|
realm?: string | undefined;
|
|
64
|
-
id: string;
|
|
65
68
|
} | undefined>;
|
|
66
69
|
can(action: string): boolean;
|
|
67
70
|
login(provider: string, options: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/auth/hooks/useAuth.ts","../../../src/react/auth/services/ReactAuth.ts","../../../src/react/auth/providers/ReactAuthProvider.ts","../../../src/react/auth/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/auth/hooks/useAuth.ts","../../../src/react/auth/services/ReactAuth.ts","../../../src/react/auth/providers/ReactAuthProvider.ts","../../../src/react/auth/index.ts"],"mappings":";;;;;;cAKa,UAAW;;;;;;;;;;;;;;;0BAUF,GAAC;IAEf;IACA;IACA;IACA;KACC;QACF;;;;;;;;;;;;;;;cCNM;qBACQ,6BAAG;qBACH,QAAM;qBACN,YAAU;qBACV,cAAY;qBAEZ,oCAAiB;qBAWjB,iCAAc;;;;;;MAetB,QAAQ;EAMN,QAAI;;;;;;;;;;;;;EAcV,IAAI;EAQE,MACX,kBACA;IACE;IACA;IACA;IACA;IACA;KACC;MAEF,QAAQ;EA+CJ;;;;cClII;qBACQ,QAAM;WAET,2BAAQ;;;;;YCUd;IACR,OAAO;;;;;;;;;;;;;cAgBE,kCAAe,yBAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/react/auth/providers/ReactAuthProvider.ts","../../../src/react/auth/services/ReactAuth.ts","../../../src/react/auth/hooks/useAuth.ts","../../../src/react/auth/index.ts"],"sourcesContent":["import { $hook, $inject, Alepha } from \"alepha\";\nimport { currentUserAtom } from \"alepha/security\";\n\nexport class ReactAuthProvider {\n protected readonly alepha = $inject(Alepha);\n\n public readonly onRender = $hook({\n on: \"react:server:render:begin\",\n handler: async ({ request, state }) => {\n if (request?.user) {\n const { token, realm, ...user } = request.user; // do not send token and realm to the client\n this.alepha.store.set(currentUserAtom, user);\n state.user = user;\n }\n },\n });\n}\n","import { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { ReactBrowserProvider, Redirection } from \"alepha/react/router\";\nimport { currentUserAtom, type UserAccountToken } from \"alepha/security\";\nimport { HttpClient } from \"alepha/server\";\nimport {\n alephaServerAuthRoutes,\n type Tokens,\n tokenResponseSchema,\n userinfoResponseSchema,\n} from \"alepha/server/auth\";\nimport { LinkProvider } from \"alepha/server/links\";\n\n/**\n * Browser, SSR friendly, service to handle authentication.\n */\nexport class ReactAuth {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n protected readonly linkProvider = $inject(LinkProvider);\n\n protected readonly onBeginTransition = $hook({\n on: \"react:transition:begin\",\n handler: async (event) => {\n if (this.alepha.isBrowser()) {\n Object.defineProperty(event.state, \"user\", {\n get: () => this.user,\n });\n }\n },\n });\n\n protected readonly onFetchRequest = $hook({\n on: \"client:onRequest\",\n handler: async ({ request }) => {\n if (this.alepha.isBrowser() && this.user) {\n // ensure cookies are sent with requests and refresh-able\n request.credentials ??= \"include\";\n }\n },\n });\n\n /**\n * Get the current authenticated user.\n *\n * Alias for `alepha.state.get(\"user\")`\n */\n public get user(): UserAccountToken | undefined {\n return this.alepha.store.get(currentUserAtom) as\n | UserAccountToken\n | undefined;\n }\n\n public async ping() {\n const { data } = await this.httpClient.fetch(\n alephaServerAuthRoutes.userinfo,\n {\n schema: { response: userinfoResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data.user;\n }\n\n public can(action: string): boolean {\n if (!this.user) {\n return false;\n }\n\n return this.linkProvider.can(action);\n }\n\n public async login(\n provider: string,\n options: {\n hostname?: string;\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n },\n ): Promise<Tokens> {\n const realmParam = options.realm\n ? `&realm=${encodeURIComponent(options.realm)}`\n : \"\";\n\n if (options.username || options.password) {\n const { data } = await this.httpClient.fetch(\n `${options.hostname || \"\"}${alephaServerAuthRoutes.token}?provider=${provider}${realmParam}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n username: options.username,\n password: options.password,\n }),\n schema: { response: tokenResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data;\n }\n\n if (this.alepha.isBrowser()) {\n const browser = this.alepha.inject(ReactBrowserProvider);\n const redirect =\n options.redirect ||\n (browser.transitioning\n ? window.location.origin + browser.transitioning.to\n : window.location.href);\n\n const href = `${window.location.origin}${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${encodeURIComponent(redirect)}`;\n\n if (browser.transitioning) {\n throw new Redirection(href);\n } else {\n window.location.href = href;\n return {} as Tokens;\n }\n }\n\n throw new Redirection(\n `${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${options.redirect || \"/\"}`,\n );\n }\n\n public logout() {\n const form = document.createElement(\"form\");\n form.method = \"POST\";\n form.action = `${alephaServerAuthRoutes.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;\n form.style.display = \"none\";\n document.body.appendChild(form);\n form.submit();\n }\n}\n","import { useAlepha, useStore } from \"alepha/react\";\nimport { currentUserAtom } from \"alepha/security\";\nimport { LinkProvider } from \"alepha/server/links\";\nimport { ReactAuth } from \"../services/ReactAuth.ts\";\n\nexport const useAuth = <T extends object = any>() => {\n const alepha = useAlepha();\n const [user] = useStore(currentUserAtom);\n\n return {\n user,\n logout: () => {\n alepha.inject(ReactAuth).logout();\n },\n login: async (\n provider: keyof T,\n options: {\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n } = {},\n ) => {\n await alepha.inject(ReactAuth).login(provider as string, options);\n },\n /**\n * UI permission check — does the current user hold this permission?\n * Supports exact and wildcard names (e.g. `\"admin:*\"`, `\"admin:user:read\"`).\n *\n * UI affordance only (show/hide/disable). Real access control is enforced\n * server-side via `$secure` on the route/action.\n */\n has: (permission: string): boolean => {\n return alepha.inject(LinkProvider).can(permission);\n },\n };\n};\n","import { $module } from \"alepha\";\nimport { AlephaReact } from \"alepha/react\";\nimport type { UserAccount } from \"alepha/security\";\nimport { $auth, AlephaServerAuth } from \"alepha/server/auth\";\nimport { AlephaServerLinks } from \"alepha/server/links\";\nimport { ReactAuthProvider } from \"./providers/ReactAuthProvider.ts\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/ReactAuthProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha/react/router\" {\n interface ReactRouterState {\n user?: UserAccount;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Auth-related React components and hooks.\n *\n * **Features:**\n * - Login/logout components\n * - Protected route wrappers\n * - Auth state hooks\n *\n * @module alepha.react.auth\n */\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n primitives: [$auth],\n services: [\n AlephaReact,\n AlephaServerLinks,\n AlephaServerAuth,\n ReactAuthProvider,\n ReactAuth,\n ],\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/react/auth/providers/ReactAuthProvider.ts","../../../src/react/auth/services/ReactAuth.ts","../../../src/react/auth/hooks/useAuth.ts","../../../src/react/auth/index.ts"],"sourcesContent":["import { $hook, $inject, Alepha } from \"alepha\";\nimport { currentUserAtom } from \"alepha/security\";\n\nexport class ReactAuthProvider {\n protected readonly alepha = $inject(Alepha);\n\n public readonly onRender = $hook({\n on: \"react:server:render:begin\",\n handler: async ({ request, state }) => {\n if (request?.user) {\n const { token, realm, ...user } = request.user; // do not send token and realm to the client\n this.alepha.store.set(currentUserAtom, user);\n state.user = user;\n }\n },\n });\n}\n","import { $hook, $inject, Alepha } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { ReactBrowserProvider, Redirection } from \"alepha/react/router\";\nimport { currentUserAtom, type UserAccountToken } from \"alepha/security\";\nimport { HttpClient } from \"alepha/server\";\nimport {\n alephaServerAuthRoutes,\n type Tokens,\n tokenResponseSchema,\n userinfoResponseSchema,\n} from \"alepha/server/auth\";\nimport { LinkProvider } from \"alepha/server/links\";\n\n/**\n * Browser, SSR friendly, service to handle authentication.\n */\nexport class ReactAuth {\n protected readonly log = $logger();\n protected readonly alepha = $inject(Alepha);\n protected readonly httpClient = $inject(HttpClient);\n protected readonly linkProvider = $inject(LinkProvider);\n\n protected readonly onBeginTransition = $hook({\n on: \"react:transition:begin\",\n handler: async (event) => {\n if (this.alepha.isBrowser()) {\n Object.defineProperty(event.state, \"user\", {\n get: () => this.user,\n });\n }\n },\n });\n\n protected readonly onFetchRequest = $hook({\n on: \"client:onRequest\",\n handler: async ({ request }) => {\n if (this.alepha.isBrowser() && this.user) {\n // ensure cookies are sent with requests and refresh-able\n request.credentials ??= \"include\";\n }\n },\n });\n\n /**\n * Get the current authenticated user.\n *\n * Alias for `alepha.state.get(\"user\")`\n */\n public get user(): UserAccountToken | undefined {\n return this.alepha.store.get(currentUserAtom) as\n | UserAccountToken\n | undefined;\n }\n\n public async ping() {\n const { data } = await this.httpClient.fetch(\n alephaServerAuthRoutes.userinfo,\n {\n schema: { response: userinfoResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data.user;\n }\n\n public can(action: string): boolean {\n if (!this.user) {\n return false;\n }\n\n return this.linkProvider.can(action);\n }\n\n public async login(\n provider: string,\n options: {\n hostname?: string;\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n },\n ): Promise<Tokens> {\n const realmParam = options.realm\n ? `&realm=${encodeURIComponent(options.realm)}`\n : \"\";\n\n if (options.username || options.password) {\n const { data } = await this.httpClient.fetch(\n `${options.hostname || \"\"}${alephaServerAuthRoutes.token}?provider=${provider}${realmParam}`,\n {\n method: \"POST\",\n body: JSON.stringify({\n username: options.username,\n password: options.password,\n }),\n schema: { response: tokenResponseSchema },\n },\n );\n\n this.alepha.store.set(\"alepha.server.request.apiLinks\", data.api);\n this.alepha.store.set(currentUserAtom, data.user);\n\n return data;\n }\n\n if (this.alepha.isBrowser()) {\n const browser = this.alepha.inject(ReactBrowserProvider);\n const redirect =\n options.redirect ||\n (browser.transitioning\n ? window.location.origin + browser.transitioning.to\n : window.location.href);\n\n const href = `${window.location.origin}${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${encodeURIComponent(redirect)}`;\n\n if (browser.transitioning) {\n throw new Redirection(href);\n } else {\n window.location.href = href;\n return {} as Tokens;\n }\n }\n\n throw new Redirection(\n `${alephaServerAuthRoutes.login}?provider=${provider}${realmParam}&redirect_uri=${options.redirect || \"/\"}`,\n );\n }\n\n public logout() {\n const form = document.createElement(\"form\");\n form.method = \"POST\";\n form.action = `${alephaServerAuthRoutes.logout}?post_logout_redirect_uri=${encodeURIComponent(window.location.origin)}`;\n form.style.display = \"none\";\n document.body.appendChild(form);\n form.submit();\n }\n}\n","import { useAlepha, useStore } from \"alepha/react\";\nimport { currentUserAtom } from \"alepha/security\";\nimport { LinkProvider } from \"alepha/server/links\";\nimport { ReactAuth } from \"../services/ReactAuth.ts\";\n\nexport const useAuth = <T extends object = any>() => {\n const alepha = useAlepha();\n const [user] = useStore(currentUserAtom);\n\n return {\n user,\n logout: () => {\n alepha.inject(ReactAuth).logout();\n },\n login: async (\n provider: keyof T,\n options: {\n username?: string;\n password?: string;\n redirect?: string;\n realm?: string;\n [extra: string]: any;\n } = {},\n ) => {\n await alepha.inject(ReactAuth).login(provider as string, options);\n },\n /**\n * UI permission check — does the current user hold this permission?\n * Supports exact and wildcard names (e.g. `\"admin:*\"`, `\"admin:user:read\"`).\n *\n * UI affordance only (show/hide/disable). Real access control is enforced\n * server-side via `$secure` on the route/action.\n */\n has: (permission: string): boolean => {\n return alepha.inject(LinkProvider).can(permission);\n },\n };\n};\n","import { $module } from \"alepha\";\nimport { AlephaReact } from \"alepha/react\";\nimport type { UserAccount } from \"alepha/security\";\nimport { $auth, AlephaServerAuth } from \"alepha/server/auth\";\nimport { AlephaServerLinks } from \"alepha/server/links\";\nimport { ReactAuthProvider } from \"./providers/ReactAuthProvider.ts\";\nimport { ReactAuth } from \"./services/ReactAuth.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./index.shared.ts\";\nexport * from \"./providers/ReactAuthProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha/react/router\" {\n interface ReactRouterState {\n user?: UserAccount;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Auth-related React components and hooks.\n *\n * **Features:**\n * - Login/logout components\n * - Protected route wrappers\n * - Auth state hooks\n *\n * @module alepha.react.auth\n */\nexport const AlephaReactAuth = $module({\n name: \"alepha.react.auth\",\n primitives: [$auth],\n services: [\n AlephaReact,\n AlephaServerLinks,\n AlephaServerAuth,\n ReactAuthProvider,\n ReactAuth,\n ],\n});\n"],"mappings":"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"}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import { Alepha, Async, Atom, Hook, Hooks, Service, State, Static, TAtomObject } from "alepha";
|
|
1
|
+
import { Alepha, Async, Atom, Computed, Hook, Hooks, Service, State, Static, TAtomObject } from "alepha";
|
|
2
2
|
import React, { DependencyList, ErrorInfo, PropsWithChildren, ReactNode } from "react";
|
|
3
3
|
import { DurationLike } from "alepha/datetime";
|
|
4
4
|
import { ClientScope, HttpVirtualClient } from "alepha/server/links";
|
|
5
|
-
|
|
6
5
|
//#region ../../src/react/core/components/ClientOnly.d.ts
|
|
7
6
|
interface ClientOnlyProps {
|
|
8
7
|
fallback?: ReactNode;
|
|
@@ -49,6 +48,19 @@ interface ErrorBoundaryProps {
|
|
|
49
48
|
* Use this to log errors to a monitoring service.
|
|
50
49
|
*/
|
|
51
50
|
onError?: (error: Error, info: ErrorInfo) => void;
|
|
51
|
+
/**
|
|
52
|
+
* Clear a caught error whenever any of these values changes (compared with
|
|
53
|
+
* `Object.is`, positionally).
|
|
54
|
+
*
|
|
55
|
+
* A boundary that catches has to be told when the reason to fail is gone —
|
|
56
|
+
* otherwise the fallback latches and every later render keeps showing the
|
|
57
|
+
* stale error. The router passes the current path, so navigating away from a
|
|
58
|
+
* page that threw recovers on its own.
|
|
59
|
+
*
|
|
60
|
+
* Unlike remounting via `key`, this clears the error WITHOUT tearing down the
|
|
61
|
+
* children, so unrelated component state survives an ordinary navigation.
|
|
62
|
+
*/
|
|
63
|
+
resetKeys?: readonly unknown[];
|
|
52
64
|
}
|
|
53
65
|
/**
|
|
54
66
|
* State of the ErrorBoundary component.
|
|
@@ -72,6 +84,11 @@ declare class ErrorBoundary extends React.Component<PropsWithChildren<ErrorBound
|
|
|
72
84
|
* You can log the error or perform side effects here.
|
|
73
85
|
*/
|
|
74
86
|
componentDidCatch(error: Error, info: ErrorInfo): void;
|
|
87
|
+
/**
|
|
88
|
+
* Recover once the caller signals the failing input is gone.
|
|
89
|
+
*/
|
|
90
|
+
componentDidUpdate(prevProps: PropsWithChildren<ErrorBoundaryProps>): void;
|
|
91
|
+
protected hasResetKeyChanged(previous: readonly unknown[] | undefined, next: readonly unknown[] | undefined): boolean;
|
|
75
92
|
render(): ReactNode;
|
|
76
93
|
}
|
|
77
94
|
//#endregion
|
|
@@ -92,7 +109,7 @@ interface AlephaProviderProps {
|
|
|
92
109
|
*
|
|
93
110
|
* This isn't recommended for apps using `alepha/react/router`, as Router will handle this for you.
|
|
94
111
|
*/
|
|
95
|
-
declare const AlephaProvider: (props: AlephaProviderProps) => string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean |
|
|
112
|
+
declare const AlephaProvider: (props: AlephaProviderProps) => string | number | bigint | boolean | import("react").JSX.Element | Iterable<ReactNode> | Promise<string | number | bigint | boolean | Iterable<ReactNode> | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | import("react").ReactPortal | null | undefined> | null | undefined;
|
|
96
113
|
//#endregion
|
|
97
114
|
//#region ../../src/react/core/hooks/useAction.d.ts
|
|
98
115
|
/**
|
|
@@ -352,6 +369,42 @@ declare const useAlepha: () => Alepha;
|
|
|
352
369
|
*/
|
|
353
370
|
declare const useClient: <T extends object>(scope?: ClientScope) => HttpVirtualClient<T>;
|
|
354
371
|
//#endregion
|
|
372
|
+
//#region ../../src/react/core/hooks/useComputed.d.ts
|
|
373
|
+
/**
|
|
374
|
+
* Subscribes to a `$computed` value.
|
|
375
|
+
*
|
|
376
|
+
* `getSnapshot` always reads the dependency atoms **live** off the store —
|
|
377
|
+
* never through a subscription-set dirty flag. A dirty flag is only ever
|
|
378
|
+
* flipped by the `state:mutate` listener registered in `subscribe`, which
|
|
379
|
+
* React wires up in a passive effect (after commit); `EventManager.emit` is
|
|
380
|
+
* async on top of that. A mutation dispatched between the initial render and
|
|
381
|
+
* that effect committing would be invisible to the flag, so `getSnapshot`
|
|
382
|
+
* (including React's own post-subscribe consistency re-check) would keep
|
|
383
|
+
* returning the stale pre-mutation value. See `useStore.ts` and
|
|
384
|
+
* `useSelector.ts` for the same rationale.
|
|
385
|
+
*
|
|
386
|
+
* Referential stability for `useSyncExternalStore` comes from comparing the
|
|
387
|
+
* *inputs* (the resolved values of the computed's transitive atom
|
|
388
|
+
* dependencies) by identity, not from caching on a mount-time ref: when none
|
|
389
|
+
* of the inputs changed since the last snapshot, the previous output
|
|
390
|
+
* reference is returned as-is; when any input changed (or `target` itself
|
|
391
|
+
* was swapped for a different `Computed`), the value is recomputed and a new
|
|
392
|
+
* reference is cached.
|
|
393
|
+
*
|
|
394
|
+
* A `Computed` passed here should be declared at module scope, like an
|
|
395
|
+
* atom — constructing one inline in a component body creates a new
|
|
396
|
+
* instance every render, which (because `subscribe`/`getSnapshot` are keyed
|
|
397
|
+
* on `target.key`, matching `useStore`/`useSelector`) is tolerated for
|
|
398
|
+
* resubscription purposes, but any closures captured by that instance's
|
|
399
|
+
* `get()` will be locked to whichever render first created the subscription
|
|
400
|
+
* until `target.key` itself changes.
|
|
401
|
+
*
|
|
402
|
+
* ```tsx
|
|
403
|
+
* const total = useComputed(cartTotal);
|
|
404
|
+
* ```
|
|
405
|
+
*/
|
|
406
|
+
declare function useComputed<R>(target: Computed<R>): R;
|
|
407
|
+
//#endregion
|
|
355
408
|
//#region ../../src/react/core/hooks/useEvents.d.ts
|
|
356
409
|
/**
|
|
357
410
|
* Allow subscribing to multiple Alepha events. See {@link Hooks} for available events.
|
|
@@ -377,7 +430,7 @@ declare const useClient: <T extends object>(scope?: ClientScope) => HttpVirtualC
|
|
|
377
430
|
* ```
|
|
378
431
|
*/
|
|
379
432
|
declare const useEvents: (opts: UseEvents, deps: DependencyList) => void;
|
|
380
|
-
type UseEvents = { [T in keyof Hooks]?: Hook<T> | ((payload: Hooks[T]) => Async<void>) };
|
|
433
|
+
type UseEvents = { [T in keyof Hooks]?: Hook<T> | ((payload: Hooks[T]) => Async<void>); };
|
|
381
434
|
//#endregion
|
|
382
435
|
//#region ../../src/react/core/hooks/useInject.d.ts
|
|
383
436
|
/**
|
|
@@ -489,14 +542,43 @@ interface UseQueryReturn<Result> {
|
|
|
489
542
|
cancel: () => void;
|
|
490
543
|
}
|
|
491
544
|
//#endregion
|
|
545
|
+
//#region ../../src/react/core/hooks/useSelector.d.ts
|
|
546
|
+
/**
|
|
547
|
+
* Subscribes to a slice of an atom's state.
|
|
548
|
+
*
|
|
549
|
+
* Unlike {@link useStore}, which re-renders on every mutation of the atom,
|
|
550
|
+
* `useSelector` re-renders only when the selected slice actually changes
|
|
551
|
+
* according to `equality` (default: `Object.is`). Pass {@link shallowEqual}
|
|
552
|
+
* when the selector builds a fresh object on each call.
|
|
553
|
+
*
|
|
554
|
+
* ```tsx
|
|
555
|
+
* const theme = useSelector(uiAtom, (s) => s.theme);
|
|
556
|
+
* ```
|
|
557
|
+
*/
|
|
558
|
+
declare function useSelector<T extends TAtomObject, R>(target: Atom<T>, select: (state: Static<T>) => R, equality?: (a: R, b: R) => boolean): R;
|
|
559
|
+
//#endregion
|
|
492
560
|
//#region ../../src/react/core/hooks/useStore.d.ts
|
|
493
561
|
/**
|
|
494
562
|
* Hook to access and mutate the Alepha state.
|
|
563
|
+
*
|
|
564
|
+
* Reads through `useSyncExternalStore`, so the store — not a `useState` copy of
|
|
565
|
+
* it — is the single source of truth. That is what keeps the value correct when
|
|
566
|
+
* a mutation lands between render and effect-commit, when the component swaps
|
|
567
|
+
* which `target` it watches, and when React renders concurrently (no tearing).
|
|
495
568
|
*/
|
|
496
569
|
declare function useStore<T extends TAtomObject>(target: Atom<T>, defaultValue?: Static<T>): UseStoreReturn<Static<T>>;
|
|
497
570
|
declare function useStore<Key extends keyof State>(target: Key, defaultValue?: State[Key]): UseStoreReturn<State[Key]>;
|
|
498
571
|
type UseStoreReturn<T> = [T, (value: T) => void];
|
|
499
572
|
//#endregion
|
|
573
|
+
//#region ../../src/react/core/utils/shallowEqual.d.ts
|
|
574
|
+
/**
|
|
575
|
+
* Shallow structural equality over own enumerable keys.
|
|
576
|
+
*
|
|
577
|
+
* Intended as the `equality` argument of `useSelector` when the selector
|
|
578
|
+
* builds a fresh object/array on every call (e.g. `(s) => ({ a: s.a })`).
|
|
579
|
+
*/
|
|
580
|
+
declare const shallowEqual: (a: unknown, b: unknown) => boolean;
|
|
581
|
+
//#endregion
|
|
500
582
|
//#region ../../src/react/core/index.d.ts
|
|
501
583
|
declare module "alepha" {
|
|
502
584
|
interface Hooks {
|
|
@@ -561,5 +643,5 @@ declare module "alepha" {
|
|
|
561
643
|
*/
|
|
562
644
|
declare const AlephaReact: import("alepha").Service<import("alepha").Module>;
|
|
563
645
|
//#endregion
|
|
564
|
-
export { ActionContext, AlephaContext, AlephaProvider, AlephaProviderProps, AlephaReact, ClientOnly, type ClientOnlyProps, ErrorBoundary, type ErrorBoundaryProps, UseActionOptions, UseActionReturn, UseQueryOptions, UseQueryReturn, UseStoreReturn, useAction, useAlepha, useClient, useEvents, useInject, useQuery, useStore };
|
|
646
|
+
export { ActionContext, AlephaContext, AlephaProvider, AlephaProviderProps, AlephaReact, ClientOnly, type ClientOnlyProps, ErrorBoundary, type ErrorBoundaryProps, UseActionOptions, UseActionReturn, UseQueryOptions, UseQueryReturn, UseStoreReturn, shallowEqual, useAction, useAlepha, useClient, useComputed, useEvents, useInject, useQuery, useSelector, useStore };
|
|
565
647
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/core/components/ClientOnly.tsx","../../../src/react/core/components/ErrorBoundary.tsx","../../../src/react/core/contexts/AlephaContext.ts","../../../src/react/core/contexts/AlephaProvider.tsx","../../../src/react/core/hooks/useAction.ts","../../../src/react/core/hooks/useAlepha.ts","../../../src/react/core/hooks/useClient.ts","../../../src/react/core/hooks/useEvents.ts","../../../src/react/core/hooks/useInject.ts","../../../src/react/core/hooks/useQuery.ts","../../../src/react/core/hooks/useStore.ts","../../../src/react/core/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/react/core/components/ClientOnly.tsx","../../../src/react/core/components/ErrorBoundary.tsx","../../../src/react/core/contexts/AlephaContext.ts","../../../src/react/core/contexts/AlephaProvider.tsx","../../../src/react/core/hooks/useAction.ts","../../../src/react/core/hooks/useAlepha.ts","../../../src/react/core/hooks/useClient.ts","../../../src/react/core/hooks/useComputed.ts","../../../src/react/core/hooks/useEvents.ts","../../../src/react/core/hooks/useInject.ts","../../../src/react/core/hooks/useQuery.ts","../../../src/react/core/hooks/useSelector.ts","../../../src/react/core/hooks/useStore.ts","../../../src/react/core/utils/shallowEqual.ts","../../../src/react/core/index.ts"],"mappings":"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"}
|