alepha 0.19.1 → 0.19.2
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/LICENSE +1 -1
- package/README.md +6 -9
- package/dist/api/audits/index.d.ts +378 -346
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/files/index.d.ts +216 -184
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/jobs/index.d.ts +528 -496
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/jobs/index.js +3 -3
- package/dist/api/jobs/index.js.map +1 -1
- package/dist/api/keys/index.d.ts +207 -207
- package/dist/api/keys/index.d.ts.map +1 -1
- package/dist/api/notifications/index.d.ts +152 -152
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/organizations/index.browser.js +48 -0
- package/dist/api/organizations/index.browser.js.map +1 -0
- package/dist/api/organizations/index.d.ts +516 -0
- package/dist/api/organizations/index.d.ts.map +1 -0
- package/dist/api/organizations/index.js +202 -0
- package/dist/api/organizations/index.js.map +1 -0
- package/dist/api/parameters/index.d.ts +391 -358
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/parameters/index.js +5 -1
- package/dist/api/parameters/index.js.map +1 -1
- package/dist/api/users/index.browser.js +7 -5
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +978 -913
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +160 -112
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +135 -135
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/api/verifications/index.js +2 -2
- package/dist/api/verifications/index.js.map +1 -1
- package/dist/batch/index.d.ts +6 -6
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/billing/index.d.ts +1048 -0
- package/dist/billing/index.d.ts.map +1 -0
- package/dist/billing/index.js +713 -0
- package/dist/billing/index.js.map +1 -0
- package/dist/bin/index.js +0 -2
- package/dist/bin/index.js.map +1 -1
- package/dist/bucket/index.d.ts +10 -10
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/bucket/index.js +2 -2
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/core/index.d.ts +9 -9
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/core/index.js +2 -2
- package/dist/cache/core/index.js.map +1 -1
- package/dist/cache/core/index.workerd.js +2 -2
- package/dist/cache/core/index.workerd.js.map +1 -1
- package/dist/cache/redis/index.d.ts +6 -6
- 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/cli/config/index.d.ts +12 -2
- package/dist/cli/config/index.d.ts.map +1 -1
- package/dist/cli/config/index.js +4 -0
- package/dist/cli/config/index.js.map +1 -1
- package/dist/cli/core/index.d.ts +183 -140
- package/dist/cli/core/index.d.ts.map +1 -1
- package/dist/cli/core/index.js +279 -89
- package/dist/cli/core/index.js.map +1 -1
- package/dist/cli/devtools/index.d.ts +45 -0
- package/dist/cli/devtools/index.d.ts.map +1 -0
- package/dist/cli/devtools/index.js +170 -0
- package/dist/cli/devtools/index.js.map +1 -0
- package/dist/cli/platform/index.d.ts +383 -492
- package/dist/cli/platform/index.d.ts.map +1 -1
- package/dist/cli/platform/index.js +42 -511
- package/dist/cli/platform/index.js.map +1 -1
- package/dist/cli/vendor/index.d.ts +196 -0
- package/dist/cli/vendor/index.d.ts.map +1 -0
- package/dist/cli/vendor/index.js +384 -0
- package/dist/cli/vendor/index.js.map +1 -0
- package/dist/command/index.d.ts +18 -18
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +2 -2
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +4 -4
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +10 -10
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +4 -4
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +4 -4
- package/dist/core/index.native.js.map +1 -1
- package/dist/core/index.workerd.js +4 -4
- package/dist/core/index.workerd.js.map +1 -1
- package/dist/crypto/index.d.ts +7 -7
- package/dist/crypto/index.d.ts.map +1 -1
- package/dist/datetime/index.d.ts +4 -4
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/email/brevo/index.d.ts +4 -4
- package/dist/email/brevo/index.d.ts.map +1 -1
- package/dist/email/core/index.d.ts +15 -11
- package/dist/email/core/index.d.ts.map +1 -1
- package/dist/email/core/index.js +12 -35
- package/dist/email/core/index.js.map +1 -1
- package/dist/email/smtp/index.d.ts +12 -12
- package/dist/email/smtp/index.d.ts.map +1 -1
- package/dist/email/smtp/index.js +7 -4
- package/dist/email/smtp/index.js.map +1 -1
- package/dist/fake/index.d.ts +4 -8
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +55 -889
- package/dist/fake/index.js.map +1 -1
- package/dist/lock/core/index.d.ts +13 -13
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/core/index.js +2 -2
- package/dist/lock/core/index.js.map +1 -1
- package/dist/lock/redis/index.d.ts +4 -4
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/logger/index.d.ts +16 -15
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +5 -2
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +11 -11
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +2 -2
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/core/index.browser.js +11 -1
- package/dist/orm/core/index.browser.js.map +1 -1
- package/dist/orm/core/index.bun.js +53 -16
- package/dist/orm/core/index.bun.js.map +1 -1
- package/dist/orm/core/index.d.ts +95 -51
- package/dist/orm/core/index.d.ts.map +1 -1
- package/dist/orm/core/index.js +55 -14
- package/dist/orm/core/index.js.map +1 -1
- package/dist/orm/postgres/index.d.ts +18 -17
- package/dist/orm/postgres/index.d.ts.map +1 -1
- package/dist/queue/core/index.d.ts +14 -14
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/core/index.js +2 -2
- package/dist/queue/core/index.js.map +1 -1
- package/dist/queue/core/index.workerd.js +2 -2
- package/dist/queue/core/index.workerd.js.map +1 -1
- package/dist/queue/redis/index.d.ts +4 -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.d.ts +9 -9
- package/dist/react/auth/index.d.ts.map +1 -1
- package/dist/react/core/index.d.ts +6 -6
- package/dist/react/core/index.d.ts.map +1 -1
- package/dist/react/core/index.js +5 -4
- package/dist/react/core/index.js.map +1 -1
- package/dist/react/form/index.d.ts +4 -4
- package/dist/react/form/index.d.ts.map +1 -1
- package/dist/react/head/index.d.ts +4 -4
- package/dist/react/head/index.d.ts.map +1 -1
- package/dist/react/i18n/index.d.ts +9 -9
- package/dist/react/i18n/index.d.ts.map +1 -1
- package/dist/react/intro/index.d.ts +2 -2
- package/dist/react/intro/index.d.ts.map +1 -1
- package/dist/react/intro/index.js +1 -1
- package/dist/react/intro/index.js.map +1 -1
- package/dist/react/router/index.browser.js +4 -5
- package/dist/react/router/index.browser.js.map +1 -1
- package/dist/react/router/index.d.ts +215 -215
- package/dist/react/router/index.d.ts.map +1 -1
- package/dist/react/router/index.js +6 -7
- package/dist/react/router/index.js.map +1 -1
- package/dist/react/testing/index.d.ts +2 -2
- package/dist/react/testing/index.d.ts.map +1 -1
- package/dist/react/testing/index.js +2 -4
- package/dist/react/testing/index.js.map +1 -1
- package/dist/redis/index.d.ts +19 -19
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/retry/index.d.ts +4 -4
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +13 -13
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +2 -2
- package/dist/scheduler/index.js.map +1 -1
- package/dist/scheduler/index.workerd.js +2 -2
- package/dist/scheduler/index.workerd.js.map +1 -1
- package/dist/security/index.browser.js +1 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +47 -47
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +9 -12
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +170 -169
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +16 -2
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts +7 -7
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/core/index.d.ts +76 -76
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +23 -17
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +13 -13
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/cors/index.js +2 -2
- package/dist/server/cors/index.js.map +1 -1
- package/dist/server/etag/index.d.ts +9 -9
- package/dist/server/etag/index.d.ts.map +1 -1
- package/dist/server/health/index.d.ts +20 -20
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/links/index.browser.js +2 -2
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +66 -66
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +4 -4
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +7 -7
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/proxy/index.d.ts +5 -5
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.d.ts +12 -12
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.js +2 -2
- package/dist/server/rate-limit/index.js.map +1 -1
- package/dist/server/static/index.d.ts +5 -5
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/swagger/index.d.ts +7 -7
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +2 -2
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +11 -7
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +9 -15
- package/dist/sms/index.js.map +1 -1
- package/dist/system/index.d.ts +4 -4
- package/dist/system/index.d.ts.map +1 -1
- package/dist/topic/core/index.d.ts +6 -6
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/redis/index.d.ts +7 -7
- 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/dist/websocket/index.d.ts +36 -36
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +2 -2
- package/dist/websocket/index.js.map +1 -1
- package/package.json +36 -14
- package/src/api/jobs/{services → __tests__}/JobService.spec.ts +1 -1
- package/src/api/jobs/providers/JobProvider.ts +3 -3
- package/src/api/keys/{services → __tests__}/ApiKeyService.spec.ts +1 -1
- package/src/api/organizations/__tests__/OrganizationService.spec.ts +193 -0
- package/src/api/organizations/controllers/AdminOrganizationController.ts +103 -0
- package/src/api/organizations/entities/organizations.ts +20 -0
- package/src/api/organizations/index.browser.ts +10 -0
- package/src/api/organizations/index.ts +31 -0
- package/src/api/organizations/schemas/createOrganizationSchema.ts +10 -0
- package/src/api/organizations/schemas/organizationQuerySchema.ts +10 -0
- package/src/api/organizations/schemas/organizationResourceSchema.ts +6 -0
- package/src/api/organizations/schemas/updateOrganizationSchema.ts +7 -0
- package/src/api/organizations/services/OrganizationService.ts +75 -0
- package/src/api/parameters/services/ParameterProvider.ts +6 -1
- package/src/api/users/{services → __tests__}/SessionService.spec.ts +67 -0
- package/src/api/users/{jobs → __tests__}/UserJobs.spec.ts +1 -1
- package/src/api/users/entities/users.ts +9 -3
- package/src/api/users/index.ts +23 -4
- package/src/api/users/primitives/$realm.ts +6 -4
- package/src/api/users/providers/RealmProvider.ts +1 -1
- package/src/api/users/services/RegistrationService.ts +1 -1
- package/src/api/users/services/SessionService.ts +92 -5
- package/src/api/users/services/UserService.ts +1 -1
- package/src/api/verifications/{jobs → __tests__}/VerificationJobs.spec.ts +4 -2
- package/src/api/verifications/parameters/VerificationParameters.ts +2 -2
- package/src/billing/__tests__/BillingService.spec.ts +136 -0
- package/src/billing/__tests__/PaymentMethodService.spec.ts +78 -0
- package/src/billing/controllers/AdminBillingController.ts +149 -0
- package/src/billing/controllers/BillingController.ts +108 -0
- package/src/billing/entities/paymentIntents.ts +34 -0
- package/src/billing/entities/paymentMethods.ts +24 -0
- package/src/billing/entities/refunds.ts +22 -0
- package/src/billing/errors/BillingError.ts +5 -0
- package/src/billing/index.ts +76 -0
- package/src/billing/providers/BillingProvider.ts +79 -0
- package/src/billing/providers/MemoryBillingProvider.ts +139 -0
- package/src/billing/schemas/intentSchemas.ts +60 -0
- package/src/billing/schemas/paymentMethodSchemas.ts +13 -0
- package/src/billing/schemas/refundSchemas.ts +6 -0
- package/src/billing/services/BillingService.ts +325 -0
- package/src/billing/services/PaymentMethodService.ts +82 -0
- package/src/bin/index.ts +0 -2
- package/src/bucket/providers/LocalFileStorageProvider.ts +2 -2
- package/src/cache/core/{primitives → __tests__}/$cache.middleware.spec.ts +1 -1
- package/src/cache/core/{providers → __tests__}/MemoryCacheProvider.spec.ts +1 -1
- package/src/cache/core/primitives/$cache.ts +2 -2
- package/src/cache/redis/providers/RedisCacheProvider.ts +2 -2
- package/src/cli/config/defineConfig.ts +20 -0
- package/src/cli/core/{services → __tests__}/ProjectScaffolder.spec.ts +1 -1
- package/src/cli/core/{commands/gen → __tests__}/changelog.spec.ts +1 -1
- package/src/cli/core/{commands → __tests__}/init.spec.ts +2 -8
- package/src/cli/core/atoms/devOptions.ts +0 -5
- package/src/cli/core/commands/build.ts +2 -2
- package/src/cli/core/commands/dev.ts +165 -30
- package/src/cli/core/commands/gen/changelog.ts +2 -2
- package/src/cli/core/commands/init.ts +2 -7
- package/src/cli/core/commands/verify.ts +0 -1
- package/src/cli/core/providers/AppEntryProvider.ts +2 -2
- package/src/cli/core/providers/ViteDevServerProvider.ts +54 -66
- package/src/cli/core/services/PackageManagerUtils.ts +8 -3
- package/src/cli/core/services/ProjectScaffolder.ts +18 -18
- package/src/cli/core/tasks/BuildClientTask.ts +8 -0
- package/src/cli/core/tasks/BuildServerTask.ts +17 -4
- package/src/cli/core/templates/alephaConfigTs.ts +0 -6
- package/src/cli/core/templates/webAdminDashboardTsx.ts +17 -0
- package/src/cli/core/templates/webAppRouterTs.ts +85 -2
- package/src/cli/devtools/atoms/devtoolsOptions.ts +26 -0
- package/src/cli/devtools/index.ts +194 -0
- package/src/cli/platform/{adapters → __tests__}/CloudflareAdapter.spec.ts +2 -2
- package/src/cli/platform/{providers → __tests__}/GitHubSecretStore.spec.ts +1 -1
- package/src/cli/platform/{services → __tests__}/NamingService.spec.ts +1 -1
- package/src/cli/platform/{providers → __tests__}/PlatformCacheProvider.spec.ts +1 -1
- package/src/cli/platform/{services → __tests__}/PlatformInspector.spec.ts +1 -1
- package/src/cli/platform/{services → __tests__}/PlatformOrchestrator.spec.ts +3 -3
- package/src/cli/platform/{services → __tests__}/SecretFilterService.spec.ts +1 -1
- package/src/cli/platform/{commands → __tests__}/SecretsCommand.spec.ts +1 -1
- package/src/cli/platform/{adapters → __tests__}/VercelAdapter.spec.ts +2 -2
- package/src/cli/platform/atoms/platformOptions.ts +2 -10
- package/src/cli/platform/commands/SecretsCommand.ts +2 -2
- package/src/cli/platform/commands/platform.ts +2 -11
- package/src/cli/platform/index.ts +34 -11
- package/src/cli/platform/services/PlatformInspector.ts +2 -2
- package/src/cli/platform/services/PlatformOrchestrator.ts +0 -9
- package/src/cli/vendor/__tests__/VendorService.spec.ts +407 -0
- package/src/cli/vendor/atoms/vendorOptions.ts +41 -0
- package/src/cli/vendor/commands/VendorCommand.ts +204 -0
- package/src/cli/vendor/index.ts +43 -0
- package/src/cli/vendor/services/VendorService.ts +338 -0
- package/src/command/{providers → __tests__}/CliProvider.spec.ts +1 -1
- package/src/command/{helpers → __tests__}/EnvUtils.spec.ts +1 -1
- package/src/command/providers/CliProvider.ts +2 -2
- package/src/core/{primitives → __tests__}/$atom.spec.ts +2 -2
- package/src/core/{primitives → __tests__}/$memoize.spec.ts +1 -1
- package/src/core/{primitives → __tests__}/$mode.spec.ts +1 -1
- package/src/core/{primitives → __tests__}/$pipeline.spec.ts +1 -1
- package/src/core/{primitives → __tests__}/$scope.spec.ts +2 -2
- package/src/core/{providers → __tests__}/KeylessJsonSchemaCodec.spec.ts +1 -1
- package/src/core/{providers → __tests__}/SchemaValidator.spec.ts +1 -1
- package/src/core/{helpers → __tests__}/jsonSchemaToTypeBox.spec.ts +1 -1
- package/src/core/index.shared.ts +1 -1
- package/src/core/primitives/{$use.ts → $state.ts} +4 -4
- package/src/crypto/{providers → __tests__}/BrowserCryptoProvider.browser.spec.ts +1 -1
- package/src/crypto/{providers → __tests__}/CryptoProvider.spec.ts +1 -1
- package/src/datetime/{primitives → __tests__}/$debounce.spec.ts +1 -1
- package/src/datetime/{primitives → __tests__}/$throttle.spec.ts +1 -1
- package/src/datetime/{primitives → __tests__}/$timeout.spec.ts +1 -1
- package/src/email/brevo/{providers → __tests__}/BrevoEmailProvider.spec.ts +1 -1
- package/src/email/core/{providers → __tests__}/LocalEmailProvider.spec.ts +39 -150
- package/src/email/core/providers/LocalEmailProvider.ts +13 -51
- package/src/email/smtp/providers/NodemailerEmailProvider.ts +2 -2
- package/src/lock/core/{primitives → __tests__}/$lock.middleware.spec.ts +1 -1
- package/src/lock/core/primitives/$lock.ts +2 -2
- package/src/logger/index.ts +10 -4
- package/src/mcp/transports/SseMcpTransport.ts +2 -2
- package/src/orm/__tests__/ModelBuilder-tests.ts +53 -0
- package/src/orm/__tests__/ModelBuilder.spec.ts +80 -0
- package/src/orm/__tests__/organization-tests.ts +200 -0
- package/src/orm/__tests__/organization.spec.ts +103 -0
- package/src/orm/core/{providers/drivers → __tests__}/BunSqliteProvider.bun.spec.ts +5 -2
- package/src/orm/core/constants/PG_SYMBOLS.ts +2 -0
- package/src/orm/core/index.shared.ts +1 -0
- package/src/orm/core/primitives/$entity.ts +31 -0
- package/src/orm/core/providers/DatabaseTypeProvider.ts +11 -0
- package/src/orm/core/providers/DrizzleKitProvider.ts +1 -1
- package/src/orm/core/providers/drivers/BunSqliteProvider.ts +2 -2
- package/src/orm/core/providers/drivers/NodeSqliteProvider.ts +3 -3
- package/src/orm/core/services/ModelBuilder.ts +11 -0
- package/src/orm/core/services/QueryManager.ts +16 -2
- package/src/orm/core/services/Repository.ts +70 -10
- package/src/orm/postgres/{providers → __tests__}/BunPostgresProvider.bun.spec.ts +1 -1
- package/src/queue/core/providers/WorkerProvider.ts +2 -2
- package/src/queue/redis/providers/RedisQueueProvider.ts +2 -2
- package/src/react/core/{hooks → __tests__}/useAction.browser.spec.tsx +1 -1
- package/src/react/core/hooks/useAction.ts +7 -6
- package/src/react/head/{providers → __tests__}/BrowserHeadProvider.browser.spec.ts +1 -1
- package/src/react/head/{helpers → __tests__}/SeoExpander.spec.ts +1 -1
- package/src/react/i18n/{providers → __tests__}/I18nProvider.spec.ts +1 -1
- package/src/react/i18n/{hooks → __tests__}/useI18n.browser.spec.tsx +1 -1
- package/src/react/intro/components/GettingStartedDevtoolsSlide.tsx +1 -1
- package/src/react/router/{providers → __tests__}/ReactBrowserProvider.browser.spec.ts +1 -1
- package/src/react/router/providers/ReactBrowserProvider.ts +2 -2
- package/src/react/router/providers/ReactPageProvider.ts +2 -2
- package/src/react/router/providers/ReactServerProvider.ts +3 -3
- package/src/redis/{providers → __tests__}/BunRedisProvider.bun.spec.ts +4 -4
- package/src/retry/{primitives → __tests__}/$retry.middleware.spec.ts +1 -1
- package/src/router/{TemplatedPathParser.spec.ts → __tests__/TemplatedPathParser.spec.ts} +1 -1
- package/src/scheduler/primitives/$scheduler.ts +2 -2
- package/src/security/{primitives → __tests__}/$secure-browser.spec.ts +1 -1
- package/src/security/{primitives → __tests__}/$secure.spec.ts +1 -1
- package/src/security/primitives/$issuer.ts +1 -1
- package/src/security/providers/JwtProvider.ts +6 -10
- package/src/security/providers/SecurityProvider.ts +6 -11
- package/src/security/schemas/userAccountInfoSchema.ts +3 -3
- package/src/server/auth/providers/ServerAuthProvider.ts +24 -2
- package/src/server/cookies/{services → __tests__}/CookieParser.spec.ts +1 -1
- package/src/server/core/{primitives → __tests__}/$circuit.spec.ts +1 -1
- package/src/server/core/{providers → __tests__}/NodeHttpServerProvider.spec.ts +1 -1
- package/src/server/core/{providers → __tests__}/ServerBodyParserProvider.spec.ts +31 -1
- package/src/server/core/{providers → __tests__}/ServerCompressProvider.spec.ts +1 -1
- package/src/server/core/{providers → __tests__}/ServerHelmetProvider.spec.ts +4 -1
- package/src/server/core/{providers → __tests__}/ServerMultipartProvider.spec.ts +1 -1
- package/src/server/core/{services → __tests__}/ServerRequestParser.spec.ts +1 -1
- package/src/server/core/primitives/$action.ts +2 -2
- package/src/server/core/primitives/$sse.ts +2 -2
- package/src/server/core/providers/ServerBodyParserProvider.ts +21 -12
- package/src/server/core/providers/ServerCompressProvider.ts +2 -2
- package/src/server/core/providers/ServerHelmetProvider.ts +2 -2
- package/src/server/core/providers/ServerMultipartProvider.ts +2 -2
- package/src/server/core/providers/ServerRouterProvider.ts +1 -5
- package/src/server/cors/{primitives → __tests__}/$cors.spec.ts +1 -1
- package/src/server/cors/providers/ServerCorsProvider.ts +2 -2
- package/src/server/links/{services → __tests__}/BatchCollector.spec.ts +1 -1
- package/src/server/links/providers/LinkProvider.ts +2 -2
- package/src/server/links/providers/RemotePrimitiveProvider.ts +2 -2
- package/src/server/links/providers/ServerLinksProvider.ts +2 -2
- package/src/server/rate-limit/{primitives → __tests__}/$rateLimit.spec.ts +1 -1
- package/src/server/rate-limit/providers/ServerRateLimitProvider.ts +2 -2
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +2 -2
- package/src/sms/{providers → __tests__}/LocalSmsProvider.spec.ts +35 -29
- package/src/sms/providers/LocalSmsProvider.ts +13 -24
- package/src/system/{providers → __tests__}/MemoryFileSystemProvider.spec.ts +1 -1
- package/src/system/{providers → __tests__}/MemoryShellProvider.spec.ts +1 -1
- package/src/topic/redis/providers/RedisTopicProvider.ts +2 -2
- package/src/websocket/{services → __tests__}/RoomManager.spec.ts +1 -1
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +2 -2
- package/tsconfig.base.json +1 -0
- package/src/cli/platform/adapters/DockerAdapter.spec.ts +0 -378
- package/src/cli/platform/adapters/DockerAdapter.ts +0 -417
- package/src/cli/platform/services/DockerComposeGenerator.spec.ts +0 -490
- package/src/cli/platform/services/DockerComposeGenerator.ts +0 -353
- package/src/cli/platform/services/DockerSshService.spec.ts +0 -47
- package/src/cli/platform/services/DockerSshService.ts +0 -61
- /package/src/api/audits/{primitives → __tests__}/$audit.spec.ts +0 -0
- /package/src/api/audits/{services → __tests__}/AuditService.spec.ts +0 -0
- /package/src/api/files/{controllers → __tests__}/AdminFileStatsController.spec.ts +0 -0
- /package/src/api/files/{controllers → __tests__}/FileController.spec.ts +0 -0
- /package/src/api/files/{jobs → __tests__}/FileJobs.spec.ts +0 -0
- /package/src/api/files/{services → __tests__}/FileService.spec.ts +0 -0
- /package/src/api/jobs/{primitives → __tests__}/$job-middleware.spec.ts +0 -0
- /package/src/api/parameters/{primitives → __tests__}/$parameter.spec.ts +0 -0
- /package/src/api/users/{primitives → __tests__}/$realm.spec.ts +0 -0
- /package/src/api/users/{controllers → __tests__}/AdminIdentityController.spec.ts +0 -0
- /package/src/api/users/{controllers → __tests__}/AdminSessionController.spec.ts +0 -0
- /package/src/api/users/{controllers → __tests__}/AdminUserController.spec.ts +0 -0
- /package/src/api/users/{services → __tests__}/CredentialService.spec.ts +0 -0
- /package/src/api/users/{providers → __tests__}/RealmProvider.spec.ts +0 -0
- /package/src/api/users/{services → __tests__}/RegistrationService.spec.ts +0 -0
- /package/src/batch/{primitives → __tests__}/$batch.spec.ts +0 -0
- /package/src/batch/{providers → __tests__}/BatchProvider.spec.ts +0 -0
- /package/src/bucket/{primitives → __tests__}/$bucket.spec.ts +0 -0
- /package/src/bucket/{providers → __tests__}/FileStorageProvider.spec.ts +0 -0
- /package/src/bucket/{providers → __tests__}/LocalFileStorageProvider.spec.ts +0 -0
- /package/src/bucket/{providers → __tests__}/MemoryFileStorageProvider.spec.ts +0 -0
- /package/src/cache/core/{primitives → __tests__}/$cache.spec.ts +0 -0
- /package/src/cache/redis/{providers → __tests__}/RedisCacheProvider.spec.ts +0 -0
- /package/src/command/{primitives → __tests__}/$command.spec.ts +0 -0
- /package/src/command/{helpers → __tests__}/Asker.spec.ts +0 -0
- /package/src/command/{helpers → __tests__}/Runner.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$context.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$env.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$hook.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$inject.spec.ts +0 -0
- /package/src/core/{primitives → __tests__}/$module.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/CodecManager.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/EventManager.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/StateManager.spec.ts +0 -0
- /package/src/core/{providers → __tests__}/TypeProvider.spec.ts +0 -0
- /package/src/datetime/{primitives → __tests__}/$interval.spec.ts +0 -0
- /package/src/datetime/{providers → __tests__}/DateTimeProvider.spec.ts +0 -0
- /package/src/email/core/{primitives → __tests__}/$email.spec.ts +0 -0
- /package/src/fake/{providers → __tests__}/FakeProvider.spec.ts +0 -0
- /package/src/lock/core/{providers → __tests__}/MemoryLockProvider.spec.ts +0 -0
- /package/src/lock/redis/{providers → __tests__}/RedisLockProvider.spec.ts +0 -0
- /package/src/logger/{primitives → __tests__}/$logger.spec.ts +0 -0
- /package/src/logger/{services → __tests__}/Logger.spec.ts +0 -0
- /package/src/mcp/{primitives → __tests__}/$prompt.spec.ts +0 -0
- /package/src/mcp/{primitives → __tests__}/$resource.spec.ts +0 -0
- /package/src/mcp/{primitives → __tests__}/$tool.spec.ts +0 -0
- /package/src/mcp/{providers → __tests__}/McpServerProvider.spec.ts +0 -0
- /package/src/mcp/{helpers → __tests__}/jsonrpc.spec.ts +0 -0
- /package/src/orm/core/{helpers → __tests__}/parseQueryString.spec.ts +0 -0
- /package/src/queue/core/{primitives → __tests__}/$consumer.spec.ts +0 -0
- /package/src/queue/core/{providers → __tests__}/MemoryQueueProvider.spec.ts +0 -0
- /package/src/queue/core/{providers → __tests__}/WorkerProvider.spec.ts +0 -0
- /package/src/queue/redis/{providers → __tests__}/RedisQueueProvider.spec.ts +0 -0
- /package/src/react/form/{hooks → __tests__}/useForm.browser.spec.tsx +0 -0
- /package/src/react/head/{hooks → __tests__}/useHead.spec.tsx +0 -0
- /package/src/react/i18n/{components → __tests__}/Localize.spec.tsx +0 -0
- /package/src/react/router/{primitives → __tests__}/$page.browser.spec.tsx +0 -0
- /package/src/react/router/{primitives → __tests__}/$page.middleware.spec.tsx +0 -0
- /package/src/react/router/{primitives → __tests__}/$page.spec.tsx +0 -0
- /package/src/react/router/{providers → __tests__}/ReactPreloadProvider.spec.ts +0 -0
- /package/src/react/router/{providers → __tests__}/ReactServerProvider.spec.tsx +0 -0
- /package/src/react/router/{providers → __tests__}/ReactServerTemplateProvider.spec.ts +0 -0
- /package/src/retry/{primitives → __tests__}/$retry.spec.ts +0 -0
- /package/src/retry/{providers → __tests__}/RetryProvider.spec.ts +0 -0
- /package/src/router/{providers → __tests__}/RouterProvider.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$issuer.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$permission.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$role.spec.ts +0 -0
- /package/src/security/{primitives → __tests__}/$serviceAccount.spec.ts +0 -0
- /package/src/security/{providers → __tests__}/SecurityProvider.spec.ts +0 -0
- /package/src/server/cookies/{providers → __tests__}/ServerCookiesProvider.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$action.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$middleware.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$route.spec.ts +0 -0
- /package/src/server/core/{primitives → __tests__}/$sse.spec.ts +0 -0
- /package/src/server/core/{providers → __tests__}/BunHttpServerProvider.bun.spec.ts +0 -0
- /package/src/server/core/{services → __tests__}/HttpClient.spec.ts +0 -0
- /package/src/server/core/{providers → __tests__}/ServerLoggerProvider.spec.ts +0 -0
- /package/src/server/core/{services → __tests__}/UserAgentParser.spec.ts +0 -0
- /package/src/server/cors/{providers → __tests__}/ServerCorsProvider.spec.ts +0 -0
- /package/src/server/etag/{providers → __tests__}/ServerEtagProvider.spec.ts +0 -0
- /package/src/server/health/{providers → __tests__}/ServerHealthProvider.spec.ts +0 -0
- /package/src/server/links/{primitives → __tests__}/$remote.spec.ts +0 -0
- /package/src/server/links/{services → __tests__}/BatchEndpoint.spec.ts +0 -0
- /package/src/server/links/{providers → __tests__}/LinkProvider.spec.ts +0 -0
- /package/src/server/links/{providers → __tests__}/ServerLinksProvider.spec.ts +0 -0
- /package/src/server/metrics/{providers → __tests__}/ServerMetricsProvider.spec.ts +0 -0
- /package/src/server/proxy/{primitives → __tests__}/$proxy.spec.ts +0 -0
- /package/src/server/rate-limit/{providers → __tests__}/ServerRateLimitProvider.spec.ts +0 -0
- /package/src/server/static/{primitives → __tests__}/$serve.spec.ts +0 -0
- /package/src/server/swagger/{primitives → __tests__}/$swagger.spec.ts +0 -0
- /package/src/sms/{primitives → __tests__}/$sms.spec.ts +0 -0
- /package/src/sms/{providers → __tests__}/MemorySmsProvider.spec.ts +0 -0
- /package/src/system/{services → __tests__}/FileDetector.spec.ts +0 -0
- /package/src/system/{providers → __tests__}/NodeFileSystemProvider.spec.ts +0 -0
- /package/src/topic/core/{primitives → __tests__}/$subscriber.spec.ts +0 -0
- /package/src/topic/core/{providers → __tests__}/MemoryTopicProvider.spec.ts +0 -0
- /package/src/topic/redis/{providers → __tests__}/RedisTopicProvider.spec.ts +0 -0
- /package/src/websocket/{primitives → __tests__}/$channel.spec.ts +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/billing/entities/paymentIntents.ts","../../src/billing/schemas/intentSchemas.ts","../../src/billing/entities/refunds.ts","../../src/billing/schemas/refundSchemas.ts","../../src/billing/errors/BillingError.ts","../../src/billing/providers/BillingProvider.ts","../../src/billing/services/BillingService.ts","../../src/billing/controllers/AdminBillingController.ts","../../src/billing/entities/paymentMethods.ts","../../src/billing/schemas/paymentMethodSchemas.ts","../../src/billing/services/PaymentMethodService.ts","../../src/billing/controllers/BillingController.ts","../../src/billing/providers/MemoryBillingProvider.ts","../../src/billing/index.ts"],"sourcesContent":["import { type Static, t } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const paymentIntents = $entity({\n name: \"payment_intents\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n version: db.version(),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n organizationId: db.organization(),\n amount: t.integer(),\n currency: t.text({ size: \"short\" }),\n status: t.enum([\n \"created\",\n \"processing\",\n \"authorized\",\n \"captured\",\n \"voided\",\n \"failed\",\n \"cancelled\",\n \"refunded\",\n \"expired\",\n ]),\n providerRef: t.optional(t.text()),\n providerRaw: t.optional(t.json()),\n metadata: t.optional(t.json()),\n paymentMethodId: t.optional(t.uuid()),\n userId: t.optional(t.uuid()),\n }),\n indexes: [\"status\", \"organizationId\", \"userId\", \"createdAt\"],\n});\n\nexport type PaymentIntentEntity = Static<typeof paymentIntents.schema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\nimport { paymentIntents } from \"../entities/paymentIntents.ts\";\n\nexport const createIntentSchema = t.object({\n amount: t.integer({ minimum: 1 }),\n currency: t.text({ size: \"short\" }),\n metadata: t.optional(t.json()),\n paymentMethodId: t.optional(t.uuid()),\n});\n\nexport type CreateIntent = Static<typeof createIntentSchema>;\n\nexport const createCheckoutSchema = t.object({\n intentId: t.uuid(),\n returnUrl: t.text(),\n authorize: t.optional(t.boolean()),\n});\n\nexport type CreateCheckout = Static<typeof createCheckoutSchema>;\n\nexport const checkoutResponseSchema = t.object({\n url: t.text(),\n intentId: t.text(),\n});\n\nexport type CheckoutResponse = Static<typeof checkoutResponseSchema>;\n\nexport const captureIntentSchema = t.object({\n amount: t.optional(t.integer({ minimum: 1 })),\n});\n\nexport type CaptureIntent = Static<typeof captureIntentSchema>;\n\nexport const refundIntentSchema = t.object({\n amount: t.integer({ minimum: 1 }),\n reason: t.optional(t.text()),\n});\n\nexport type RefundIntent = Static<typeof refundIntentSchema>;\n\nexport const recordCashSchema = t.object({\n amount: t.integer({ minimum: 1 }),\n currency: t.text({ size: \"short\" }),\n metadata: t.optional(t.json()),\n});\n\nexport type RecordCash = Static<typeof recordCashSchema>;\n\nexport const intentQuerySchema = t.extend(pageQuerySchema, {\n status: t.optional(t.text({ description: \"Filter by status\" })),\n userId: t.optional(t.uuid({ description: \"Filter by user ID\" })),\n});\n\nexport type IntentQuery = Static<typeof intentQuerySchema>;\n\nexport const intentResourceSchema = paymentIntents.schema;\n\nexport type IntentResource = Static<typeof intentResourceSchema>;\n","import { type Static, t } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const refunds = $entity({\n name: \"refunds\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n version: db.version(),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n organizationId: db.organization(),\n intentId: t.uuid(),\n amount: t.integer(),\n currency: t.text({ size: \"short\" }),\n status: t.enum([\"pending\", \"processing\", \"completed\", \"failed\"]),\n reason: t.optional(t.text()),\n providerRef: t.optional(t.text()),\n }),\n indexes: [\"intentId\", \"organizationId\", \"status\"],\n});\n\nexport type RefundEntity = Static<typeof refunds.schema>;\n","import type { Static } from \"alepha\";\nimport { refunds } from \"../entities/refunds.ts\";\n\nexport const refundResourceSchema = refunds.schema;\n\nexport type RefundResource = Static<typeof refundResourceSchema>;\n","import { AlephaError } from \"alepha\";\n\nexport class BillingError extends AlephaError {\n public readonly status = 400;\n}\n","import type { PaymentIntentEntity } from \"../entities/paymentIntents.ts\";\n\nexport interface CreateSessionResult {\n url: string;\n providerRef: string;\n}\n\nexport interface RefundResult {\n providerRef: string;\n}\n\nexport interface WebhookEvent {\n providerRef: string;\n status: string;\n raw: unknown;\n}\n\nexport interface CreatePaymentMethodResult {\n providerRef: string;\n type: string;\n brand?: string;\n last4?: string;\n expMonth?: number;\n expYear?: number;\n}\n\nexport abstract class BillingProvider {\n /**\n * Create a checkout session with the PSP.\n * Returns a URL to redirect the user to, and the PSP's reference ID.\n */\n abstract createSession(\n intent: PaymentIntentEntity,\n options: { returnUrl: string; authorize?: boolean },\n ): Promise<CreateSessionResult>;\n\n /**\n * Capture a previously authorized payment.\n * Amount can differ from the original authorization (partial capture).\n */\n abstract capturePayment(providerRef: string, amount: number): Promise<void>;\n\n /**\n * Void/cancel a previously authorized payment before capture.\n */\n abstract voidPayment(providerRef: string): Promise<void>;\n\n /**\n * Refund a captured payment (partial or full).\n */\n abstract refundPayment(\n providerRef: string,\n amount: number,\n ): Promise<RefundResult>;\n\n /**\n * Parse an incoming PSP webhook request into a normalized event.\n */\n abstract parseWebhook(request: Request): Promise<WebhookEvent>;\n\n /**\n * Store a payment method token with the PSP.\n */\n abstract createPaymentMethod(\n userId: string,\n token: string,\n ): Promise<CreatePaymentMethodResult>;\n\n /**\n * Delete a stored payment method from the PSP.\n */\n abstract deletePaymentMethod(providerRef: string): Promise<void>;\n\n /**\n * Expire/cancel a checkout session on the PSP side.\n * Called during stale session cleanup.\n */\n abstract expireSession(providerRef: string): Promise<void>;\n}\n","import { $inject, Alepha } from \"alepha\";\nimport { $job } from \"alepha/api/jobs\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport {\n type PaymentIntentEntity,\n paymentIntents,\n} from \"../entities/paymentIntents.ts\";\nimport { type RefundEntity, refunds } from \"../entities/refunds.ts\";\nimport { BillingError } from \"../errors/BillingError.ts\";\nimport { BillingProvider } from \"../providers/BillingProvider.ts\";\n\nexport class BillingService {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly dateTime = $inject(DateTimeProvider);\n protected readonly provider = $inject(BillingProvider);\n protected readonly intentRepo = $repository(paymentIntents);\n protected readonly refundRepo = $repository(refunds);\n\n /**\n * Expires stale payment intents that have been in \"processing\" status\n * for more than 30 minutes. Runs every 15 minutes.\n */\n protected readonly expireStaleIntents = $job({\n cron: \"*/15 * * * *\",\n handler: async () => {\n const cutoff = this.dateTime.now().subtract(30, \"minutes\").toISOString();\n\n const stale = await this.intentRepo.findMany({\n where: { status: { eq: \"processing\" }, createdAt: { lt: cutoff } },\n });\n\n for (const intent of stale) {\n if (intent.providerRef) {\n try {\n await this.provider.expireSession(intent.providerRef);\n } catch (error) {\n this.log.warn(\n `Failed to expire session for intent ${intent.id}`,\n error,\n );\n }\n }\n await this.intentRepo.updateById(intent.id, { status: \"expired\" });\n this.log.info(`Expired stale intent ${intent.id}`);\n }\n },\n });\n\n /**\n * Create a new payment intent in \"created\" status.\n */\n public async createIntent(\n amount: number,\n currency: string,\n metadata?: unknown,\n options?: { paymentMethodId?: string; userId?: string },\n ): Promise<PaymentIntentEntity> {\n return await this.intentRepo.create({\n amount,\n currency,\n status: \"created\",\n metadata: metadata as any,\n paymentMethodId: options?.paymentMethodId,\n userId: options?.userId,\n });\n }\n\n /**\n * Create a checkout session with the payment provider and\n * transition the intent to \"processing\".\n */\n public async createSession(\n intentId: string,\n returnUrl: string,\n authorize?: boolean,\n ): Promise<{ url: string; intentId: string }> {\n const intent = await this.getIntent(intentId);\n this.assertStatus(intent, \"created\", \"createSession\");\n\n const result = await this.provider.createSession(intent, {\n returnUrl,\n authorize,\n });\n\n await this.intentRepo.updateById(intent.id, {\n status: \"processing\",\n providerRef: result.providerRef,\n });\n\n return { url: result.url, intentId: intent.id };\n }\n\n /**\n * Handle an incoming webhook from the payment provider.\n */\n public async handleWebhook(request: Request): Promise<void> {\n const event = await this.provider.parseWebhook(request);\n const intents = await this.intentRepo.findMany({\n where: { providerRef: { eq: event.providerRef } },\n limit: 1,\n });\n\n if (intents.length === 0) {\n this.log.warn(`Webhook for unknown providerRef: ${event.providerRef}`);\n return;\n }\n\n const intent = intents[0];\n await this.handleWebhookEvent(intent.id, event.status, event.raw);\n }\n\n /**\n * Process a webhook event by updating the intent status and emitting\n * the corresponding billing event.\n */\n public async handleWebhookEvent(\n intentId: string,\n status: string,\n raw?: unknown,\n ): Promise<void> {\n const intent = await this.getIntent(intentId);\n\n const eventMap = {\n authorized: \"billing:authorized\",\n captured: \"billing:captured\",\n failed: \"billing:failed\",\n } as const;\n\n type WebhookStatus = keyof typeof eventMap;\n if (!(status in eventMap)) {\n this.log.warn(`Unknown webhook status: ${status}`);\n return;\n }\n\n const webhookStatus = status as WebhookStatus;\n\n await this.intentRepo.updateById(intent.id, {\n status: webhookStatus,\n providerRaw: raw as any,\n });\n\n await this.alepha.events.emit(eventMap[webhookStatus], {\n intentId: intent.id,\n amount: intent.amount,\n currency: intent.currency,\n metadata: intent.metadata,\n });\n }\n\n /**\n * Capture a previously authorized payment. Optionally specify a different\n * amount for partial capture.\n */\n public async capture(\n intentId: string,\n finalAmount?: number,\n ): Promise<PaymentIntentEntity> {\n const intent = await this.getIntent(intentId);\n this.assertStatus(intent, \"authorized\", \"capture\");\n\n const amount = finalAmount ?? intent.amount;\n if (intent.providerRef) {\n await this.provider.capturePayment(intent.providerRef, amount);\n }\n\n const updated = await this.intentRepo.updateById(intent.id, {\n status: \"captured\",\n amount,\n });\n\n await this.alepha.events.emit(\"billing:captured\", {\n intentId: intent.id,\n amount,\n currency: intent.currency,\n metadata: intent.metadata,\n });\n\n return updated;\n }\n\n /**\n * Void a previously authorized payment before capture.\n */\n public async void(intentId: string): Promise<PaymentIntentEntity> {\n const intent = await this.getIntent(intentId);\n this.assertStatus(intent, \"authorized\", \"void\");\n\n if (intent.providerRef) {\n await this.provider.voidPayment(intent.providerRef);\n }\n\n const updated = await this.intentRepo.updateById(intent.id, {\n status: \"voided\",\n });\n\n await this.alepha.events.emit(\"billing:voided\", {\n intentId: intent.id,\n amount: intent.amount,\n currency: intent.currency,\n metadata: intent.metadata,\n });\n\n return updated;\n }\n\n /**\n * Refund a captured payment (partial or full).\n */\n public async refund(\n intentId: string,\n amount: number,\n reason?: string,\n ): Promise<RefundEntity> {\n const intent = await this.getIntent(intentId);\n this.assertStatus(intent, \"captured\", \"refund\");\n\n let refundProviderRef: string | undefined;\n if (intent.providerRef) {\n const result = await this.provider.refundPayment(\n intent.providerRef,\n amount,\n );\n refundProviderRef = result.providerRef;\n }\n\n const refund = await this.refundRepo.create({\n intentId: intent.id,\n organizationId: intent.organizationId,\n amount,\n currency: intent.currency,\n status: \"completed\",\n reason,\n providerRef: refundProviderRef,\n });\n\n await this.intentRepo.updateById(intent.id, { status: \"refunded\" });\n\n await this.alepha.events.emit(\"billing:refunded\", {\n intentId: intent.id,\n refundId: refund.id,\n amount,\n currency: intent.currency,\n metadata: intent.metadata,\n });\n\n return refund;\n }\n\n /**\n * Record a cash or offline payment directly as captured,\n * bypassing the checkout flow.\n */\n public async recordCashPayment(\n amount: number,\n currency: string,\n metadata?: unknown,\n ): Promise<PaymentIntentEntity> {\n const intent = await this.intentRepo.create({\n amount,\n currency,\n status: \"captured\",\n metadata: metadata as any,\n });\n\n await this.alepha.events.emit(\"billing:captured\", {\n intentId: intent.id,\n amount,\n currency,\n metadata,\n });\n\n return intent;\n }\n\n /**\n * Cancel a payment intent that has not yet entered processing.\n */\n public async cancel(intentId: string): Promise<PaymentIntentEntity> {\n const intent = await this.getIntent(intentId);\n this.assertStatus(intent, \"created\", \"cancel\");\n\n return await this.intentRepo.updateById(intent.id, {\n status: \"cancelled\",\n });\n }\n\n /**\n * Get a payment intent by ID. Throws NotFoundError if not found.\n */\n public async getIntent(intentId: string): Promise<PaymentIntentEntity> {\n return await this.intentRepo.getById(intentId);\n }\n\n /**\n * Find payment intents with optional filters and pagination.\n */\n public async findIntents(query: {\n status?: string;\n userId?: string;\n sort?: string;\n size?: number;\n page?: number;\n }) {\n const where = this.intentRepo.createQueryWhere();\n if (query.status)\n where.status = { eq: query.status as PaymentIntentEntity[\"status\"] };\n if (query.userId) where.userId = { eq: query.userId };\n return await this.intentRepo.paginate(query, { where }, { count: true });\n }\n\n protected assertStatus(\n intent: PaymentIntentEntity,\n expected: PaymentIntentEntity[\"status\"],\n operation: string,\n ): void {\n if (intent.status !== expected) {\n throw new BillingError(\n `Cannot ${operation}: intent ${intent.id} is '${intent.status}', expected '${expected}'`,\n );\n }\n }\n}\n","import { $inject, t } from \"alepha\";\nimport { $secure } from \"alepha/security\";\nimport { $action, okSchema } from \"alepha/server\";\nimport {\n captureIntentSchema,\n intentQuerySchema,\n intentResourceSchema,\n recordCashSchema,\n refundIntentSchema,\n} from \"../schemas/intentSchemas.ts\";\nimport { refundResourceSchema } from \"../schemas/refundSchemas.ts\";\nimport { BillingService } from \"../services/BillingService.ts\";\n\nexport class AdminBillingController {\n protected readonly url = \"/admin/billing\";\n protected readonly group = \"admin:billing\";\n protected readonly billing = $inject(BillingService);\n\n /**\n * List payment intents with pagination and filtering.\n */\n public readonly listIntents = $action({\n path: `${this.url}/intents`,\n group: this.group,\n use: [$secure({ permissions: [\"billing:read\"] })],\n description: \"List payment intents\",\n schema: {\n query: intentQuerySchema,\n response: t.page(intentResourceSchema),\n },\n handler: ({ query }) => this.billing.findIntents(query),\n });\n\n /**\n * Get a payment intent by ID.\n */\n public readonly getIntent = $action({\n path: `${this.url}/intents/:id`,\n group: this.group,\n use: [$secure({ permissions: [\"billing:read\"] })],\n description: \"Get payment intent details\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: intentResourceSchema,\n },\n handler: ({ params }) => this.billing.getIntent(params.id),\n });\n\n /**\n * Capture an authorized intent.\n */\n public readonly captureIntent = $action({\n method: \"POST\",\n path: `${this.url}/intents/:id/capture`,\n group: this.group,\n use: [$secure({ permissions: [\"billing:write\"] })],\n description: \"Capture an authorized payment intent\",\n schema: {\n params: t.object({ id: t.uuid() }),\n body: captureIntentSchema,\n response: intentResourceSchema,\n },\n handler: ({ params, body }) => this.billing.capture(params.id, body.amount),\n });\n\n /**\n * Void an authorized intent.\n */\n public readonly voidIntent = $action({\n method: \"POST\",\n path: `${this.url}/intents/:id/void`,\n group: this.group,\n use: [$secure({ permissions: [\"billing:write\"] })],\n description: \"Void an authorized payment intent\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: intentResourceSchema,\n },\n handler: ({ params }) => this.billing.void(params.id),\n });\n\n /**\n * Refund a captured intent.\n */\n public readonly refundIntent = $action({\n method: \"POST\",\n path: `${this.url}/intents/:id/refund`,\n group: this.group,\n use: [$secure({ permissions: [\"billing:write\"] })],\n description: \"Issue partial or full refund\",\n schema: {\n params: t.object({ id: t.uuid() }),\n body: refundIntentSchema,\n response: refundResourceSchema,\n },\n handler: ({ params, body }) =>\n this.billing.refund(params.id, body.amount, body.reason),\n });\n\n /**\n * Cancel a created intent.\n */\n public readonly cancelIntent = $action({\n method: \"POST\",\n path: `${this.url}/intents/:id/cancel`,\n group: this.group,\n use: [$secure({ permissions: [\"billing:write\"] })],\n description: \"Cancel a created payment intent\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: intentResourceSchema,\n },\n handler: ({ params }) => this.billing.cancel(params.id),\n });\n\n /**\n * Record a cash payment.\n */\n public readonly recordCash = $action({\n method: \"POST\",\n path: `${this.url}/cash`,\n group: this.group,\n use: [$secure({ permissions: [\"billing:write\"] })],\n description: \"Record a cash payment\",\n schema: {\n body: recordCashSchema,\n response: intentResourceSchema,\n },\n handler: ({ body }) =>\n this.billing.recordCashPayment(body.amount, body.currency, body.metadata),\n });\n\n /**\n * PSP webhook endpoint (not under /admin, no auth — verified by provider).\n */\n public readonly webhook = $action({\n method: \"POST\",\n path: \"/billing/webhook\",\n group: this.group,\n description: \"PSP webhook endpoint\",\n schema: {\n response: okSchema,\n },\n handler: async (request) => {\n await this.billing.handleWebhook(request.raw.web!.req);\n return { ok: true };\n },\n });\n}\n","import { type Static, t } from \"alepha\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const paymentMethods = $entity({\n name: \"payment_methods\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n version: db.version(),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n organizationId: db.organization(),\n userId: t.uuid(),\n type: t.text({ size: \"short\" }),\n brand: t.optional(t.text({ size: \"short\" })),\n last4: t.optional(t.text({ size: \"short\" })),\n expMonth: t.optional(t.integer()),\n expYear: t.optional(t.integer()),\n isDefault: t.boolean(),\n providerRef: t.text(),\n }),\n indexes: [\"userId\", \"organizationId\"],\n});\n\nexport type PaymentMethodEntity = Static<typeof paymentMethods.schema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { paymentMethods } from \"../entities/paymentMethods.ts\";\n\nexport const addPaymentMethodSchema = t.object({\n token: t.text(),\n});\n\nexport type AddPaymentMethod = Static<typeof addPaymentMethodSchema>;\n\nexport const paymentMethodResourceSchema = paymentMethods.schema;\n\nexport type PaymentMethodResource = Static<typeof paymentMethodResourceSchema>;\n","import { $inject } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport {\n type PaymentMethodEntity,\n paymentMethods,\n} from \"../entities/paymentMethods.ts\";\nimport { BillingError } from \"../errors/BillingError.ts\";\nimport { BillingProvider } from \"../providers/BillingProvider.ts\";\n\nexport class PaymentMethodService {\n protected readonly log = $logger();\n protected readonly provider = $inject(BillingProvider);\n protected readonly methodRepo = $repository(paymentMethods);\n\n public async addPaymentMethod(\n userId: string,\n organizationId: string,\n token: string,\n ): Promise<PaymentMethodEntity> {\n const result = await this.provider.createPaymentMethod(userId, token);\n\n const existing = await this.methodRepo.findMany({\n where: { userId: { eq: userId } },\n });\n\n return await this.methodRepo.create({\n userId,\n organizationId,\n type: result.type,\n brand: result.brand,\n last4: result.last4,\n expMonth: result.expMonth,\n expYear: result.expYear,\n isDefault: existing.length === 0,\n providerRef: result.providerRef,\n });\n }\n\n public async listPaymentMethods(\n userId: string,\n ): Promise<PaymentMethodEntity[]> {\n return await this.methodRepo.findMany({\n where: { userId: { eq: userId } },\n });\n }\n\n public async removePaymentMethod(\n methodId: string,\n userId: string,\n ): Promise<void> {\n const method = await this.methodRepo.getById(methodId);\n if (method.userId !== userId) {\n throw new BillingError(\"Cannot remove another user's payment method\");\n }\n\n await this.provider.deletePaymentMethod(method.providerRef);\n await this.methodRepo.deleteById(method.id);\n }\n\n public async setDefault(\n methodId: string,\n userId: string,\n ): Promise<PaymentMethodEntity> {\n const method = await this.methodRepo.getById(methodId);\n if (method.userId !== userId) {\n throw new BillingError(\"Cannot modify another user's payment method\");\n }\n\n const userMethods = await this.methodRepo.findMany({\n where: { userId: { eq: userId } },\n });\n\n for (const m of userMethods) {\n if (m.isDefault) {\n await this.methodRepo.updateById(m.id, { isDefault: false });\n }\n }\n\n return await this.methodRepo.updateById(method.id, { isDefault: true });\n }\n}\n","import { $inject, t } from \"alepha\";\nimport { $secure } from \"alepha/security\";\nimport { $action, okSchema } from \"alepha/server\";\nimport {\n checkoutResponseSchema,\n createCheckoutSchema,\n} from \"../schemas/intentSchemas.ts\";\nimport {\n addPaymentMethodSchema,\n paymentMethodResourceSchema,\n} from \"../schemas/paymentMethodSchemas.ts\";\nimport { BillingService } from \"../services/BillingService.ts\";\nimport { PaymentMethodService } from \"../services/PaymentMethodService.ts\";\n\nexport class BillingController {\n protected readonly url = \"/billing\";\n protected readonly group = \"billing\";\n protected readonly billing = $inject(BillingService);\n protected readonly paymentMethods = $inject(PaymentMethodService);\n\n /**\n * List the current user's saved payment methods.\n */\n public readonly listPaymentMethods = $action({\n path: `${this.url}/payment-methods`,\n group: this.group,\n use: [$secure()],\n description: \"List current user's saved payment methods\",\n schema: {\n response: t.array(paymentMethodResourceSchema),\n },\n handler: ({ user }) => this.paymentMethods.listPaymentMethods(user.id),\n });\n\n /**\n * Add a new payment method.\n */\n public readonly addPaymentMethod = $action({\n method: \"POST\",\n path: `${this.url}/payment-methods`,\n group: this.group,\n use: [$secure()],\n description: \"Tokenize and store a new payment method\",\n schema: {\n body: addPaymentMethodSchema,\n response: paymentMethodResourceSchema,\n },\n handler: ({ body, user }) =>\n this.paymentMethods.addPaymentMethod(\n user.id,\n user.organization!,\n body.token,\n ),\n });\n\n /**\n * Remove a payment method.\n */\n public readonly removePaymentMethod = $action({\n method: \"DELETE\",\n path: `${this.url}/payment-methods/:id`,\n group: this.group,\n use: [$secure()],\n description: \"Remove own payment method\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: okSchema,\n },\n handler: async ({ params, user }) => {\n await this.paymentMethods.removePaymentMethod(params.id, user.id);\n return { ok: true, id: params.id };\n },\n });\n\n /**\n * Set a payment method as default.\n */\n public readonly setDefaultPaymentMethod = $action({\n method: \"PATCH\",\n path: `${this.url}/payment-methods/:id/default`,\n group: this.group,\n use: [$secure()],\n description: \"Set as default payment method\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: paymentMethodResourceSchema,\n },\n handler: ({ params, user }) =>\n this.paymentMethods.setDefault(params.id, user.id),\n });\n\n /**\n * Create a checkout session.\n */\n public readonly createCheckout = $action({\n method: \"POST\",\n path: `${this.url}/checkout`,\n group: this.group,\n use: [$secure()],\n description: \"Create checkout session and return URL\",\n schema: {\n body: createCheckoutSchema,\n response: checkoutResponseSchema,\n },\n handler: ({ body }) =>\n this.billing.createSession(body.intentId, body.returnUrl, body.authorize),\n });\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { PaymentIntentEntity } from \"../entities/paymentIntents.ts\";\nimport type {\n BillingProvider,\n CreatePaymentMethodResult,\n CreateSessionResult,\n RefundResult,\n WebhookEvent,\n} from \"./BillingProvider.ts\";\n\ninterface MemoryCharge {\n providerRef: string;\n amount: number;\n status: string;\n}\n\ninterface MemoryRefund {\n providerRef: string;\n chargeRef: string;\n amount: number;\n}\n\nexport class MemoryBillingProvider implements BillingProvider {\n protected readonly charges: Map<string, MemoryCharge> = new Map();\n protected readonly refundRecords: Map<string, MemoryRefund> = new Map();\n protected readonly methods: Map<string, CreatePaymentMethodResult> =\n new Map();\n protected readonly expiredSessions: Set<string> = new Set();\n\n public async createSession(\n intent: PaymentIntentEntity,\n options: { returnUrl: string; authorize?: boolean },\n ): Promise<CreateSessionResult> {\n const providerRef = `mem_session_${randomUUID()}`;\n const status = options.authorize ? \"authorized\" : \"captured\";\n this.charges.set(providerRef, {\n providerRef,\n amount: intent.amount,\n status,\n });\n return {\n url: `/billing/mock-checkout/${intent.id}`,\n providerRef,\n };\n }\n\n public async capturePayment(\n providerRef: string,\n amount: number,\n ): Promise<void> {\n const charge = this.charges.get(providerRef);\n if (charge) {\n charge.status = \"captured\";\n charge.amount = amount;\n }\n }\n\n public async voidPayment(providerRef: string): Promise<void> {\n const charge = this.charges.get(providerRef);\n if (charge) {\n charge.status = \"voided\";\n }\n }\n\n public async refundPayment(\n providerRef: string,\n amount: number,\n ): Promise<RefundResult> {\n const refundRef = `mem_refund_${randomUUID()}`;\n this.refundRecords.set(refundRef, {\n providerRef: refundRef,\n chargeRef: providerRef,\n amount,\n });\n return { providerRef: refundRef };\n }\n\n public async parseWebhook(request: Request): Promise<WebhookEvent> {\n const body = (await request.json()) as {\n providerRef: string;\n status: string;\n };\n return {\n providerRef: body.providerRef,\n status: body.status,\n raw: body,\n };\n }\n\n public async createPaymentMethod(\n userId: string,\n token: string,\n ): Promise<CreatePaymentMethodResult> {\n const providerRef = `mem_pm_${randomUUID()}`;\n const result: CreatePaymentMethodResult = {\n providerRef,\n type: \"card\",\n brand: \"visa\",\n last4: \"4242\",\n expMonth: 12,\n expYear: 2030,\n };\n this.methods.set(providerRef, result);\n return result;\n }\n\n public async deletePaymentMethod(providerRef: string): Promise<void> {\n this.methods.delete(providerRef);\n }\n\n public async expireSession(providerRef: string): Promise<void> {\n this.expiredSessions.add(providerRef);\n }\n\n // --- Test assertion helpers ---\n\n public wasCharged(providerRef: string): boolean {\n const charge = this.charges.get(providerRef);\n return charge?.status === \"captured\";\n }\n\n public wasRefunded(providerRef: string): boolean {\n return Array.from(this.refundRecords.values()).some(\n (r) => r.chargeRef === providerRef,\n );\n }\n\n public wasExpired(providerRef: string): boolean {\n return this.expiredSessions.has(providerRef);\n }\n\n public getCharges(): MemoryCharge[] {\n return Array.from(this.charges.values());\n }\n\n public getRefunds(): MemoryRefund[] {\n return Array.from(this.refundRecords.values());\n }\n}\n","import { $module } from \"alepha\";\nimport { AdminBillingController } from \"./controllers/AdminBillingController.ts\";\nimport { BillingController } from \"./controllers/BillingController.ts\";\nimport { BillingProvider } from \"./providers/BillingProvider.ts\";\nimport { MemoryBillingProvider } from \"./providers/MemoryBillingProvider.ts\";\nimport { BillingService } from \"./services/BillingService.ts\";\nimport { PaymentMethodService } from \"./services/PaymentMethodService.ts\";\n\nexport * from \"./controllers/AdminBillingController.ts\";\nexport * from \"./controllers/BillingController.ts\";\nexport * from \"./entities/paymentIntents.ts\";\nexport * from \"./entities/paymentMethods.ts\";\nexport * from \"./entities/refunds.ts\";\nexport * from \"./errors/BillingError.ts\";\nexport * from \"./providers/BillingProvider.ts\";\nexport * from \"./providers/MemoryBillingProvider.ts\";\nexport * from \"./schemas/intentSchemas.ts\";\nexport * from \"./schemas/paymentMethodSchemas.ts\";\nexport * from \"./schemas/refundSchemas.ts\";\nexport * from \"./services/BillingService.ts\";\nexport * from \"./services/PaymentMethodService.ts\";\n\ndeclare module \"alepha\" {\n interface Hooks {\n \"billing:authorized\": {\n intentId: string;\n amount: number;\n currency: string;\n metadata?: unknown;\n };\n \"billing:captured\": {\n intentId: string;\n amount: number;\n currency: string;\n metadata?: unknown;\n };\n \"billing:failed\": {\n intentId: string;\n amount: number;\n currency: string;\n metadata?: unknown;\n };\n \"billing:voided\": {\n intentId: string;\n amount: number;\n currency: string;\n metadata?: unknown;\n };\n \"billing:refunded\": {\n intentId: string;\n refundId: string;\n amount: number;\n currency: string;\n metadata?: unknown;\n };\n }\n}\n\nexport const AlephaBilling = $module({\n name: \"alepha.billing\",\n services: [\n AdminBillingController,\n BillingController,\n BillingProvider,\n MemoryBillingProvider,\n BillingService,\n PaymentMethodService,\n ],\n register: (alepha) => {\n alepha.with({\n optional: true,\n provide: BillingProvider,\n use: MemoryBillingProvider,\n });\n },\n});\n"],"mappings":"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"}
|
package/dist/bin/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Alepha, run } from "alepha";
|
|
3
3
|
import { AlephaCli, version } from "alepha/cli";
|
|
4
|
-
import { AlephaCliPlatform } from "alepha/cli/platform";
|
|
5
4
|
//#region ../../src/bin/index.ts
|
|
6
5
|
const alepha = Alepha.create({ env: {
|
|
7
6
|
APP_NAME: "CLI",
|
|
@@ -11,7 +10,6 @@ const alepha = Alepha.create({ env: {
|
|
|
11
10
|
LOG_LEVEL: process.env.LOG_LEVEL ?? "alepha.core:warn,info"
|
|
12
11
|
} });
|
|
13
12
|
alepha.with(AlephaCli);
|
|
14
|
-
alepha.with(AlephaCliPlatform);
|
|
15
13
|
run(alepha);
|
|
16
14
|
//#endregion
|
|
17
15
|
export {};
|
package/dist/bin/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/bin/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Alepha, run } from \"alepha\";\nimport { AlephaCli, version } from \"alepha/cli\";\
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/bin/index.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Alepha, run } from \"alepha\";\nimport { AlephaCli, version } from \"alepha/cli\";\n\nconst alepha = Alepha.create({\n env: {\n APP_NAME: \"CLI\",\n CLI_NAME: \"alepha\",\n CLI_DESCRIPTION: `Alepha CLI v${version} - Create and manage Alepha projects.`,\n LOG_FORMAT: (process.env.LOG_FORMAT ?? \"raw\") as any,\n LOG_LEVEL: process.env.LOG_LEVEL ?? \"alepha.core:warn,info\",\n },\n});\n\nalepha.with(AlephaCli);\n\nrun(alepha);\n"],"mappings":";;;;AAIA,MAAM,SAAS,OAAO,OAAO,EAC3B,KAAK;CACH,UAAU;CACV,UAAU;CACV,iBAAiB,eAAe,QAAQ;CACxC,YAAa,QAAQ,IAAI,cAAc;CACvC,WAAW,QAAQ,IAAI,aAAa;CACrC,EACF,CAAC;AAEF,OAAO,KAAK,UAAU;AAEtB,IAAI,OAAO"}
|
package/dist/bucket/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import * as alepha from "alepha";
|
|
1
|
+
import * as _$alepha from "alepha";
|
|
2
2
|
import { Alepha, AlephaError, FileLike, KIND, Primitive, Service, Static } from "alepha";
|
|
3
3
|
import { FileDetector, FileSystemProvider } from "alepha/system";
|
|
4
4
|
import * as fs from "node:fs";
|
|
5
|
-
import * as alepha_logger0 from "alepha/logger";
|
|
5
|
+
import * as _$alepha_logger0 from "alepha/logger";
|
|
6
6
|
|
|
7
7
|
//#region ../../src/bucket/providers/FileStorageProvider.d.ts
|
|
8
8
|
declare abstract class FileStorageProvider {
|
|
@@ -440,7 +440,7 @@ interface R2UploadedPart {
|
|
|
440
440
|
*/
|
|
441
441
|
declare class CloudflareR2Provider implements FileStorageProvider {
|
|
442
442
|
protected readonly alepha: Alepha;
|
|
443
|
-
protected readonly log: alepha_logger0.Logger;
|
|
443
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
444
444
|
protected readonly env: {
|
|
445
445
|
R2_BUCKET_NAME: string;
|
|
446
446
|
};
|
|
@@ -454,7 +454,7 @@ declare class CloudflareR2Provider implements FileStorageProvider {
|
|
|
454
454
|
* Used for multi-app setups sharing the same R2 bucket.
|
|
455
455
|
*/
|
|
456
456
|
get prefix(): string | undefined;
|
|
457
|
-
protected readonly onStart: alepha.HookPrimitive<"start">;
|
|
457
|
+
protected readonly onStart: _$alepha.HookPrimitive<"start">;
|
|
458
458
|
upload(bucketName: string, file: FileLike, fileId?: string): Promise<string>;
|
|
459
459
|
download(bucketName: string, fileId: string): Promise<FileLike>;
|
|
460
460
|
exists(bucketName: string, fileId: string): Promise<boolean>;
|
|
@@ -471,8 +471,8 @@ declare class CloudflareR2Provider implements FileStorageProvider {
|
|
|
471
471
|
/**
|
|
472
472
|
* Local file storage configuration atom
|
|
473
473
|
*/
|
|
474
|
-
declare const localFileStorageOptions: alepha.Atom<alepha.TObject<{
|
|
475
|
-
storagePath: alepha.TString;
|
|
474
|
+
declare const localFileStorageOptions: _$alepha.Atom<_$alepha.TObject<{
|
|
475
|
+
storagePath: _$alepha.TString;
|
|
476
476
|
}>, "alepha.bucket.local.options">;
|
|
477
477
|
type LocalFileStorageProviderOptions = Static<typeof localFileStorageOptions.schema>;
|
|
478
478
|
declare module "alepha" {
|
|
@@ -482,15 +482,15 @@ declare module "alepha" {
|
|
|
482
482
|
}
|
|
483
483
|
declare class LocalFileStorageProvider implements FileStorageProvider {
|
|
484
484
|
protected readonly alepha: Alepha;
|
|
485
|
-
protected readonly log: alepha_logger0.Logger;
|
|
485
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
486
486
|
protected readonly fileDetector: FileDetector;
|
|
487
487
|
protected readonly fileSystemProvider: FileSystemProvider;
|
|
488
488
|
protected readonly options: Readonly<{
|
|
489
489
|
storagePath: string;
|
|
490
490
|
}>;
|
|
491
491
|
protected get storagePath(): string;
|
|
492
|
-
protected readonly onConfigure: alepha.HookPrimitive<"configure">;
|
|
493
|
-
protected readonly onStart: alepha.HookPrimitive<"start">;
|
|
492
|
+
protected readonly onConfigure: _$alepha.HookPrimitive<"configure">;
|
|
493
|
+
protected readonly onStart: _$alepha.HookPrimitive<"start">;
|
|
494
494
|
upload(bucketName: string, file: FileLike, fileId?: string): Promise<string>;
|
|
495
495
|
download(bucketName: string, fileId: string): Promise<FileLike>;
|
|
496
496
|
exists(bucketName: string, fileId: string): Promise<boolean>;
|
|
@@ -537,7 +537,7 @@ declare module "alepha" {
|
|
|
537
537
|
*
|
|
538
538
|
* @module alepha.bucket
|
|
539
539
|
*/
|
|
540
|
-
declare const AlephaBucket: alepha.Service<alepha.Module>;
|
|
540
|
+
declare const AlephaBucket: _$alepha.Service<_$alepha.Module>;
|
|
541
541
|
//#endregion
|
|
542
542
|
export { $bucket, AlephaBucket, BucketFileOptions, BucketPrimitive, BucketPrimitiveOptions, CloudflareR2Provider, FileNotFoundError, FileStorageProvider, LocalFileStorageProvider, LocalFileStorageProviderOptions, MemoryFileStorageProvider, R2Bucket, R2Checksums, R2Conditional, R2GetOptions, R2HTTPMetadata, R2ListOptions, R2MultipartOptions, R2MultipartUpload, R2Object, R2ObjectBody, R2Objects, R2PutOptions, R2Range, R2UploadedPart, localFileStorageOptions };
|
|
543
543
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/bucket/providers/FileStorageProvider.ts","../../src/bucket/providers/MemoryFileStorageProvider.ts","../../src/bucket/primitives/$bucket.ts","../../src/bucket/errors/FileNotFoundError.ts","../../src/bucket/providers/CloudflareR2Provider.ts","../../src/bucket/providers/LocalFileStorageProvider.ts","../../src/bucket/index.ts"],"mappings":"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
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/bucket/providers/FileStorageProvider.ts","../../src/bucket/providers/MemoryFileStorageProvider.ts","../../src/bucket/primitives/$bucket.ts","../../src/bucket/errors/FileNotFoundError.ts","../../src/bucket/providers/CloudflareR2Provider.ts","../../src/bucket/providers/LocalFileStorageProvider.ts","../../src/bucket/index.ts"],"mappings":"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"}
|
package/dist/bucket/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $atom, $env, $hook, $inject, $module, $
|
|
1
|
+
import { $atom, $env, $hook, $inject, $module, $state, Alepha, AlephaError, KIND, Primitive, createPrimitive, t } from "alepha";
|
|
2
2
|
import { FileDetector, FileSystemProvider } from "alepha/system";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { createReadStream } from "node:fs";
|
|
@@ -188,7 +188,7 @@ var LocalFileStorageProvider = class {
|
|
|
188
188
|
log = $logger();
|
|
189
189
|
fileDetector = $inject(FileDetector);
|
|
190
190
|
fileSystemProvider = $inject(FileSystemProvider);
|
|
191
|
-
options = $
|
|
191
|
+
options = $state(localFileStorageOptions);
|
|
192
192
|
get storagePath() {
|
|
193
193
|
return this.options.storagePath;
|
|
194
194
|
}
|
package/dist/bucket/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/bucket/errors/InvalidFileError.ts","../../src/bucket/providers/FileStorageProvider.ts","../../src/bucket/errors/FileNotFoundError.ts","../../src/bucket/providers/MemoryFileStorageProvider.ts","../../src/bucket/primitives/$bucket.ts","../../src/bucket/providers/LocalFileStorageProvider.ts","../../src/bucket/providers/CloudflareR2Provider.ts","../../src/bucket/index.ts"],"sourcesContent":["import { AlephaError } from \"alepha\";\n\nexport class InvalidFileError extends AlephaError {\n public readonly status = 400;\n}\n","import type { FileLike } from \"alepha\";\n\nexport abstract class FileStorageProvider {\n /**\n * Uploads a file to the storage.\n *\n * @param bucketName - Container name\n * @param file - File to upload\n * @param fileId - Optional file identifier. If not provided, a unique ID will be generated.\n * @return The identifier of the uploaded file.\n */\n abstract upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string>;\n\n /**\n * Downloads a file from the storage.\n *\n * @param bucketName - Container name\n * @param fileId - Identifier of the file to download\n * @return The downloaded file as a FileLike object.\n */\n abstract download(bucketName: string, fileId: string): Promise<FileLike>;\n\n /**\n * Check if fileId exists in the storage bucket.\n *\n * @param bucketName - Container name\n * @param fileId - Identifier of the file to stream\n * @return True is the file exists, false otherwise.\n */\n abstract exists(bucketName: string, fileId: string): Promise<boolean>;\n\n /**\n * Delete permanently a file from the storage.\n *\n * @param bucketName - Container name\n * @param fileId - Identifier of the file to delete\n */\n abstract delete(bucketName: string, fileId: string): Promise<void>;\n}\n","import { AlephaError } from \"alepha\";\n\nexport class FileNotFoundError extends AlephaError {\n public readonly status = 404;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { $inject, type FileLike } from \"alepha\";\nimport { FileDetector, FileSystemProvider } from \"alepha/system\";\nimport { FileNotFoundError } from \"../errors/FileNotFoundError.ts\";\nimport type { FileStorageProvider } from \"./FileStorageProvider.ts\";\n\ninterface StoredFile {\n buffer: Buffer;\n name: string;\n type: string;\n size: number;\n}\n\nexport class MemoryFileStorageProvider implements FileStorageProvider {\n public readonly files: Record<string, StoredFile> = {};\n protected readonly fileSystem = $inject(FileSystemProvider);\n protected readonly fileDetector = $inject(FileDetector);\n\n public async upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string> {\n fileId ??= this.createId();\n\n // Consume the stream and store as buffer so downloads are repeatable\n const chunks: Uint8Array[] = [];\n for await (const chunk of file.stream() as AsyncIterable<Uint8Array>) {\n chunks.push(chunk);\n }\n const buffer = Buffer.concat(chunks);\n\n this.files[`${bucketName}/${fileId}`] = {\n buffer,\n name: file.name,\n type: file.type,\n size: file.size,\n };\n\n return fileId;\n }\n\n public async download(bucketName: string, fileId: string): Promise<FileLike> {\n const fileKey = `${bucketName}/${fileId}`;\n const stored = this.files[fileKey];\n\n if (!stored) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n\n // Create a fresh FileLike with a new stream from the stored buffer\n return this.fileSystem.createFile({\n stream: new Blob([new Uint8Array(stored.buffer)]).stream(),\n name: stored.name,\n type: stored.type,\n size: stored.size,\n });\n }\n\n public async exists(bucketName: string, fileId: string): Promise<boolean> {\n return `${bucketName}/${fileId}` in this.files;\n }\n\n public async delete(bucketName: string, fileId: string): Promise<void> {\n const fileKey = `${bucketName}/${fileId}`;\n if (!(fileKey in this.files)) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n\n delete this.files[fileKey];\n }\n\n protected createId(): string {\n return randomUUID();\n }\n}\n","import {\n $inject,\n createPrimitive,\n type FileLike,\n KIND,\n Primitive,\n type Service,\n} from \"alepha\";\nimport { FileSystemProvider } from \"alepha/system\";\nimport { InvalidFileError } from \"../errors/InvalidFileError.ts\";\nimport { FileStorageProvider } from \"../providers/FileStorageProvider.ts\";\nimport { MemoryFileStorageProvider } from \"../providers/MemoryFileStorageProvider.ts\";\n\n/**\n * Creates a bucket primitive for file storage and management with configurable validation.\n *\n * Provides a comprehensive file storage system that handles uploads, downloads, validation,\n * and management across multiple storage backends with MIME type and size limit controls.\n *\n * **Key Features**\n * - Multi-provider support (filesystem, cloud storage, in-memory)\n * - Automatic MIME type and file size validation\n * - Event integration for file operations monitoring\n * - Flexible per-bucket and per-operation configuration\n * - Smart file type and size detection\n *\n * **Common Use Cases**\n * - User profile pictures and document uploads\n * - Product images and media management\n * - Document storage and retrieval systems\n *\n * @example\n * ```ts\n * class MediaService {\n * images = $bucket({\n * name: \"user-images\",\n * mimeTypes: [\"image/jpeg\", \"image/png\", \"image/gif\"],\n * maxSize: 5 // 5MB limit\n * });\n *\n * documents = $bucket({\n * name: \"documents\",\n * mimeTypes: [\"application/pdf\", \"text/plain\"],\n * maxSize: 50 // 50MB limit\n * });\n *\n * async uploadProfileImage(file: FileLike, userId: string): Promise<string> {\n * const fileId = await this.images.upload(file);\n * await this.userService.updateProfileImage(userId, fileId);\n * return fileId;\n * }\n *\n * async downloadDocument(documentId: string): Promise<FileLike> {\n * return await this.documents.download(documentId);\n * }\n *\n * async deleteDocument(documentId: string): Promise<void> {\n * await this.documents.delete(documentId);\n * }\n * }\n * ```\n */\nexport const $bucket = (options: BucketPrimitiveOptions) =>\n createPrimitive(BucketPrimitive, options);\n\nexport interface BucketPrimitiveOptions extends BucketFileOptions {\n /**\n * File storage provider configuration for the bucket.\n *\n * Options:\n * - **\"memory\"**: In-memory storage (default for development, lost on restart)\n * - **Service<FileStorageProvider>**: Custom provider class (e.g., S3FileStorageProvider, AzureBlobProvider)\n * - **undefined**: Uses the default file storage provider from dependency injection\n *\n * **Provider Selection Guidelines**:\n * - **Development**: Use \"memory\" for fast, simple testing without external dependencies\n * - **Production**: Use cloud providers (S3, Azure Blob, Google Cloud Storage) for scalability\n * - **Local deployment**: Use filesystem providers for on-premise installations\n * - **Hybrid**: Use different providers for different bucket types (temp files vs permanent storage)\n *\n * **Provider Capabilities**:\n * - File persistence and durability guarantees\n * - Scalability and performance characteristics\n * - Geographic distribution and CDN integration\n * - Cost implications for storage and bandwidth\n * - Backup and disaster recovery features\n *\n * @default Uses injected FileStorageProvider\n * @example \"memory\"\n * @example S3FileStorageProvider\n * @example AzureBlobStorageProvider\n */\n provider?: Service<FileStorageProvider> | \"memory\";\n\n /**\n * Unique name identifier for the bucket.\n *\n * This name is used for:\n * - Storage backend organization and partitioning\n * - File path generation and URL construction\n * - Logging, monitoring, and debugging\n * - Access control and permissions management\n * - Backup and replication configuration\n *\n * **Naming Conventions**:\n * - Use lowercase with hyphens for consistency\n * - Include purpose or content type in the name\n * - Avoid spaces and special characters\n * - Consider environment prefixes for deployment isolation\n *\n * If not provided, defaults to the property key where the bucket is declared.\n *\n * @example \"user-avatars\"\n * @example \"product-images\"\n * @example \"legal-documents\"\n * @example \"temp-processing-files\"\n */\n name?: string;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BucketFileOptions {\n /**\n * Human-readable description of the bucket's purpose and contents.\n *\n * Used for:\n * - Documentation generation and API references\n * - Developer onboarding and system understanding\n * - Monitoring dashboards and admin interfaces\n * - Compliance and audit documentation\n *\n * **Description Best Practices**:\n * - Explain what types of files this bucket stores\n * - Mention any special handling or processing requirements\n * - Include information about retention policies if applicable\n * - Note any compliance or security considerations\n *\n * @example \"User profile pictures and avatar images\"\n * @example \"Product catalog images with automated thumbnail generation\"\n * @example \"Legal documents requiring long-term retention\"\n * @example \"Temporary files for data processing workflows\"\n */\n description?: string;\n\n /**\n * Array of allowed MIME types for files uploaded to this bucket.\n *\n * When specified, only files with these exact MIME types will be accepted.\n * Files with disallowed MIME types will be rejected with an InvalidFileError.\n *\n * **MIME Type Categories**:\n * - Images: \"image/jpeg\", \"image/png\", \"image/gif\", \"image/webp\", \"image/svg+xml\"\n * - Documents: \"application/pdf\", \"text/plain\", \"text/csv\"\n * - Office: \"application/msword\", \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\"\n * - Archives: \"application/zip\", \"application/x-tar\", \"application/gzip\"\n * - Media: \"video/mp4\", \"audio/mpeg\", \"audio/wav\"\n *\n * **Security Considerations**:\n * - Always validate MIME types for user uploads\n * - Be cautious with executable file types\n * - Consider using allow-lists rather than deny-lists\n * - Remember that MIME types can be spoofed by malicious users\n *\n * If not specified, all MIME types are allowed (not recommended for user uploads).\n *\n * @example [\"image/jpeg\", \"image/png\"] // Only JPEG and PNG images\n * @example [\"application/pdf\", \"text/plain\"] // Documents only\n * @example [\"video/mp4\", \"video/webm\"] // Video files\n */\n mimeTypes?: string[];\n\n /**\n * Maximum file size allowed in megabytes (MB).\n *\n * Files larger than this limit will be rejected with an InvalidFileError.\n * This helps prevent:\n * - Storage quota exhaustion\n * - Memory issues during file processing\n * - Long upload times and timeouts\n * - Abuse of storage resources\n *\n * **Size Guidelines by File Type**:\n * - Profile images: 1-5 MB\n * - Product photos: 5-10 MB\n * - Documents: 10-50 MB\n * - Video files: 50-500 MB\n * - Data files: 100-1000 MB\n *\n * **Considerations**:\n * - Consider your storage costs and limits\n * - Factor in network upload speeds for users\n * - Account for processing requirements (thumbnails, compression)\n * - Set reasonable limits based on actual use cases\n *\n * @default 10 MB\n *\n * @example 1 // 1MB for small images\n * @example 25 // 25MB for documents\n * @example 100 // 100MB for media files\n */\n maxSize?: number;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class BucketPrimitive extends Primitive<BucketPrimitiveOptions> {\n public readonly provider = this.$provider();\n protected readonly fileSystem = $inject(FileSystemProvider);\n\n public get name() {\n return this.options.name ?? `${this.config.propertyKey}`;\n }\n\n /**\n * Uploads a file to the bucket.\n */\n public async upload(\n file: FileLike,\n options?: BucketFileOptions,\n ): Promise<string> {\n if (file instanceof File) {\n // our createFile is smarter than the browser's File constructor\n // by doing this, we can guess the MIME type and size!\n file = this.fileSystem.createFile({ file });\n }\n\n options = {\n ...this.options,\n ...options,\n };\n\n const mimeTypes = options.mimeTypes ?? undefined;\n const maxSize = options.maxSize ?? 10; // Default to 10 MB if not specified\n\n if (mimeTypes) {\n const mimeType = file.type || \"application/octet-stream\";\n if (!mimeTypes.includes(mimeType)) {\n throw new InvalidFileError(\n `MIME type ${mimeType} is not allowed in bucket ${this.name}`,\n );\n }\n }\n\n // check size in bytes, convert MB to bytes\n if (file.size > maxSize * 1024 * 1024) {\n throw new InvalidFileError(\n `File size ${file.size} exceeds the maximum size of ${maxSize} MB in bucket ${this.name}`,\n );\n }\n\n const id = await this.provider.upload(this.name, file);\n\n await this.alepha.events.emit(\"bucket:file:uploaded\", {\n id,\n bucket: this,\n file,\n options,\n });\n\n return id;\n }\n\n /**\n * Delete permanently a file from the bucket.\n */\n public async delete(fileId: string, skipHook = false): Promise<void> {\n await this.provider.delete(this.name, fileId);\n\n if (skipHook) {\n return;\n }\n\n await this.alepha.events.emit(\"bucket:file:deleted\", {\n id: fileId,\n bucket: this,\n });\n }\n\n /**\n * Checks if a file exists in the bucket.\n */\n public async exists(fileId: string): Promise<boolean> {\n return this.provider.exists(this.name, fileId);\n }\n\n /**\n * Downloads a file from the bucket.\n */\n public async download(fileId: string): Promise<FileLike> {\n return this.provider.download(this.name, fileId);\n }\n\n protected $provider() {\n if (!this.options.provider) {\n return this.alepha.inject(FileStorageProvider);\n }\n if (this.options.provider === \"memory\") {\n return this.alepha.inject(MemoryFileStorageProvider);\n }\n return this.alepha.inject(this.options.provider);\n }\n}\n\n$bucket[KIND] = BucketPrimitive;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BucketFileOptions {\n /**\n * Optional description of the bucket.\n */\n description?: string;\n\n /**\n * Allowed MIME types.\n */\n mimeTypes?: string[];\n\n /**\n * Maximum size of the files in the bucket.\n *\n * @default 10\n */\n maxSize?: number;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type * as fs from \"node:fs\";\nimport { createReadStream } from \"node:fs\";\nimport { mkdir, stat, unlink } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n $atom,\n $hook,\n $inject,\n $use,\n Alepha,\n AlephaError,\n type FileLike,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { FileDetector, FileSystemProvider } from \"alepha/system\";\nimport { FileNotFoundError } from \"../errors/FileNotFoundError.ts\";\nimport { $bucket } from \"../primitives/$bucket.ts\";\nimport type { FileStorageProvider } from \"./FileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Local file storage configuration atom\n */\nexport const localFileStorageOptions = $atom({\n name: \"alepha.bucket.local.options\",\n schema: t.object({\n storagePath: t.string({\n description: \"Directory path where files will be stored\",\n }),\n }),\n default: {\n storagePath: \"node_modules/.alepha/buckets\",\n },\n});\n\nexport type LocalFileStorageProviderOptions = Static<\n typeof localFileStorageOptions.schema\n>;\n\ndeclare module \"alepha\" {\n interface State {\n [localFileStorageOptions.key]: LocalFileStorageProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class LocalFileStorageProvider implements FileStorageProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly fileDetector = $inject(FileDetector);\n protected readonly fileSystemProvider = $inject(FileSystemProvider);\n protected readonly options = $use(localFileStorageOptions);\n\n protected get storagePath(): string {\n return this.options.storagePath;\n }\n\n protected readonly onConfigure = $hook({\n on: \"configure\",\n handler: async () => {\n if (\n this.alepha.isTest() &&\n this.storagePath === localFileStorageOptions.options.default.storagePath\n ) {\n this.alepha.store.set(localFileStorageOptions, {\n storagePath: join(tmpdir(), `alepha-test-${Date.now()}`),\n });\n }\n },\n });\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n try {\n await mkdir(this.storagePath, { recursive: true });\n } catch {}\n\n for (const bucket of this.alepha.primitives($bucket)) {\n if (bucket.provider !== this) {\n continue;\n }\n\n await mkdir(join(this.storagePath, bucket.name), {\n recursive: true,\n });\n\n this.log.debug(`Bucket '${bucket.name}' at ${this.storagePath} OK`);\n }\n },\n });\n\n public async upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string> {\n fileId ??= this.createId(file.type);\n\n this.log.trace(`Uploading file to ${bucketName}`);\n\n await this.fileSystemProvider.writeFile(\n this.path(bucketName, fileId),\n file,\n );\n\n return fileId;\n }\n\n public async download(bucketName: string, fileId: string): Promise<FileLike> {\n const filePath = this.path(bucketName, fileId);\n\n try {\n const stats = await stat(filePath);\n const mimeType = this.fileDetector.getContentType(fileId);\n\n return this.fileSystemProvider.createFile({\n stream: createReadStream(filePath),\n name: fileId,\n type: mimeType,\n size: stats.size,\n });\n } catch (error) {\n if (this.isErrorNoEntry(error)) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n throw new AlephaError(\"Invalid file operation\", { cause: error });\n }\n }\n\n public async exists(bucketName: string, fileId: string): Promise<boolean> {\n try {\n await stat(this.path(bucketName, fileId));\n return true;\n } catch (error) {\n if (this.isErrorNoEntry(error)) {\n return false;\n }\n throw new AlephaError(\"Error checking file existence\", { cause: error });\n }\n }\n\n public async delete(bucketName: string, fileId: string): Promise<void> {\n try {\n return await unlink(this.path(bucketName, fileId));\n } catch (error) {\n if (this.isErrorNoEntry(error)) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n throw new AlephaError(\"Error deleting file\", { cause: error });\n }\n }\n\n protected stat(bucket: string, fileId: string): Promise<fs.Stats> {\n return stat(this.path(bucket, fileId));\n }\n\n protected createId(mimeType: string): string {\n const ext = this.fileDetector.getExtensionFromMimeType(mimeType);\n return `${randomUUID()}.${ext}`;\n }\n\n protected path(bucket: string, fileId = \"\"): string {\n return join(this.storagePath, bucket, fileId);\n }\n\n protected isErrorNoEntry(error: unknown): boolean {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n }\n}\n","import {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type FileLike,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { FileNotFoundError } from \"../errors/FileNotFoundError.ts\";\nimport { $bucket } from \"../primitives/$bucket.ts\";\nimport type { FileStorageProvider } from \"./FileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * R2Bucket interface matching Cloudflare's R2 API.\n */\nexport interface R2Bucket {\n put(\n key: string,\n value:\n | ReadableStream\n | ArrayBuffer\n | ArrayBufferView\n | string\n | Blob\n | null,\n options?: R2PutOptions,\n ): Promise<R2Object | null>;\n get(key: string, options?: R2GetOptions): Promise<R2ObjectBody | null>;\n head(key: string): Promise<R2Object | null>;\n delete(keys: string | string[]): Promise<void>;\n list(options?: R2ListOptions): Promise<R2Objects>;\n createMultipartUpload(\n key: string,\n options?: R2MultipartOptions,\n ): Promise<R2MultipartUpload>;\n}\n\nexport interface R2Object {\n key: string;\n version: string;\n size: number;\n etag: string;\n httpEtag: string;\n checksums: R2Checksums;\n uploaded: Date;\n httpMetadata?: R2HTTPMetadata;\n customMetadata?: Record<string, string>;\n range?: R2Range;\n storageClass: string;\n}\n\nexport interface R2ObjectBody extends R2Object {\n body: ReadableStream;\n bodyUsed: boolean;\n arrayBuffer(): Promise<ArrayBuffer>;\n text(): Promise<string>;\n json<T>(): Promise<T>;\n blob(): Promise<Blob>;\n}\n\nexport interface R2PutOptions {\n onlyIf?: R2Conditional;\n httpMetadata?: R2HTTPMetadata;\n customMetadata?: Record<string, string>;\n md5?: ArrayBuffer | string;\n sha1?: ArrayBuffer | string;\n sha256?: ArrayBuffer | string;\n sha384?: ArrayBuffer | string;\n sha512?: ArrayBuffer | string;\n storageClass?: string;\n}\n\nexport interface R2GetOptions {\n onlyIf?: R2Conditional;\n range?: R2Range;\n}\n\nexport interface R2ListOptions {\n limit?: number;\n prefix?: string;\n cursor?: string;\n delimiter?: string;\n startAfter?: string;\n include?: (\"httpMetadata\" | \"customMetadata\")[];\n}\n\nexport interface R2Objects {\n objects: R2Object[];\n truncated: boolean;\n cursor?: string;\n delimitedPrefixes: string[];\n}\n\nexport interface R2Checksums {\n md5?: ArrayBuffer;\n sha1?: ArrayBuffer;\n sha256?: ArrayBuffer;\n sha384?: ArrayBuffer;\n sha512?: ArrayBuffer;\n}\n\nexport interface R2HTTPMetadata {\n contentType?: string;\n contentLanguage?: string;\n contentDisposition?: string;\n contentEncoding?: string;\n cacheControl?: string;\n cacheExpiry?: Date;\n}\n\nexport interface R2Conditional {\n etagMatches?: string;\n etagDoesNotMatch?: string;\n uploadedBefore?: Date;\n uploadedAfter?: Date;\n secondsGranularity?: boolean;\n}\n\nexport interface R2Range {\n offset?: number;\n length?: number;\n suffix?: number;\n}\n\nexport interface R2MultipartOptions {\n httpMetadata?: R2HTTPMetadata;\n customMetadata?: Record<string, string>;\n storageClass?: string;\n}\n\nexport interface R2MultipartUpload {\n key: string;\n uploadId: string;\n uploadPart(\n partNumber: number,\n value: ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob,\n ): Promise<R2UploadedPart>;\n abort(): Promise<void>;\n complete(uploadedParts: R2UploadedPart[]): Promise<R2Object>;\n}\n\nexport interface R2UploadedPart {\n partNumber: number;\n etag: string;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare R2 storage provider.\n *\n * Uses a single R2 bucket binding for all $bucket primitives.\n * Files are organized as: {APP_NAME}/{bucketName}/{fileId}\n *\n * **Required environment variables:**\n * - `R2_BUCKET_NAME` - The actual R2 bucket name in Cloudflare\n *\n * **Optional (uses core Alepha env):**\n * - `APP_NAME` - Prefix for all files (for multi-app setups sharing one R2 bucket)\n *\n * @example\n * ```bash\n * # .env\n * APP_NAME=myapp # optional, used as prefix\n * R2_BUCKET_NAME=storage\n * ```\n *\n * @example\n * ```toml\n * # wrangler.toml - automatically generated by alepha build\n * [[r2_buckets]]\n * binding = \"R2\"\n * bucket_name = \"storage\"\n * ```\n *\n * @example\n * ```ts\n * // Define buckets with validation rules\n * const avatars = $bucket({\n * name: \"avatars\",\n * maxFileSize: 5 * 1024 * 1024,\n * allowedMimeTypes: [\"image/*\"],\n * });\n *\n * const documents = $bucket({\n * name: \"documents\",\n * maxFileSize: 50 * 1024 * 1024,\n * allowedMimeTypes: [\"application/pdf\"],\n * });\n *\n * // Files stored at: myapp/avatars/uuid.png, myapp/documents/uuid.pdf\n * ```\n */\nexport class CloudflareR2Provider implements FileStorageProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly env = $env(\n t.object({\n /**\n * The actual R2 bucket name in Cloudflare.\n */\n R2_BUCKET_NAME: t.string({\n description: \"R2 bucket name in Cloudflare\",\n }),\n }),\n );\n\n protected r2?: R2Bucket;\n\n /**\n * Get the R2 bucket name from environment.\n */\n public get bucketName(): string {\n return this.env.R2_BUCKET_NAME;\n }\n\n /**\n * Get the optional prefix from APP_NAME environment variable.\n * Used for multi-app setups sharing the same R2 bucket.\n */\n public get prefix(): string | undefined {\n return this.alepha.env.APP_NAME;\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n const cloudflareEnv = this.alepha.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[this.bucketName] as R2Bucket | undefined;\n if (!binding) {\n throw new AlephaError(\n `R2 binding '${this.bucketName}' not found in Cloudflare Workers environment.`,\n );\n }\n\n this.r2 = binding;\n\n const prefixStr = this.prefix ? `${this.prefix}/` : \"\";\n this.log.info(\n `R2 storage ready (bucket: ${this.bucketName}, prefix: ${prefixStr || \"(none)\"})`,\n );\n\n for (const bucket of this.alepha.primitives($bucket)) {\n if (bucket.provider !== this) {\n continue;\n }\n this.log.debug(\n `Bucket '${bucket.name}' -> ${prefixStr}${bucket.name}/`,\n );\n }\n },\n });\n\n public async upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string> {\n const r2 = this.getR2();\n fileId ??= this.createId(file.name);\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Uploading '${key}'`);\n\n const arrayBuffer = await file.arrayBuffer();\n\n await r2.put(key, arrayBuffer, {\n httpMetadata: {\n contentType: file.type,\n },\n customMetadata: {\n originalName: file.name,\n bucket: bucketName,\n },\n });\n\n return fileId;\n }\n\n public async download(bucketName: string, fileId: string): Promise<FileLike> {\n const r2 = this.getR2();\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Downloading '${key}'`);\n\n const object = await r2.get(key);\n if (!object) {\n throw new FileNotFoundError(\n `File '${fileId}' not found in bucket '${bucketName}'.`,\n );\n }\n\n const originalName = object.customMetadata?.originalName ?? fileId;\n const contentType =\n object.httpMetadata?.contentType ?? \"application/octet-stream\";\n\n return {\n name: originalName,\n type: contentType,\n size: object.size,\n lastModified: object.uploaded.getTime(),\n stream: () => object.body,\n arrayBuffer: () => object.arrayBuffer(),\n text: () => object.text(),\n };\n }\n\n public async exists(bucketName: string, fileId: string): Promise<boolean> {\n const r2 = this.getR2();\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Checking '${key}'`);\n\n const object = await r2.head(key);\n return object !== null;\n }\n\n public async delete(bucketName: string, fileId: string): Promise<void> {\n const r2 = this.getR2();\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Deleting '${key}'`);\n\n // R2's delete doesn't throw if the file doesn't exist,\n // so we check existence first for consistency with other providers\n const exists = await this.exists(bucketName, fileId);\n if (!exists) {\n throw new FileNotFoundError(\n `File '${fileId}' not found in bucket '${bucketName}'.`,\n );\n }\n\n await r2.delete(key);\n }\n\n /**\n * Build the full R2 key: {prefix}/{bucketName}/{fileId}\n */\n protected key(bucketName: string, fileId: string): string {\n const parts = [bucketName, fileId];\n if (this.prefix) {\n parts.unshift(this.prefix);\n }\n return parts.join(\"/\");\n }\n\n protected getR2(): R2Bucket {\n if (!this.r2) {\n throw new AlephaError(\"R2 storage not initialized. Call start() first.\");\n }\n return this.r2;\n }\n\n protected createId(filename: string): string {\n const ext = filename.includes(\".\") ? filename.split(\".\").pop() : \"\";\n const id = crypto.randomUUID();\n return ext ? `${id}.${ext}` : id;\n }\n}\n","import { $module, type FileLike } from \"alepha\";\nimport {\n $bucket,\n type BucketFileOptions,\n type BucketPrimitive,\n} from \"./primitives/$bucket.ts\";\nimport { FileStorageProvider } from \"./providers/FileStorageProvider.ts\";\nimport { LocalFileStorageProvider } from \"./providers/LocalFileStorageProvider.ts\";\nimport { MemoryFileStorageProvider } from \"./providers/MemoryFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./errors/FileNotFoundError.ts\";\nexport * from \"./primitives/$bucket.ts\";\nexport * from \"./providers/CloudflareR2Provider.ts\";\nexport * from \"./providers/FileStorageProvider.ts\";\nexport * from \"./providers/LocalFileStorageProvider.ts\";\nexport * from \"./providers/MemoryFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Triggered when a file is uploaded to a bucket.\n * Can be used to perform actions after a file is uploaded, like creating a database record!\n */\n \"bucket:file:uploaded\": {\n id: string;\n file: FileLike;\n bucket: BucketPrimitive;\n options: BucketFileOptions;\n };\n /**\n * Triggered when a file is deleted from a bucket.\n */\n \"bucket:file:deleted\": {\n id: string;\n bucket: BucketPrimitive;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Unified file storage abstraction across multiple backends.\n *\n * **Features:**\n * - File storage buckets with constraints\n * - Unified API across all storage backends\n * - MIME type validation\n * - File size limits\n * - Upload/download/delete operations\n * - TTL-based file expiration\n * - Providers: Memory (testing), Local filesystem, AWS S3 / Cloudflare R2 / MinIO, Azure Blob Storage, Vercel Blob\n *\n * @module alepha.bucket\n */\nexport const AlephaBucket = $module({\n name: \"alepha.bucket\",\n primitives: [$bucket],\n services: [\n FileStorageProvider,\n MemoryFileStorageProvider,\n LocalFileStorageProvider,\n ],\n register: (alepha) => {\n alepha.with({\n optional: true,\n provide: FileStorageProvider,\n use:\n alepha.isTest() || alepha.isServerless()\n ? MemoryFileStorageProvider\n : LocalFileStorageProvider,\n });\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/bucket/errors/InvalidFileError.ts","../../src/bucket/providers/FileStorageProvider.ts","../../src/bucket/errors/FileNotFoundError.ts","../../src/bucket/providers/MemoryFileStorageProvider.ts","../../src/bucket/primitives/$bucket.ts","../../src/bucket/providers/LocalFileStorageProvider.ts","../../src/bucket/providers/CloudflareR2Provider.ts","../../src/bucket/index.ts"],"sourcesContent":["import { AlephaError } from \"alepha\";\n\nexport class InvalidFileError extends AlephaError {\n public readonly status = 400;\n}\n","import type { FileLike } from \"alepha\";\n\nexport abstract class FileStorageProvider {\n /**\n * Uploads a file to the storage.\n *\n * @param bucketName - Container name\n * @param file - File to upload\n * @param fileId - Optional file identifier. If not provided, a unique ID will be generated.\n * @return The identifier of the uploaded file.\n */\n abstract upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string>;\n\n /**\n * Downloads a file from the storage.\n *\n * @param bucketName - Container name\n * @param fileId - Identifier of the file to download\n * @return The downloaded file as a FileLike object.\n */\n abstract download(bucketName: string, fileId: string): Promise<FileLike>;\n\n /**\n * Check if fileId exists in the storage bucket.\n *\n * @param bucketName - Container name\n * @param fileId - Identifier of the file to stream\n * @return True is the file exists, false otherwise.\n */\n abstract exists(bucketName: string, fileId: string): Promise<boolean>;\n\n /**\n * Delete permanently a file from the storage.\n *\n * @param bucketName - Container name\n * @param fileId - Identifier of the file to delete\n */\n abstract delete(bucketName: string, fileId: string): Promise<void>;\n}\n","import { AlephaError } from \"alepha\";\n\nexport class FileNotFoundError extends AlephaError {\n public readonly status = 404;\n}\n","import { randomUUID } from \"node:crypto\";\nimport { $inject, type FileLike } from \"alepha\";\nimport { FileDetector, FileSystemProvider } from \"alepha/system\";\nimport { FileNotFoundError } from \"../errors/FileNotFoundError.ts\";\nimport type { FileStorageProvider } from \"./FileStorageProvider.ts\";\n\ninterface StoredFile {\n buffer: Buffer;\n name: string;\n type: string;\n size: number;\n}\n\nexport class MemoryFileStorageProvider implements FileStorageProvider {\n public readonly files: Record<string, StoredFile> = {};\n protected readonly fileSystem = $inject(FileSystemProvider);\n protected readonly fileDetector = $inject(FileDetector);\n\n public async upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string> {\n fileId ??= this.createId();\n\n // Consume the stream and store as buffer so downloads are repeatable\n const chunks: Uint8Array[] = [];\n for await (const chunk of file.stream() as AsyncIterable<Uint8Array>) {\n chunks.push(chunk);\n }\n const buffer = Buffer.concat(chunks);\n\n this.files[`${bucketName}/${fileId}`] = {\n buffer,\n name: file.name,\n type: file.type,\n size: file.size,\n };\n\n return fileId;\n }\n\n public async download(bucketName: string, fileId: string): Promise<FileLike> {\n const fileKey = `${bucketName}/${fileId}`;\n const stored = this.files[fileKey];\n\n if (!stored) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n\n // Create a fresh FileLike with a new stream from the stored buffer\n return this.fileSystem.createFile({\n stream: new Blob([new Uint8Array(stored.buffer)]).stream(),\n name: stored.name,\n type: stored.type,\n size: stored.size,\n });\n }\n\n public async exists(bucketName: string, fileId: string): Promise<boolean> {\n return `${bucketName}/${fileId}` in this.files;\n }\n\n public async delete(bucketName: string, fileId: string): Promise<void> {\n const fileKey = `${bucketName}/${fileId}`;\n if (!(fileKey in this.files)) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n\n delete this.files[fileKey];\n }\n\n protected createId(): string {\n return randomUUID();\n }\n}\n","import {\n $inject,\n createPrimitive,\n type FileLike,\n KIND,\n Primitive,\n type Service,\n} from \"alepha\";\nimport { FileSystemProvider } from \"alepha/system\";\nimport { InvalidFileError } from \"../errors/InvalidFileError.ts\";\nimport { FileStorageProvider } from \"../providers/FileStorageProvider.ts\";\nimport { MemoryFileStorageProvider } from \"../providers/MemoryFileStorageProvider.ts\";\n\n/**\n * Creates a bucket primitive for file storage and management with configurable validation.\n *\n * Provides a comprehensive file storage system that handles uploads, downloads, validation,\n * and management across multiple storage backends with MIME type and size limit controls.\n *\n * **Key Features**\n * - Multi-provider support (filesystem, cloud storage, in-memory)\n * - Automatic MIME type and file size validation\n * - Event integration for file operations monitoring\n * - Flexible per-bucket and per-operation configuration\n * - Smart file type and size detection\n *\n * **Common Use Cases**\n * - User profile pictures and document uploads\n * - Product images and media management\n * - Document storage and retrieval systems\n *\n * @example\n * ```ts\n * class MediaService {\n * images = $bucket({\n * name: \"user-images\",\n * mimeTypes: [\"image/jpeg\", \"image/png\", \"image/gif\"],\n * maxSize: 5 // 5MB limit\n * });\n *\n * documents = $bucket({\n * name: \"documents\",\n * mimeTypes: [\"application/pdf\", \"text/plain\"],\n * maxSize: 50 // 50MB limit\n * });\n *\n * async uploadProfileImage(file: FileLike, userId: string): Promise<string> {\n * const fileId = await this.images.upload(file);\n * await this.userService.updateProfileImage(userId, fileId);\n * return fileId;\n * }\n *\n * async downloadDocument(documentId: string): Promise<FileLike> {\n * return await this.documents.download(documentId);\n * }\n *\n * async deleteDocument(documentId: string): Promise<void> {\n * await this.documents.delete(documentId);\n * }\n * }\n * ```\n */\nexport const $bucket = (options: BucketPrimitiveOptions) =>\n createPrimitive(BucketPrimitive, options);\n\nexport interface BucketPrimitiveOptions extends BucketFileOptions {\n /**\n * File storage provider configuration for the bucket.\n *\n * Options:\n * - **\"memory\"**: In-memory storage (default for development, lost on restart)\n * - **Service<FileStorageProvider>**: Custom provider class (e.g., S3FileStorageProvider, AzureBlobProvider)\n * - **undefined**: Uses the default file storage provider from dependency injection\n *\n * **Provider Selection Guidelines**:\n * - **Development**: Use \"memory\" for fast, simple testing without external dependencies\n * - **Production**: Use cloud providers (S3, Azure Blob, Google Cloud Storage) for scalability\n * - **Local deployment**: Use filesystem providers for on-premise installations\n * - **Hybrid**: Use different providers for different bucket types (temp files vs permanent storage)\n *\n * **Provider Capabilities**:\n * - File persistence and durability guarantees\n * - Scalability and performance characteristics\n * - Geographic distribution and CDN integration\n * - Cost implications for storage and bandwidth\n * - Backup and disaster recovery features\n *\n * @default Uses injected FileStorageProvider\n * @example \"memory\"\n * @example S3FileStorageProvider\n * @example AzureBlobStorageProvider\n */\n provider?: Service<FileStorageProvider> | \"memory\";\n\n /**\n * Unique name identifier for the bucket.\n *\n * This name is used for:\n * - Storage backend organization and partitioning\n * - File path generation and URL construction\n * - Logging, monitoring, and debugging\n * - Access control and permissions management\n * - Backup and replication configuration\n *\n * **Naming Conventions**:\n * - Use lowercase with hyphens for consistency\n * - Include purpose or content type in the name\n * - Avoid spaces and special characters\n * - Consider environment prefixes for deployment isolation\n *\n * If not provided, defaults to the property key where the bucket is declared.\n *\n * @example \"user-avatars\"\n * @example \"product-images\"\n * @example \"legal-documents\"\n * @example \"temp-processing-files\"\n */\n name?: string;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BucketFileOptions {\n /**\n * Human-readable description of the bucket's purpose and contents.\n *\n * Used for:\n * - Documentation generation and API references\n * - Developer onboarding and system understanding\n * - Monitoring dashboards and admin interfaces\n * - Compliance and audit documentation\n *\n * **Description Best Practices**:\n * - Explain what types of files this bucket stores\n * - Mention any special handling or processing requirements\n * - Include information about retention policies if applicable\n * - Note any compliance or security considerations\n *\n * @example \"User profile pictures and avatar images\"\n * @example \"Product catalog images with automated thumbnail generation\"\n * @example \"Legal documents requiring long-term retention\"\n * @example \"Temporary files for data processing workflows\"\n */\n description?: string;\n\n /**\n * Array of allowed MIME types for files uploaded to this bucket.\n *\n * When specified, only files with these exact MIME types will be accepted.\n * Files with disallowed MIME types will be rejected with an InvalidFileError.\n *\n * **MIME Type Categories**:\n * - Images: \"image/jpeg\", \"image/png\", \"image/gif\", \"image/webp\", \"image/svg+xml\"\n * - Documents: \"application/pdf\", \"text/plain\", \"text/csv\"\n * - Office: \"application/msword\", \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\"\n * - Archives: \"application/zip\", \"application/x-tar\", \"application/gzip\"\n * - Media: \"video/mp4\", \"audio/mpeg\", \"audio/wav\"\n *\n * **Security Considerations**:\n * - Always validate MIME types for user uploads\n * - Be cautious with executable file types\n * - Consider using allow-lists rather than deny-lists\n * - Remember that MIME types can be spoofed by malicious users\n *\n * If not specified, all MIME types are allowed (not recommended for user uploads).\n *\n * @example [\"image/jpeg\", \"image/png\"] // Only JPEG and PNG images\n * @example [\"application/pdf\", \"text/plain\"] // Documents only\n * @example [\"video/mp4\", \"video/webm\"] // Video files\n */\n mimeTypes?: string[];\n\n /**\n * Maximum file size allowed in megabytes (MB).\n *\n * Files larger than this limit will be rejected with an InvalidFileError.\n * This helps prevent:\n * - Storage quota exhaustion\n * - Memory issues during file processing\n * - Long upload times and timeouts\n * - Abuse of storage resources\n *\n * **Size Guidelines by File Type**:\n * - Profile images: 1-5 MB\n * - Product photos: 5-10 MB\n * - Documents: 10-50 MB\n * - Video files: 50-500 MB\n * - Data files: 100-1000 MB\n *\n * **Considerations**:\n * - Consider your storage costs and limits\n * - Factor in network upload speeds for users\n * - Account for processing requirements (thumbnails, compression)\n * - Set reasonable limits based on actual use cases\n *\n * @default 10 MB\n *\n * @example 1 // 1MB for small images\n * @example 25 // 25MB for documents\n * @example 100 // 100MB for media files\n */\n maxSize?: number;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class BucketPrimitive extends Primitive<BucketPrimitiveOptions> {\n public readonly provider = this.$provider();\n protected readonly fileSystem = $inject(FileSystemProvider);\n\n public get name() {\n return this.options.name ?? `${this.config.propertyKey}`;\n }\n\n /**\n * Uploads a file to the bucket.\n */\n public async upload(\n file: FileLike,\n options?: BucketFileOptions,\n ): Promise<string> {\n if (file instanceof File) {\n // our createFile is smarter than the browser's File constructor\n // by doing this, we can guess the MIME type and size!\n file = this.fileSystem.createFile({ file });\n }\n\n options = {\n ...this.options,\n ...options,\n };\n\n const mimeTypes = options.mimeTypes ?? undefined;\n const maxSize = options.maxSize ?? 10; // Default to 10 MB if not specified\n\n if (mimeTypes) {\n const mimeType = file.type || \"application/octet-stream\";\n if (!mimeTypes.includes(mimeType)) {\n throw new InvalidFileError(\n `MIME type ${mimeType} is not allowed in bucket ${this.name}`,\n );\n }\n }\n\n // check size in bytes, convert MB to bytes\n if (file.size > maxSize * 1024 * 1024) {\n throw new InvalidFileError(\n `File size ${file.size} exceeds the maximum size of ${maxSize} MB in bucket ${this.name}`,\n );\n }\n\n const id = await this.provider.upload(this.name, file);\n\n await this.alepha.events.emit(\"bucket:file:uploaded\", {\n id,\n bucket: this,\n file,\n options,\n });\n\n return id;\n }\n\n /**\n * Delete permanently a file from the bucket.\n */\n public async delete(fileId: string, skipHook = false): Promise<void> {\n await this.provider.delete(this.name, fileId);\n\n if (skipHook) {\n return;\n }\n\n await this.alepha.events.emit(\"bucket:file:deleted\", {\n id: fileId,\n bucket: this,\n });\n }\n\n /**\n * Checks if a file exists in the bucket.\n */\n public async exists(fileId: string): Promise<boolean> {\n return this.provider.exists(this.name, fileId);\n }\n\n /**\n * Downloads a file from the bucket.\n */\n public async download(fileId: string): Promise<FileLike> {\n return this.provider.download(this.name, fileId);\n }\n\n protected $provider() {\n if (!this.options.provider) {\n return this.alepha.inject(FileStorageProvider);\n }\n if (this.options.provider === \"memory\") {\n return this.alepha.inject(MemoryFileStorageProvider);\n }\n return this.alepha.inject(this.options.provider);\n }\n}\n\n$bucket[KIND] = BucketPrimitive;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface BucketFileOptions {\n /**\n * Optional description of the bucket.\n */\n description?: string;\n\n /**\n * Allowed MIME types.\n */\n mimeTypes?: string[];\n\n /**\n * Maximum size of the files in the bucket.\n *\n * @default 10\n */\n maxSize?: number;\n}\n","import { randomUUID } from \"node:crypto\";\nimport type * as fs from \"node:fs\";\nimport { createReadStream } from \"node:fs\";\nimport { mkdir, stat, unlink } from \"node:fs/promises\";\nimport { tmpdir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n $atom,\n $hook,\n $inject,\n $state,\n Alepha,\n AlephaError,\n type FileLike,\n type Static,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { FileDetector, FileSystemProvider } from \"alepha/system\";\nimport { FileNotFoundError } from \"../errors/FileNotFoundError.ts\";\nimport { $bucket } from \"../primitives/$bucket.ts\";\nimport type { FileStorageProvider } from \"./FileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Local file storage configuration atom\n */\nexport const localFileStorageOptions = $atom({\n name: \"alepha.bucket.local.options\",\n schema: t.object({\n storagePath: t.string({\n description: \"Directory path where files will be stored\",\n }),\n }),\n default: {\n storagePath: \"node_modules/.alepha/buckets\",\n },\n});\n\nexport type LocalFileStorageProviderOptions = Static<\n typeof localFileStorageOptions.schema\n>;\n\ndeclare module \"alepha\" {\n interface State {\n [localFileStorageOptions.key]: LocalFileStorageProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class LocalFileStorageProvider implements FileStorageProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly fileDetector = $inject(FileDetector);\n protected readonly fileSystemProvider = $inject(FileSystemProvider);\n protected readonly options = $state(localFileStorageOptions);\n\n protected get storagePath(): string {\n return this.options.storagePath;\n }\n\n protected readonly onConfigure = $hook({\n on: \"configure\",\n handler: async () => {\n if (\n this.alepha.isTest() &&\n this.storagePath === localFileStorageOptions.options.default.storagePath\n ) {\n this.alepha.store.set(localFileStorageOptions, {\n storagePath: join(tmpdir(), `alepha-test-${Date.now()}`),\n });\n }\n },\n });\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n try {\n await mkdir(this.storagePath, { recursive: true });\n } catch {}\n\n for (const bucket of this.alepha.primitives($bucket)) {\n if (bucket.provider !== this) {\n continue;\n }\n\n await mkdir(join(this.storagePath, bucket.name), {\n recursive: true,\n });\n\n this.log.debug(`Bucket '${bucket.name}' at ${this.storagePath} OK`);\n }\n },\n });\n\n public async upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string> {\n fileId ??= this.createId(file.type);\n\n this.log.trace(`Uploading file to ${bucketName}`);\n\n await this.fileSystemProvider.writeFile(\n this.path(bucketName, fileId),\n file,\n );\n\n return fileId;\n }\n\n public async download(bucketName: string, fileId: string): Promise<FileLike> {\n const filePath = this.path(bucketName, fileId);\n\n try {\n const stats = await stat(filePath);\n const mimeType = this.fileDetector.getContentType(fileId);\n\n return this.fileSystemProvider.createFile({\n stream: createReadStream(filePath),\n name: fileId,\n type: mimeType,\n size: stats.size,\n });\n } catch (error) {\n if (this.isErrorNoEntry(error)) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n throw new AlephaError(\"Invalid file operation\", { cause: error });\n }\n }\n\n public async exists(bucketName: string, fileId: string): Promise<boolean> {\n try {\n await stat(this.path(bucketName, fileId));\n return true;\n } catch (error) {\n if (this.isErrorNoEntry(error)) {\n return false;\n }\n throw new AlephaError(\"Error checking file existence\", { cause: error });\n }\n }\n\n public async delete(bucketName: string, fileId: string): Promise<void> {\n try {\n return await unlink(this.path(bucketName, fileId));\n } catch (error) {\n if (this.isErrorNoEntry(error)) {\n throw new FileNotFoundError(`File with ID ${fileId} not found.`);\n }\n throw new AlephaError(\"Error deleting file\", { cause: error });\n }\n }\n\n protected stat(bucket: string, fileId: string): Promise<fs.Stats> {\n return stat(this.path(bucket, fileId));\n }\n\n protected createId(mimeType: string): string {\n const ext = this.fileDetector.getExtensionFromMimeType(mimeType);\n return `${randomUUID()}.${ext}`;\n }\n\n protected path(bucket: string, fileId = \"\"): string {\n return join(this.storagePath, bucket, fileId);\n }\n\n protected isErrorNoEntry(error: unknown): boolean {\n return error instanceof Error && \"code\" in error && error.code === \"ENOENT\";\n }\n}\n","import {\n $env,\n $hook,\n $inject,\n Alepha,\n AlephaError,\n type FileLike,\n t,\n} from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport { FileNotFoundError } from \"../errors/FileNotFoundError.ts\";\nimport { $bucket } from \"../primitives/$bucket.ts\";\nimport type { FileStorageProvider } from \"./FileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * R2Bucket interface matching Cloudflare's R2 API.\n */\nexport interface R2Bucket {\n put(\n key: string,\n value:\n | ReadableStream\n | ArrayBuffer\n | ArrayBufferView\n | string\n | Blob\n | null,\n options?: R2PutOptions,\n ): Promise<R2Object | null>;\n get(key: string, options?: R2GetOptions): Promise<R2ObjectBody | null>;\n head(key: string): Promise<R2Object | null>;\n delete(keys: string | string[]): Promise<void>;\n list(options?: R2ListOptions): Promise<R2Objects>;\n createMultipartUpload(\n key: string,\n options?: R2MultipartOptions,\n ): Promise<R2MultipartUpload>;\n}\n\nexport interface R2Object {\n key: string;\n version: string;\n size: number;\n etag: string;\n httpEtag: string;\n checksums: R2Checksums;\n uploaded: Date;\n httpMetadata?: R2HTTPMetadata;\n customMetadata?: Record<string, string>;\n range?: R2Range;\n storageClass: string;\n}\n\nexport interface R2ObjectBody extends R2Object {\n body: ReadableStream;\n bodyUsed: boolean;\n arrayBuffer(): Promise<ArrayBuffer>;\n text(): Promise<string>;\n json<T>(): Promise<T>;\n blob(): Promise<Blob>;\n}\n\nexport interface R2PutOptions {\n onlyIf?: R2Conditional;\n httpMetadata?: R2HTTPMetadata;\n customMetadata?: Record<string, string>;\n md5?: ArrayBuffer | string;\n sha1?: ArrayBuffer | string;\n sha256?: ArrayBuffer | string;\n sha384?: ArrayBuffer | string;\n sha512?: ArrayBuffer | string;\n storageClass?: string;\n}\n\nexport interface R2GetOptions {\n onlyIf?: R2Conditional;\n range?: R2Range;\n}\n\nexport interface R2ListOptions {\n limit?: number;\n prefix?: string;\n cursor?: string;\n delimiter?: string;\n startAfter?: string;\n include?: (\"httpMetadata\" | \"customMetadata\")[];\n}\n\nexport interface R2Objects {\n objects: R2Object[];\n truncated: boolean;\n cursor?: string;\n delimitedPrefixes: string[];\n}\n\nexport interface R2Checksums {\n md5?: ArrayBuffer;\n sha1?: ArrayBuffer;\n sha256?: ArrayBuffer;\n sha384?: ArrayBuffer;\n sha512?: ArrayBuffer;\n}\n\nexport interface R2HTTPMetadata {\n contentType?: string;\n contentLanguage?: string;\n contentDisposition?: string;\n contentEncoding?: string;\n cacheControl?: string;\n cacheExpiry?: Date;\n}\n\nexport interface R2Conditional {\n etagMatches?: string;\n etagDoesNotMatch?: string;\n uploadedBefore?: Date;\n uploadedAfter?: Date;\n secondsGranularity?: boolean;\n}\n\nexport interface R2Range {\n offset?: number;\n length?: number;\n suffix?: number;\n}\n\nexport interface R2MultipartOptions {\n httpMetadata?: R2HTTPMetadata;\n customMetadata?: Record<string, string>;\n storageClass?: string;\n}\n\nexport interface R2MultipartUpload {\n key: string;\n uploadId: string;\n uploadPart(\n partNumber: number,\n value: ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob,\n ): Promise<R2UploadedPart>;\n abort(): Promise<void>;\n complete(uploadedParts: R2UploadedPart[]): Promise<R2Object>;\n}\n\nexport interface R2UploadedPart {\n partNumber: number;\n etag: string;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Cloudflare R2 storage provider.\n *\n * Uses a single R2 bucket binding for all $bucket primitives.\n * Files are organized as: {APP_NAME}/{bucketName}/{fileId}\n *\n * **Required environment variables:**\n * - `R2_BUCKET_NAME` - The actual R2 bucket name in Cloudflare\n *\n * **Optional (uses core Alepha env):**\n * - `APP_NAME` - Prefix for all files (for multi-app setups sharing one R2 bucket)\n *\n * @example\n * ```bash\n * # .env\n * APP_NAME=myapp # optional, used as prefix\n * R2_BUCKET_NAME=storage\n * ```\n *\n * @example\n * ```toml\n * # wrangler.toml - automatically generated by alepha build\n * [[r2_buckets]]\n * binding = \"R2\"\n * bucket_name = \"storage\"\n * ```\n *\n * @example\n * ```ts\n * // Define buckets with validation rules\n * const avatars = $bucket({\n * name: \"avatars\",\n * maxFileSize: 5 * 1024 * 1024,\n * allowedMimeTypes: [\"image/*\"],\n * });\n *\n * const documents = $bucket({\n * name: \"documents\",\n * maxFileSize: 50 * 1024 * 1024,\n * allowedMimeTypes: [\"application/pdf\"],\n * });\n *\n * // Files stored at: myapp/avatars/uuid.png, myapp/documents/uuid.pdf\n * ```\n */\nexport class CloudflareR2Provider implements FileStorageProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly env = $env(\n t.object({\n /**\n * The actual R2 bucket name in Cloudflare.\n */\n R2_BUCKET_NAME: t.string({\n description: \"R2 bucket name in Cloudflare\",\n }),\n }),\n );\n\n protected r2?: R2Bucket;\n\n /**\n * Get the R2 bucket name from environment.\n */\n public get bucketName(): string {\n return this.env.R2_BUCKET_NAME;\n }\n\n /**\n * Get the optional prefix from APP_NAME environment variable.\n * Used for multi-app setups sharing the same R2 bucket.\n */\n public get prefix(): string | undefined {\n return this.alepha.env.APP_NAME;\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n const cloudflareEnv = this.alepha.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[this.bucketName] as R2Bucket | undefined;\n if (!binding) {\n throw new AlephaError(\n `R2 binding '${this.bucketName}' not found in Cloudflare Workers environment.`,\n );\n }\n\n this.r2 = binding;\n\n const prefixStr = this.prefix ? `${this.prefix}/` : \"\";\n this.log.info(\n `R2 storage ready (bucket: ${this.bucketName}, prefix: ${prefixStr || \"(none)\"})`,\n );\n\n for (const bucket of this.alepha.primitives($bucket)) {\n if (bucket.provider !== this) {\n continue;\n }\n this.log.debug(\n `Bucket '${bucket.name}' -> ${prefixStr}${bucket.name}/`,\n );\n }\n },\n });\n\n public async upload(\n bucketName: string,\n file: FileLike,\n fileId?: string,\n ): Promise<string> {\n const r2 = this.getR2();\n fileId ??= this.createId(file.name);\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Uploading '${key}'`);\n\n const arrayBuffer = await file.arrayBuffer();\n\n await r2.put(key, arrayBuffer, {\n httpMetadata: {\n contentType: file.type,\n },\n customMetadata: {\n originalName: file.name,\n bucket: bucketName,\n },\n });\n\n return fileId;\n }\n\n public async download(bucketName: string, fileId: string): Promise<FileLike> {\n const r2 = this.getR2();\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Downloading '${key}'`);\n\n const object = await r2.get(key);\n if (!object) {\n throw new FileNotFoundError(\n `File '${fileId}' not found in bucket '${bucketName}'.`,\n );\n }\n\n const originalName = object.customMetadata?.originalName ?? fileId;\n const contentType =\n object.httpMetadata?.contentType ?? \"application/octet-stream\";\n\n return {\n name: originalName,\n type: contentType,\n size: object.size,\n lastModified: object.uploaded.getTime(),\n stream: () => object.body,\n arrayBuffer: () => object.arrayBuffer(),\n text: () => object.text(),\n };\n }\n\n public async exists(bucketName: string, fileId: string): Promise<boolean> {\n const r2 = this.getR2();\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Checking '${key}'`);\n\n const object = await r2.head(key);\n return object !== null;\n }\n\n public async delete(bucketName: string, fileId: string): Promise<void> {\n const r2 = this.getR2();\n const key = this.key(bucketName, fileId);\n\n this.log.trace(`Deleting '${key}'`);\n\n // R2's delete doesn't throw if the file doesn't exist,\n // so we check existence first for consistency with other providers\n const exists = await this.exists(bucketName, fileId);\n if (!exists) {\n throw new FileNotFoundError(\n `File '${fileId}' not found in bucket '${bucketName}'.`,\n );\n }\n\n await r2.delete(key);\n }\n\n /**\n * Build the full R2 key: {prefix}/{bucketName}/{fileId}\n */\n protected key(bucketName: string, fileId: string): string {\n const parts = [bucketName, fileId];\n if (this.prefix) {\n parts.unshift(this.prefix);\n }\n return parts.join(\"/\");\n }\n\n protected getR2(): R2Bucket {\n if (!this.r2) {\n throw new AlephaError(\"R2 storage not initialized. Call start() first.\");\n }\n return this.r2;\n }\n\n protected createId(filename: string): string {\n const ext = filename.includes(\".\") ? filename.split(\".\").pop() : \"\";\n const id = crypto.randomUUID();\n return ext ? `${id}.${ext}` : id;\n }\n}\n","import { $module, type FileLike } from \"alepha\";\nimport {\n $bucket,\n type BucketFileOptions,\n type BucketPrimitive,\n} from \"./primitives/$bucket.ts\";\nimport { FileStorageProvider } from \"./providers/FileStorageProvider.ts\";\nimport { LocalFileStorageProvider } from \"./providers/LocalFileStorageProvider.ts\";\nimport { MemoryFileStorageProvider } from \"./providers/MemoryFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./errors/FileNotFoundError.ts\";\nexport * from \"./primitives/$bucket.ts\";\nexport * from \"./providers/CloudflareR2Provider.ts\";\nexport * from \"./providers/FileStorageProvider.ts\";\nexport * from \"./providers/LocalFileStorageProvider.ts\";\nexport * from \"./providers/MemoryFileStorageProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n /**\n * Triggered when a file is uploaded to a bucket.\n * Can be used to perform actions after a file is uploaded, like creating a database record!\n */\n \"bucket:file:uploaded\": {\n id: string;\n file: FileLike;\n bucket: BucketPrimitive;\n options: BucketFileOptions;\n };\n /**\n * Triggered when a file is deleted from a bucket.\n */\n \"bucket:file:deleted\": {\n id: string;\n bucket: BucketPrimitive;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Unified file storage abstraction across multiple backends.\n *\n * **Features:**\n * - File storage buckets with constraints\n * - Unified API across all storage backends\n * - MIME type validation\n * - File size limits\n * - Upload/download/delete operations\n * - TTL-based file expiration\n * - Providers: Memory (testing), Local filesystem, AWS S3 / Cloudflare R2 / MinIO, Azure Blob Storage, Vercel Blob\n *\n * @module alepha.bucket\n */\nexport const AlephaBucket = $module({\n name: \"alepha.bucket\",\n primitives: [$bucket],\n services: [\n FileStorageProvider,\n MemoryFileStorageProvider,\n LocalFileStorageProvider,\n ],\n register: (alepha) => {\n alepha.with({\n optional: true,\n provide: FileStorageProvider,\n use:\n alepha.isTest() || alepha.isServerless()\n ? MemoryFileStorageProvider\n : LocalFileStorageProvider,\n });\n },\n});\n"],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import * as alepha from "alepha";
|
|
1
|
+
import * as _$alepha from "alepha";
|
|
2
2
|
import { Alepha, InstantiableClass, MiddlewareMetadata, OPTIONS, Primitive, Static } from "alepha";
|
|
3
3
|
import { DateTimeProvider, DurationLike, Timeout } from "alepha/datetime";
|
|
4
|
-
import * as alepha_logger0 from "alepha/logger";
|
|
4
|
+
import * as _$alepha_logger0 from "alepha/logger";
|
|
5
5
|
|
|
6
6
|
//#region ../../src/cache/core/providers/CacheProvider.d.ts
|
|
7
7
|
/**
|
|
@@ -179,9 +179,9 @@ interface CachePrimitiveOptions<TReturn = any, TParameter extends any[] = any[]>
|
|
|
179
179
|
/**
|
|
180
180
|
* Cache configuration atom.
|
|
181
181
|
*/
|
|
182
|
-
declare const cacheOptions: alepha.Atom<alepha.TObject<{
|
|
183
|
-
enabled: alepha.TBoolean;
|
|
184
|
-
defaultTtl: alepha.TNumber;
|
|
182
|
+
declare const cacheOptions: _$alepha.Atom<_$alepha.TObject<{
|
|
183
|
+
enabled: _$alepha.TBoolean;
|
|
184
|
+
defaultTtl: _$alepha.TNumber;
|
|
185
185
|
}>, "alepha.cache.options">;
|
|
186
186
|
type CacheAtomOptions = Static<typeof cacheOptions.schema>;
|
|
187
187
|
declare module "alepha" {
|
|
@@ -275,9 +275,9 @@ declare const KV_DEFAULT_BINDING = "KV_CACHE";
|
|
|
275
275
|
*/
|
|
276
276
|
declare class CloudflareKVProvider extends CacheProvider {
|
|
277
277
|
protected readonly alepha: Alepha;
|
|
278
|
-
protected readonly log: alepha_logger0.Logger;
|
|
278
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
279
279
|
protected kv?: KVNamespace;
|
|
280
|
-
protected readonly onStart: alepha.HookPrimitive<"start">;
|
|
280
|
+
protected readonly onStart: _$alepha.HookPrimitive<"start">;
|
|
281
281
|
get(name: string, key: string): Promise<Uint8Array | undefined>;
|
|
282
282
|
set(name: string, key: string, value: Uint8Array, ttl?: number): Promise<Uint8Array>;
|
|
283
283
|
del(name: string, ...keys: string[]): Promise<void>;
|
|
@@ -364,7 +364,7 @@ interface MemoryCacheProviderOptions {
|
|
|
364
364
|
*/
|
|
365
365
|
declare class MemoryCacheProvider extends CacheProvider {
|
|
366
366
|
protected readonly dateTimeProvider: DateTimeProvider;
|
|
367
|
-
protected readonly log: alepha_logger0.Logger;
|
|
367
|
+
protected readonly log: _$alepha_logger0.Logger;
|
|
368
368
|
protected store: Record<CacheName, Record<CacheKey, CacheValue>>;
|
|
369
369
|
/**
|
|
370
370
|
* All recorded get calls.
|
|
@@ -483,7 +483,7 @@ declare class MemoryCacheProvider extends CacheProvider {
|
|
|
483
483
|
*
|
|
484
484
|
* @module alepha.cache
|
|
485
485
|
*/
|
|
486
|
-
declare const AlephaCache: alepha.Service<alepha.Module>;
|
|
486
|
+
declare const AlephaCache: _$alepha.Service<_$alepha.Module>;
|
|
487
487
|
//#endregion
|
|
488
488
|
export { $cache, AlephaCache, CacheAtomOptions, CacheMiddlewareFn, CachePrimitive, CachePrimitiveFn, CachePrimitiveOptions, CacheProvider, CloudflareKVProvider, KVListKey, KVListOptions, KVListResult, KVNamespace, KVPutOptions, KV_DEFAULT_BINDING, MemoryCacheCall, MemoryCacheDelCall, MemoryCacheProvider, MemoryCacheProviderOptions, MemoryCacheSetCall, MemoryCacheStats, cacheOptions };
|
|
489
489
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/cache/core/providers/CacheProvider.ts","../../../src/cache/core/primitives/$cache.ts","../../../src/cache/core/providers/CloudflareKVProvider.ts","../../../src/cache/core/providers/MemoryCacheProvider.ts","../../../src/cache/core/index.ts"],"mappings":";;;;;;;;;;;;uBAQsB,aAAA;EAAA,UACV,OAAA,EAAS,WAAA;EAAA,UACT,OAAA,EAAS,WAAA;EAAA,UACT,KAAA;;;;;;EAmCP;;;;;;;;EAAA,SApBa,GAAA,CACd,IAAA,UACA,GAAA,WACC,OAAA,CAAQ,UAAA;EA8FgD;;;;;;;;;;EAAA,SAlF3C,GAAA,CACd,IAAA,UACA,GAAA,UACA,KAAA,EAAO,UAAA,EACP,GAAA,YACC,OAAA,CAAQ,UAAA;EA4J0C;;;;;;EAAA,SApJrC,GAAA,CAAI,IAAA,aAAiB,IAAA,aAAiB,OAAA;EAAA,SAEtC,GAAA,CAAI,IAAA,UAAc,GAAA,WAAc,OAAA;EAAA,SAEhC,IAAA,CAAK,IAAA,UAAc,MAAA,YAAkB,OAAA;;;;WAKrC,KAAA,CAAA,GAAS,OAAA;EAlCtB;;;;;;;;;;;EAAA,SA+Ca,IAAA,CACd,IAAA,UACA,GAAA,UACA,MAAA,WACC,OAAA;EA1BkC;;;EAmCxB,QAAA,CACX,IAAA,UACA,GAAA,UACA,KAAA,WACA,OAAA;IAAY,GAAA;IAAc,QAAA;EAAA,IACzB,OAAA;EApCkB;;;EA+CR,QAAA,GAAA,CAAY,IAAA,UAAc,GAAA,WAAc,OAAA,CAAQ,CAAA;EA1CpC;;;;;;EA4DZ,cAAA,CAAe,IAAA,UAAc,IAAA,aAAiB,OAAA;EAjCzD;;;EAAA,UAmDQ,SAAA,CAAU,KAAA,YAAiB,UAAA;EAhDT;;;EAAA,UAsElB,WAAA,GAAA,CAAe,UAAA,EAAY,UAAA,GAAa,CAAA;EA1D5B;;;EAAA,UA8EN,QAAA,CAAS,IAAA,EAAM,UAAA,GAAa,OAAA,CAAQ,UAAA;EA9ES;;;EAAA,UAiG7C,UAAA,CAAW,IAAA,EAAM,UAAA,GAAa,OAAA,CAAQ,UAAA;AAAA;;;;;;AAlMxD;;;;;;;;;;;;;;;;;;;;;;;;;;;iBCwCgB,MAAA,oDAAA,CACd,OAAA,EAAS,qBAAA,CAAsB,OAAA,EAAS,UAAA;EACtC,OAAA,MAAa,IAAA,EAAM,UAAA,KAAe,OAAA;AAAA,IAEnC,gBAAA,CAAiB,OAAA,EAAS,UAAA;AAAA,iBACb,MAAA,iDAAA,CACd,OAAA,GAAU,qBAAA,CAAsB,OAAA,EAAS,UAAA,IACxC,iBAAA,CAAkB,OAAA;AAAA,kBAFL,MAAA;AAAA,UAmCC,qBAAA;ED9EI;;;;;;;ECyFnB,IAAA;EDvEE;;;EC4EF,OAAA,OAAc,IAAA,EAAM,UAAA,KAAe,OAAA;ED9DjC;;;;ECoEF,GAAA,OAAU,IAAA,EAAM,UAAA;EDhEb;;;;ECsEH,QAAA,GAAW,iBAAA,CAAkB,aAAA;ED9DyB;;;;;;ECsEtD,GAAA,GAAM,YAAA;EDlE6B;;;ECuEnC,QAAA;EDrDgB;;;;EC2DhB,QAAA;AAAA;;;;cAQW,YAAA,EAAY,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/cache/core/providers/CacheProvider.ts","../../../src/cache/core/primitives/$cache.ts","../../../src/cache/core/providers/CloudflareKVProvider.ts","../../../src/cache/core/providers/MemoryCacheProvider.ts","../../../src/cache/core/index.ts"],"mappings":"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"}
|
package/dist/cache/core/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { $atom, $hook, $inject, $module, $
|
|
1
|
+
import { $atom, $hook, $inject, $module, $state, Alepha, AlephaError, KIND, OPTIONS, Primitive, createPrimitive, t } from "alepha";
|
|
2
2
|
import { DateTimeProvider } from "alepha/datetime";
|
|
3
3
|
import { $logger } from "alepha/logger";
|
|
4
4
|
//#region ../../src/cache/core/errors/CacheError.ts
|
|
@@ -416,7 +416,7 @@ const cacheOptions = $atom({
|
|
|
416
416
|
}
|
|
417
417
|
});
|
|
418
418
|
var CachePrimitive = class extends Primitive {
|
|
419
|
-
settings = $
|
|
419
|
+
settings = $state(cacheOptions);
|
|
420
420
|
dateTimeProvider = $inject(DateTimeProvider);
|
|
421
421
|
provider = this.$provider();
|
|
422
422
|
get container() {
|