alepha 0.14.4 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -102
- package/dist/api/audits/index.d.ts +331 -443
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/audits/index.js +2 -2
- package/dist/api/audits/index.js.map +1 -1
- package/dist/api/files/index.d.ts +0 -113
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +2 -3
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +151 -262
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/notifications/index.browser.js +4 -4
- package/dist/api/notifications/index.browser.js.map +1 -1
- package/dist/api/notifications/index.d.ts +164 -276
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/notifications/index.js +4 -4
- package/dist/api/notifications/index.js.map +1 -1
- package/dist/api/parameters/index.d.ts +265 -377
- package/dist/api/parameters/index.d.ts.map +1 -1
- package/dist/api/users/index.browser.js +1 -2
- package/dist/api/users/index.browser.js.map +1 -1
- package/dist/api/users/index.d.ts +195 -301
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +203 -184
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/batch/index.d.ts.map +1 -1
- package/dist/batch/index.js +1 -2
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/cache/core/index.d.ts.map +1 -1
- 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/index.d.ts +5900 -165
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1481 -639
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +8 -4
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +29 -25
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +563 -54
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +175 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +564 -54
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +563 -54
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts.map +1 -1
- package/dist/datetime/index.js +4 -4
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +89 -42
- package/dist/email/index.d.ts.map +1 -1
- package/dist/email/index.js +129 -33
- package/dist/email/index.js.map +1 -1
- package/dist/fake/index.d.ts +7969 -2
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/fake/index.js +22 -22
- package/dist/fake/index.js.map +1 -1
- package/dist/file/index.d.ts +134 -1
- package/dist/file/index.d.ts.map +1 -1
- package/dist/file/index.js +253 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/core/index.d.ts.map +1 -1
- package/dist/lock/redis/index.d.ts.map +1 -1
- package/dist/logger/index.d.ts +1 -2
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +1 -5
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +19 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +28 -4
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/chunk-DH6iiROE.js +38 -0
- package/dist/orm/index.browser.js +9 -9
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +2821 -0
- package/dist/orm/index.bun.js.map +1 -0
- package/dist/orm/index.d.ts +318 -169
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +2086 -1776
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +4 -4
- package/dist/queue/core/index.d.ts.map +1 -1
- package/dist/queue/redis/index.d.ts.map +1 -1
- package/dist/redis/index.bun.js +285 -0
- package/dist/redis/index.bun.js.map +1 -0
- package/dist/redis/index.d.ts +13 -31
- package/dist/redis/index.d.ts.map +1 -1
- package/dist/redis/index.js +18 -38
- package/dist/redis/index.js.map +1 -1
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/router/index.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +83 -1
- package/dist/scheduler/index.d.ts.map +1 -1
- package/dist/scheduler/index.js +393 -1
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.browser.js +5 -1
- package/dist/security/index.browser.js.map +1 -1
- package/dist/security/index.d.ts +598 -112
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +1808 -97
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +1200 -175
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +1268 -37
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +6 -3
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +1 -1
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/cookies/index.d.ts.map +1 -1
- package/dist/server/cookies/index.js +3 -3
- package/dist/server/cookies/index.js.map +1 -1
- package/dist/server/core/index.d.ts +115 -13
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +321 -139
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +0 -1
- package/dist/server/cors/index.d.ts.map +1 -1
- package/dist/server/health/index.d.ts +0 -1
- package/dist/server/health/index.d.ts.map +1 -1
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/links/index.browser.js +9 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +1 -2
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +14 -7
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts +514 -1
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/metrics/index.js +4462 -4
- package/dist/server/metrics/index.js.map +1 -1
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/proxy/index.d.ts +0 -1
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/swagger/index.d.ts +1 -2
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +1 -2
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +3 -1
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +10 -10
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +0 -1
- package/dist/thread/index.d.ts.map +1 -1
- package/dist/thread/index.js +2 -2
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/vite/index.d.ts +6315 -149
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +140 -469
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +9 -9
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +28 -28
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +9 -9
- package/dist/websocket/index.js.map +1 -1
- package/package.json +13 -18
- package/src/api/files/controllers/AdminFileStatsController.ts +0 -1
- package/src/api/users/atoms/realmAuthSettingsAtom.ts +5 -0
- package/src/api/users/controllers/{UserRealmController.ts → RealmController.ts} +11 -11
- package/src/api/users/entities/users.ts +1 -1
- package/src/api/users/index.ts +8 -8
- package/src/api/users/primitives/{$userRealm.ts → $realm.ts} +17 -19
- package/src/api/users/providers/{UserRealmProvider.ts → RealmProvider.ts} +26 -30
- package/src/api/users/schemas/{userRealmConfigSchema.ts → realmConfigSchema.ts} +2 -2
- package/src/api/users/services/CredentialService.ts +7 -7
- package/src/api/users/services/IdentityService.ts +4 -4
- package/src/api/users/services/RegistrationService.spec.ts +25 -27
- package/src/api/users/services/RegistrationService.ts +38 -27
- package/src/api/users/services/SessionCrudService.ts +3 -3
- package/src/api/users/services/SessionService.spec.ts +3 -3
- package/src/api/users/services/SessionService.ts +27 -18
- package/src/api/users/services/UserService.ts +7 -7
- package/src/batch/providers/BatchProvider.ts +1 -2
- package/src/cli/apps/AlephaCli.ts +2 -2
- package/src/cli/apps/AlephaPackageBuilderCli.ts +47 -20
- package/src/cli/assets/apiHelloControllerTs.ts +19 -0
- package/src/cli/assets/apiIndexTs.ts +16 -0
- package/src/cli/assets/biomeJson.ts +2 -1
- package/src/cli/assets/claudeMd.ts +308 -0
- package/src/cli/assets/dummySpecTs.ts +2 -1
- package/src/cli/assets/editorconfig.ts +2 -1
- package/src/cli/assets/mainBrowserTs.ts +4 -3
- package/src/cli/assets/mainCss.ts +24 -0
- package/src/cli/assets/mainServerTs.ts +24 -0
- package/src/cli/assets/tsconfigJson.ts +2 -1
- package/src/cli/assets/webAppRouterTs.ts +16 -0
- package/src/cli/assets/webHelloComponentTsx.ts +20 -0
- package/src/cli/assets/webIndexTs.ts +16 -0
- package/src/cli/atoms/appEntryOptions.ts +13 -0
- package/src/cli/atoms/buildOptions.ts +1 -1
- package/src/cli/atoms/changelogOptions.ts +1 -1
- package/src/cli/commands/build.ts +97 -61
- package/src/cli/commands/db.ts +21 -18
- package/src/cli/commands/deploy.ts +17 -5
- package/src/cli/commands/dev.ts +26 -47
- package/src/cli/commands/gen/env.ts +1 -1
- package/src/cli/commands/init.ts +79 -25
- package/src/cli/commands/lint.ts +9 -3
- package/src/cli/commands/test.ts +8 -2
- package/src/cli/commands/typecheck.ts +5 -1
- package/src/cli/commands/verify.ts +4 -2
- package/src/cli/defineConfig.ts +9 -0
- package/src/cli/index.ts +2 -1
- package/src/cli/providers/AppEntryProvider.ts +131 -0
- package/src/cli/providers/ViteBuildProvider.ts +82 -0
- package/src/cli/providers/ViteDevServerProvider.ts +350 -0
- package/src/cli/providers/ViteTemplateProvider.ts +27 -0
- package/src/cli/services/AlephaCliUtils.ts +72 -602
- package/src/cli/services/PackageManagerUtils.ts +308 -0
- package/src/cli/services/ProjectScaffolder.ts +329 -0
- package/src/command/helpers/Runner.ts +15 -3
- package/src/core/Alepha.ts +2 -8
- package/src/core/__tests__/Alepha-graph.spec.ts +4 -0
- package/src/core/index.shared.ts +1 -0
- package/src/core/index.ts +2 -0
- package/src/core/primitives/$hook.ts +6 -2
- package/src/core/primitives/$module.spec.ts +4 -0
- package/src/core/primitives/$module.ts +12 -0
- package/src/core/providers/AlsProvider.ts +1 -1
- package/src/core/providers/CodecManager.spec.ts +12 -6
- package/src/core/providers/CodecManager.ts +26 -6
- package/src/core/providers/EventManager.ts +169 -13
- package/src/core/providers/KeylessJsonSchemaCodec.spec.ts +878 -0
- package/src/core/providers/KeylessJsonSchemaCodec.ts +789 -0
- package/src/core/providers/SchemaValidator.spec.ts +236 -0
- package/src/core/providers/StateManager.spec.ts +27 -16
- package/src/email/providers/LocalEmailProvider.spec.ts +111 -87
- package/src/email/providers/LocalEmailProvider.ts +52 -15
- package/src/email/providers/NodemailerEmailProvider.ts +167 -56
- package/src/file/errors/FileError.ts +7 -0
- package/src/file/index.ts +9 -1
- package/src/file/providers/MemoryFileSystemProvider.ts +393 -0
- package/src/logger/providers/PrettyFormatterProvider.ts +0 -9
- package/src/mcp/errors/McpError.ts +30 -0
- package/src/mcp/index.ts +3 -0
- package/src/mcp/transports/SseMcpTransport.ts +16 -6
- package/src/orm/index.browser.ts +1 -19
- package/src/orm/index.bun.ts +77 -0
- package/src/orm/index.shared-server.ts +22 -0
- package/src/orm/index.shared.ts +15 -0
- package/src/orm/index.ts +19 -39
- package/src/orm/providers/DrizzleKitProvider.ts +3 -5
- package/src/orm/providers/drivers/BunPostgresProvider.ts +3 -5
- package/src/orm/providers/drivers/BunSqliteProvider.ts +1 -1
- package/src/orm/providers/drivers/CloudflareD1Provider.ts +4 -0
- package/src/orm/providers/drivers/DatabaseProvider.ts +4 -0
- package/src/orm/providers/drivers/PglitePostgresProvider.ts +4 -0
- package/src/orm/services/Repository.ts +19 -0
- package/src/redis/index.bun.ts +35 -0
- package/src/redis/providers/BunRedisProvider.ts +12 -43
- package/src/redis/providers/BunRedisSubscriberProvider.ts +2 -3
- package/src/redis/providers/NodeRedisProvider.ts +16 -34
- package/src/{server/security → security}/__tests__/BasicAuth.spec.ts +11 -11
- package/src/{server/security → security}/__tests__/ServerSecurityProvider-realm.spec.ts +21 -16
- package/src/{server/security/providers → security/__tests__}/ServerSecurityProvider.spec.ts +5 -5
- package/src/security/index.browser.ts +5 -0
- package/src/security/index.ts +90 -7
- package/src/security/primitives/{$realm.spec.ts → $issuer.spec.ts} +11 -11
- package/src/security/primitives/{$realm.ts → $issuer.ts} +20 -17
- package/src/security/primitives/$role.ts +5 -5
- package/src/security/primitives/$serviceAccount.spec.ts +5 -5
- package/src/security/primitives/$serviceAccount.ts +3 -3
- package/src/{server/security → security}/providers/ServerSecurityProvider.ts +5 -7
- package/src/server/auth/primitives/$auth.ts +10 -10
- package/src/server/auth/primitives/$authCredentials.ts +3 -3
- package/src/server/auth/primitives/$authGithub.ts +3 -3
- package/src/server/auth/primitives/$authGoogle.ts +3 -3
- package/src/server/auth/providers/ServerAuthProvider.ts +13 -13
- package/src/server/cache/providers/ServerCacheProvider.ts +1 -1
- package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
- package/src/server/core/index.ts +1 -1
- package/src/server/core/providers/BunHttpServerProvider.ts +1 -1
- package/src/server/core/providers/NodeHttpServerProvider.spec.ts +125 -0
- package/src/server/core/providers/NodeHttpServerProvider.ts +92 -24
- package/src/server/core/providers/ServerBodyParserProvider.ts +19 -23
- package/src/server/core/providers/ServerLoggerProvider.ts +23 -19
- package/src/server/core/providers/ServerProvider.ts +144 -24
- package/src/server/core/providers/ServerRouterProvider.ts +259 -115
- package/src/server/core/providers/ServerTimingProvider.ts +2 -2
- package/src/server/links/atoms/apiLinksAtom.ts +7 -0
- package/src/server/links/index.browser.ts +2 -0
- package/src/server/links/index.ts +3 -1
- package/src/server/links/providers/LinkProvider.ts +1 -1
- package/src/server/swagger/index.ts +1 -1
- package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
- package/src/sms/providers/LocalSmsProvider.ts +8 -7
- package/src/vite/index.ts +3 -2
- package/src/vite/tasks/buildClient.ts +0 -1
- package/src/vite/tasks/buildServer.ts +80 -22
- package/src/vite/tasks/copyAssets.ts +5 -4
- package/src/vite/tasks/generateCloudflare.ts +7 -0
- package/src/vite/tasks/generateSitemap.ts +64 -23
- package/src/vite/tasks/index.ts +0 -2
- package/src/vite/tasks/prerenderPages.ts +49 -24
- package/dist/server/security/index.browser.js +0 -13
- package/dist/server/security/index.browser.js.map +0 -1
- package/dist/server/security/index.d.ts +0 -173
- package/dist/server/security/index.d.ts.map +0 -1
- package/dist/server/security/index.js +0 -311
- package/dist/server/security/index.js.map +0 -1
- package/src/cli/assets/appRouterTs.ts +0 -9
- package/src/cli/assets/indexHtml.ts +0 -15
- package/src/cli/assets/mainTs.ts +0 -13
- package/src/cli/commands/format.ts +0 -17
- package/src/server/security/index.browser.ts +0 -10
- package/src/server/security/index.ts +0 -94
- package/src/vite/helpers/boot.ts +0 -106
- package/src/vite/plugins/viteAlephaDev.ts +0 -177
- package/src/vite/tasks/devServer.ts +0 -69
- package/src/vite/tasks/runAlepha.ts +0 -270
- /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
- /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/index.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/index.ts"],"mappings":";;;;;;;;;;;;KAmBY,QAAA,GAAW,QAAA,CAAS,KAAA;AAAA,KACpB,QAAA,GAAW,aAAA,CAAc,QAAA;AAAA,KACzB,YAAA,YAER,aAAA,CAAc,QAAA,YACL,cAAA;AAAA,cAEA,KAAA,SAAK,QAAA;AAAA,cACL,UAAA,GAAc,KAAA,cAAiB,KAAA,IAAS,QAAA;AAAA,cAIxC,gBAAA;EAAA,OACG,OAAA,EAAS,KAAA,CAAM,UAAA;EAAA,UAQnB,MAAA,EAAM,MAAA;EAAA,UACN,GAAA,EAAK,QAAA;EAAA,mBACI,QAAA,EAAU,OAAA;EAAA,mBACV,SAAA,EAAW,QAAA;;qBAQX,OAAA,EARmB,OAAA,CAQZ,aAAA;EAAA,mBAgBP,MAAA,EAhBO,OAAA,CAgBD,aAAA;EAelB,SAAA,CAAU,MAAA;EAIV,UAAA,CAAW,KAAA,YAAiB,KAAA,IAAS,QAAA;EA/D1C;;;EAsEK,GAAA,CACL,IAAA,oBAAwB,IAAA,GAAO,KAAA,sBAC9B,QAAA;EAvEsB;AAE3B;;EA4ES,EAAA,CAAG,IAAA,oBAAwB,IAAA,GAAO,KAAA,sBAA2B,QAAA;EA5EpD;;AAClB;EAkFS,WAAA,CAAY,IAAA,GAAM,IAAA,YAAgB,QAAA;;;;EAOlC,GAAA,CAAA,GAAO,QAAA;EAzFqC;;;AAIrD;;EA8FS,YAAA,CAAA;EA7FsB;;;;;EAyGtB,SAAA,CAAA;EA9F+B;;;;;EAAA,UA0G5B,cAAA,CAAA,GAAkB,QAAA;EA/CM;;;EA0D3B,QAAA,GACL,QAAA,EAAU,YAAA,EACV,IAAA,GAAO,cAAA,KACN,QAAA;EAYI,cAAA,CAAe,KAAA,YAAiB,KAAA,IAAS,YAAA;EA3DlC;;;;EAuED,IAAA,CAAA,GAAQ,OAAA;EAZ2B;;;;;;EAsBzC,IAAA,CACL,QAAA,EAAU,YAAA,EACV,OAAA;IACE,MAAA,GAAS,WAAA;IACT,GAAA;EAAA,IAED,OAAA;EA2BI,cAAA,CACL,GAAA,iBACA,QAAA,EAAU,YAAA,EACV,KAAA,aACC,QAAA;EAoEY;;;EAlDR,aAAA,CACL,QAAA,cACA,QAAA,EAAU,YAAA,EACV,GAAA,YACC,OAAA;EA8BI,YAAA,CAAa,OAAA,EAAS,OAAA;EAMtB,aAAA,CAAc,QAAA,EAAU,QAAA;EA8BnB;;;EArBC,QAAA,GAAA,CACX,EAAA,GAAK,MAAA,EAAQ,WAAA,KAAgB,OAAA,CAAQ,CAAA,GACrC,QAAA,EAAU,YAAA,GACT,OAAA,CAAQ,CAAA;EAkEa;;;EAjDX,MAAA,CACX,QAAA,EAAU,YAAA,EACV,IAAA,GAAO,cAAA,GACN,OAAA;EApS0B;;;EAkVtB,KAAA,CAAA,GAAS,QAAA;EAzUD;;;EAiVR,KAAA,CAAA;AAAA;AAAA,UAKQ,QAAA;EACf,KAAA;EACA,QAAA;EACA,GAAA;AAAA;AAAA,UAGe,OAAA;EACf,GAAA;EACA,KAAA;EACA,QAAA;EACA,QAAA;EACA,KAAA;AAAA;;;;;;;;cC/XW,SAAA;EAAA,UAAsB,wBAAA,GAAwB,iBAAA;EAAA;;UAK1C,wBAAA;EDGL;;;ECCV,OAAA;EDDmC;AACrC;;ECKE,QAAA,EAAU,YAAA;AAAA;AAAA,cAKC,iBAAA,SAA0B,SAAA,CAAU,wBAAA;EAAA,mBAC5B,gBAAA,EAAgB,gBAAA;EAE5B,MAAA;EAAA,UAEG,MAAA,CAAA;AAAA;;;cC1BC,cAAA,EAAc,OAAA,CAAA,OAAA,CAIzB,OAAA,CAJyB,MAAA"}
|
package/dist/datetime/index.js
CHANGED
|
@@ -132,16 +132,16 @@ var DateTimeProvider = class DateTimeProvider {
|
|
|
132
132
|
*/
|
|
133
133
|
wait(duration, options = {}) {
|
|
134
134
|
return new Promise((resolve) => {
|
|
135
|
-
let clearTimeout
|
|
135
|
+
let clearTimeout;
|
|
136
136
|
let callback;
|
|
137
137
|
const timeout = this.createTimeout(() => {
|
|
138
|
-
if (options.signal && clearTimeout
|
|
138
|
+
if (options.signal && clearTimeout) options.signal.removeEventListener("abort", callback);
|
|
139
139
|
resolve();
|
|
140
140
|
}, duration, options.now);
|
|
141
141
|
if (options.signal) {
|
|
142
|
-
clearTimeout
|
|
142
|
+
clearTimeout = () => this.clearTimeout(timeout);
|
|
143
143
|
callback = () => {
|
|
144
|
-
clearTimeout
|
|
144
|
+
clearTimeout();
|
|
145
145
|
resolve();
|
|
146
146
|
};
|
|
147
147
|
options.signal.addEventListener("abort", callback);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["clearTimeout"],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/index.ts"],"sourcesContent":["import \"dayjs/plugin/relativeTime.js\";\nimport \"dayjs/plugin/duration.js\";\nimport \"dayjs/plugin/utc.js\";\nimport \"dayjs/plugin/timezone.js\";\nimport \"dayjs/plugin/localizedFormat.js\";\nimport \"dayjs/locale/ar.js\";\nimport \"dayjs/locale/fr.js\";\nimport { $hook, $inject, Alepha } from \"alepha\";\nimport DayjsApi, {\n type Dayjs,\n type ManipulateType,\n type PluginFunc,\n} from \"dayjs\";\nimport dayjsDuration from \"dayjs/plugin/duration.js\";\nimport dayjsLocalizedFormat from \"dayjs/plugin/localizedFormat.js\";\nimport dayjsRelativeTime from \"dayjs/plugin/relativeTime.js\";\nimport dayjsTimezone from \"dayjs/plugin/timezone.js\";\nimport dayjsUtc from \"dayjs/plugin/utc.js\";\n\nexport type DateTime = DayjsApi.Dayjs;\nexport type Duration = dayjsDuration.Duration;\nexport type DurationLike =\n | number\n | dayjsDuration.Duration\n | [number, ManipulateType];\n\nexport const dayjs = DayjsApi;\nexport const isDateTime = (value: unknown): value is DateTime => {\n return dayjs.isDayjs(value);\n};\n\nexport class DateTimeProvider {\n public static PLUGINS: Array<PluginFunc<any>> = [\n dayjsDuration,\n dayjsRelativeTime,\n dayjsUtc,\n dayjsTimezone,\n dayjsLocalizedFormat,\n ];\n\n protected alepha = $inject(Alepha);\n protected ref: DateTime | null = null;\n protected readonly timeouts: Timeout[] = [];\n protected readonly intervals: Interval[] = [];\n\n constructor() {\n for (const plugin of DateTimeProvider.PLUGINS) {\n dayjs.extend(plugin);\n }\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n // we start intervals now but first tick will be rejected as App is not ready yet\n await Promise.all(\n this.intervals.map(async (interval) => {\n if (interval.timer != null) {\n return;\n }\n await interval.run();\n interval.timer = setInterval(interval.run, interval.duration);\n }),\n );\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: () => {\n for (const timeout of this.timeouts) {\n this.clearTimeout(timeout);\n }\n\n for (const interval of this.intervals) {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n },\n });\n\n public setLocale(locale: string): void {\n dayjs.locale(locale);\n }\n\n public isDateTime(value: unknown): value is DateTime {\n return dayjs.isDayjs(value);\n }\n\n /**\n * Create a new UTC DateTime instance.\n */\n public utc(\n date: string | number | Date | Dayjs | null | undefined,\n ): DateTime {\n return dayjs.utc(date);\n }\n\n /**\n * Create a new DateTime instance.\n */\n public of(date: string | number | Date | Dayjs | null | undefined): DateTime {\n return dayjs(date);\n }\n\n /**\n * Get the current date as a string.\n */\n public toISOString(date: Date | string | DateTime = this.now()): string {\n return this.of(date).toISOString();\n }\n\n /**\n * Get the current date.\n */\n public now(): DateTime {\n return this.getCurrentDate();\n }\n\n /**\n * Get the current date as a string.\n *\n * This is much faster than `DateTimeProvider.now().toISOString()` as it avoids creating a DateTime instance.\n */\n public nowISOString(): string {\n if (this.ref) {\n return this.ref.toISOString();\n }\n return new Date().toISOString();\n }\n\n /**\n * Get the current date as milliseconds since epoch.\n *\n * This is much faster than `DateTimeProvider.now().valueOf()` as it avoids creating a DateTime instance.\n */\n public nowMillis(): number {\n if (this.ref) {\n return this.ref.valueOf();\n }\n return Date.now();\n }\n\n /**\n * Get the current date as a string.\n *\n * @protected\n */\n protected getCurrentDate(): DateTime {\n if (this.ref) {\n return this.ref;\n }\n\n return dayjs();\n }\n\n /**\n * Create a new Duration instance.\n */\n public duration = (\n duration: DurationLike,\n unit?: ManipulateType,\n ): Duration => {\n if (Array.isArray(duration)) {\n return dayjs.duration(duration[0], duration[1]);\n }\n\n if (typeof duration === \"number\") {\n return dayjs.duration(duration, unit || \"milliseconds\");\n }\n\n return duration;\n };\n\n public isDurationLike(value: unknown): value is DurationLike {\n return dayjs.isDuration(this.duration(value as DurationLike));\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Timer Management\n\n /**\n * Return a promise that resolves after the next tick.\n * It uses `setTimeout` with 0 ms delay.\n */\n public async tick(): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n\n /**\n * Wait for a certain duration.\n *\n * You can clear the timeout by using the `AbortSignal` API.\n * Aborted signal will resolve the promise immediately, it does not reject it.\n */\n public wait(\n duration: DurationLike,\n options: {\n signal?: AbortSignal;\n now?: number;\n } = {},\n ): Promise<void> {\n return new Promise((resolve) => {\n let clearTimeout: any;\n let callback: any;\n\n const timeout = this.createTimeout(\n () => {\n if (options.signal && clearTimeout) {\n options.signal.removeEventListener(\"abort\", callback);\n }\n resolve();\n },\n duration,\n options.now,\n );\n\n if (options.signal) {\n clearTimeout = () => this.clearTimeout(timeout);\n callback = () => {\n clearTimeout();\n resolve();\n };\n options.signal.addEventListener(\"abort\", callback);\n }\n });\n }\n\n public createInterval(\n run: () => unknown,\n duration: DurationLike,\n start = false,\n ): Interval {\n const interval: Interval = {\n run,\n duration: this.duration(duration).asMilliseconds(),\n };\n\n this.intervals.push(interval);\n\n if (start) {\n interval.timer = setInterval(interval.run, interval.duration);\n }\n\n return interval;\n }\n\n /**\n * Run a callback after a certain duration.\n */\n public createTimeout(\n callback: () => void,\n duration: DurationLike,\n now?: number,\n ): Timeout {\n if (this.ref && now) {\n const next = this.of(now).add(this.duration(duration));\n if (next < this.now()) {\n callback();\n }\n return {\n now,\n duration: 0,\n callback: () => {},\n clear: () => {},\n };\n }\n\n const timeout: Timeout = {\n now: now ?? this.now().valueOf(),\n duration: this.duration(duration).asMilliseconds(),\n callback,\n clear: () => this.clearTimeout(timeout),\n };\n\n timeout.timer = setTimeout(() => {\n timeout.callback();\n }, timeout.duration);\n\n this.timeouts.push(timeout);\n\n return timeout;\n }\n\n public clearTimeout(timeout: Timeout): void {\n clearTimeout(timeout.timer);\n timeout.duration = 0;\n timeout.timer = null;\n }\n\n public clearInterval(interval: Interval): void {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n\n /**\n * Run a function with a deadline.\n */\n public async deadline<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n duration: DurationLike,\n ): Promise<T> {\n const abort = new AbortController();\n const timeout = this.createTimeout(() => abort.abort(), duration);\n try {\n return await fn(abort.signal);\n } finally {\n this.clearTimeout(timeout);\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Testing\n\n /**\n * Add time to the current date.\n */\n public async travel(\n duration: DurationLike,\n unit?: ManipulateType,\n ): Promise<void> {\n this.ref = this.ref || this.now();\n this.ref = this.ref.add(this.duration(duration, unit));\n const ms = this.duration(duration, unit).asMilliseconds();\n const now = Date.now();\n\n for (const timeout of this.timeouts) {\n if (!timeout.timer) {\n continue;\n }\n\n clearTimeout(timeout.timer);\n timeout.timer = null;\n\n const spent = now - timeout.now;\n timeout.duration = timeout.duration - spent - ms;\n\n if (timeout.duration <= 0) {\n timeout.callback();\n } else {\n timeout.timer = setTimeout(() => {\n timeout.callback();\n }, timeout.duration);\n }\n }\n\n for (const interval of this.intervals) {\n if (!interval.timer) {\n continue;\n }\n\n clearInterval(interval.timer);\n interval.timer = null;\n\n const repeat = Math.floor(ms / interval.duration);\n for (let i = 0; i < repeat; i++) {\n await interval.run();\n }\n }\n\n await this.tick();\n }\n\n /**\n * Stop the time.\n */\n public pause(): DateTime {\n this.ref = this.ref || this.now();\n return this.ref;\n }\n\n /**\n * Reset the reference date.\n */\n public reset(): void {\n this.ref = null;\n }\n}\n\nexport interface Interval {\n timer?: any;\n duration: number;\n run: () => unknown;\n}\n\nexport interface Timeout {\n now: number;\n timer?: any;\n duration: number;\n callback: () => void;\n clear: () => void;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\n/**\n * Run a function periodically.\n * It uses the `setInterval` internally.\n * It starts by default when the context starts and stops when the context stops.\n */\nexport const $interval = (options: IntervalPrimitiveOptions) =>\n createPrimitive(IntervalPrimitive, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface IntervalPrimitiveOptions {\n /**\n * The interval handler.\n */\n handler: () => unknown;\n\n /**\n * The interval duration.\n */\n duration: DurationLike;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class IntervalPrimitive extends Primitive<IntervalPrimitiveOptions> {\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n public called = 0;\n\n protected onInit() {\n this.dateTimeProvider.createInterval(async () => {\n await this.options.handler();\n this.called += 1;\n }, this.options.duration);\n }\n}\n\n$interval[KIND] = IntervalPrimitive;\n","import { $module } from \"alepha\";\nimport { $interval } from \"./primitives/$interval.ts\";\nimport { DateTimeProvider } from \"./providers/DateTimeProvider.ts\";\n\nexport * from \"./primitives/$interval.ts\";\nexport * from \"./providers/DateTimeProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaDateTime = $module({\n name: \"alepha.datetime\",\n primitives: [$interval],\n services: [DateTimeProvider],\n});\n"],"mappings":";;;;;;;;;;;AA0BA,MAAa,QAAQ;AACrB,MAAa,cAAc,UAAsC;AAC/D,QAAO,MAAM,QAAQ,MAAM;;AAG7B,IAAa,mBAAb,MAAa,iBAAiB;CAC5B,OAAc,UAAkC;EAC9C;EACA;EACA;EACA;EACA;EACD;CAED,AAAU,SAAS,QAAQ,OAAO;CAClC,AAAU,MAAuB;CACjC,AAAmB,WAAsB,EAAE;CAC3C,AAAmB,YAAwB,EAAE;CAE7C,cAAc;AACZ,OAAK,MAAM,UAAU,iBAAiB,QACpC,OAAM,OAAO,OAAO;;CAIxB,AAAmB,UAAU,MAAM;EACjC,IAAI;EACJ,SAAS,YAAY;AAEnB,SAAM,QAAQ,IACZ,KAAK,UAAU,IAAI,OAAO,aAAa;AACrC,QAAI,SAAS,SAAS,KACpB;AAEF,UAAM,SAAS,KAAK;AACpB,aAAS,QAAQ,YAAY,SAAS,KAAK,SAAS,SAAS;KAC7D,CACH;;EAEJ,CAAC;CAEF,AAAmB,SAAS,MAAM;EAChC,IAAI;EACJ,eAAe;AACb,QAAK,MAAM,WAAW,KAAK,SACzB,MAAK,aAAa,QAAQ;AAG5B,QAAK,MAAM,YAAY,KAAK,WAAW;AACrC,kBAAc,SAAS,MAAM;AAC7B,aAAS,WAAW;AACpB,aAAS,QAAQ;;;EAGtB,CAAC;CAEF,AAAO,UAAU,QAAsB;AACrC,QAAM,OAAO,OAAO;;CAGtB,AAAO,WAAW,OAAmC;AACnD,SAAO,MAAM,QAAQ,MAAM;;;;;CAM7B,AAAO,IACL,MACU;AACV,SAAO,MAAM,IAAI,KAAK;;;;;CAMxB,AAAO,GAAG,MAAmE;AAC3E,SAAO,MAAM,KAAK;;;;;CAMpB,AAAO,YAAY,OAAiC,KAAK,KAAK,EAAU;AACtE,SAAO,KAAK,GAAG,KAAK,CAAC,aAAa;;;;;CAMpC,AAAO,MAAgB;AACrB,SAAO,KAAK,gBAAgB;;;;;;;CAQ9B,AAAO,eAAuB;AAC5B,MAAI,KAAK,IACP,QAAO,KAAK,IAAI,aAAa;AAE/B,0BAAO,IAAI,MAAM,EAAC,aAAa;;;;;;;CAQjC,AAAO,YAAoB;AACzB,MAAI,KAAK,IACP,QAAO,KAAK,IAAI,SAAS;AAE3B,SAAO,KAAK,KAAK;;;;;;;CAQnB,AAAU,iBAA2B;AACnC,MAAI,KAAK,IACP,QAAO,KAAK;AAGd,SAAO,OAAO;;;;;CAMhB,AAAO,YACL,UACA,SACa;AACb,MAAI,MAAM,QAAQ,SAAS,CACzB,QAAO,MAAM,SAAS,SAAS,IAAI,SAAS,GAAG;AAGjD,MAAI,OAAO,aAAa,SACtB,QAAO,MAAM,SAAS,UAAU,QAAQ,eAAe;AAGzD,SAAO;;CAGT,AAAO,eAAe,OAAuC;AAC3D,SAAO,MAAM,WAAW,KAAK,SAAS,MAAsB,CAAC;;;;;;CAW/D,MAAa,OAAsB;AACjC,QAAM,IAAI,SAAS,YAAY,WAAW,SAAS,EAAE,CAAC;;;;;;;;CASxD,AAAO,KACL,UACA,UAGI,EAAE,EACS;AACf,SAAO,IAAI,SAAS,YAAY;GAC9B,IAAIA;GACJ,IAAI;GAEJ,MAAM,UAAU,KAAK,oBACb;AACJ,QAAI,QAAQ,UAAUA,eACpB,SAAQ,OAAO,oBAAoB,SAAS,SAAS;AAEvD,aAAS;MAEX,UACA,QAAQ,IACT;AAED,OAAI,QAAQ,QAAQ;AAClB,2BAAqB,KAAK,aAAa,QAAQ;AAC/C,qBAAiB;AACf,qBAAc;AACd,cAAS;;AAEX,YAAQ,OAAO,iBAAiB,SAAS,SAAS;;IAEpD;;CAGJ,AAAO,eACL,KACA,UACA,QAAQ,OACE;EACV,MAAM,WAAqB;GACzB;GACA,UAAU,KAAK,SAAS,SAAS,CAAC,gBAAgB;GACnD;AAED,OAAK,UAAU,KAAK,SAAS;AAE7B,MAAI,MACF,UAAS,QAAQ,YAAY,SAAS,KAAK,SAAS,SAAS;AAG/D,SAAO;;;;;CAMT,AAAO,cACL,UACA,UACA,KACS;AACT,MAAI,KAAK,OAAO,KAAK;AAEnB,OADa,KAAK,GAAG,IAAI,CAAC,IAAI,KAAK,SAAS,SAAS,CAAC,GAC3C,KAAK,KAAK,CACnB,WAAU;AAEZ,UAAO;IACL;IACA,UAAU;IACV,gBAAgB;IAChB,aAAa;IACd;;EAGH,MAAM,UAAmB;GACvB,KAAK,OAAO,KAAK,KAAK,CAAC,SAAS;GAChC,UAAU,KAAK,SAAS,SAAS,CAAC,gBAAgB;GAClD;GACA,aAAa,KAAK,aAAa,QAAQ;GACxC;AAED,UAAQ,QAAQ,iBAAiB;AAC/B,WAAQ,UAAU;KACjB,QAAQ,SAAS;AAEpB,OAAK,SAAS,KAAK,QAAQ;AAE3B,SAAO;;CAGT,AAAO,aAAa,SAAwB;AAC1C,eAAa,QAAQ,MAAM;AAC3B,UAAQ,WAAW;AACnB,UAAQ,QAAQ;;CAGlB,AAAO,cAAc,UAA0B;AAC7C,gBAAc,SAAS,MAAM;AAC7B,WAAS,WAAW;AACpB,WAAS,QAAQ;;;;;CAMnB,MAAa,SACX,IACA,UACY;EACZ,MAAM,QAAQ,IAAI,iBAAiB;EACnC,MAAM,UAAU,KAAK,oBAAoB,MAAM,OAAO,EAAE,SAAS;AACjE,MAAI;AACF,UAAO,MAAM,GAAG,MAAM,OAAO;YACrB;AACR,QAAK,aAAa,QAAQ;;;;;;CAW9B,MAAa,OACX,UACA,MACe;AACf,OAAK,MAAM,KAAK,OAAO,KAAK,KAAK;AACjC,OAAK,MAAM,KAAK,IAAI,IAAI,KAAK,SAAS,UAAU,KAAK,CAAC;EACtD,MAAM,KAAK,KAAK,SAAS,UAAU,KAAK,CAAC,gBAAgB;EACzD,MAAM,MAAM,KAAK,KAAK;AAEtB,OAAK,MAAM,WAAW,KAAK,UAAU;AACnC,OAAI,CAAC,QAAQ,MACX;AAGF,gBAAa,QAAQ,MAAM;AAC3B,WAAQ,QAAQ;GAEhB,MAAM,QAAQ,MAAM,QAAQ;AAC5B,WAAQ,WAAW,QAAQ,WAAW,QAAQ;AAE9C,OAAI,QAAQ,YAAY,EACtB,SAAQ,UAAU;OAElB,SAAQ,QAAQ,iBAAiB;AAC/B,YAAQ,UAAU;MACjB,QAAQ,SAAS;;AAIxB,OAAK,MAAM,YAAY,KAAK,WAAW;AACrC,OAAI,CAAC,SAAS,MACZ;AAGF,iBAAc,SAAS,MAAM;AAC7B,YAAS,QAAQ;GAEjB,MAAM,SAAS,KAAK,MAAM,KAAK,SAAS,SAAS;AACjD,QAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,IAC1B,OAAM,SAAS,KAAK;;AAIxB,QAAM,KAAK,MAAM;;;;;CAMnB,AAAO,QAAkB;AACvB,OAAK,MAAM,KAAK,OAAO,KAAK,KAAK;AACjC,SAAO,KAAK;;;;;CAMd,AAAO,QAAc;AACnB,OAAK,MAAM;;;;;;;;;;;AChXf,MAAa,aAAa,YACxB,gBAAgB,mBAAmB,QAAQ;AAkB7C,IAAa,oBAAb,cAAuC,UAAoC;CACzE,AAAmB,mBAAmB,QAAQ,iBAAiB;CAE/D,AAAO,SAAS;CAEhB,AAAU,SAAS;AACjB,OAAK,iBAAiB,eAAe,YAAY;AAC/C,SAAM,KAAK,QAAQ,SAAS;AAC5B,QAAK,UAAU;KACd,KAAK,QAAQ,SAAS;;;AAI7B,UAAU,QAAQ;;;;AClClB,MAAa,iBAAiB,QAAQ;CACpC,MAAM;CACN,YAAY,CAAC,UAAU;CACvB,UAAU,CAAC,iBAAiB;CAC7B,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/datetime/providers/DateTimeProvider.ts","../../src/datetime/primitives/$interval.ts","../../src/datetime/index.ts"],"sourcesContent":["import \"dayjs/plugin/relativeTime.js\";\nimport \"dayjs/plugin/duration.js\";\nimport \"dayjs/plugin/utc.js\";\nimport \"dayjs/plugin/timezone.js\";\nimport \"dayjs/plugin/localizedFormat.js\";\nimport \"dayjs/locale/ar.js\";\nimport \"dayjs/locale/fr.js\";\nimport { $hook, $inject, Alepha } from \"alepha\";\nimport DayjsApi, {\n type Dayjs,\n type ManipulateType,\n type PluginFunc,\n} from \"dayjs\";\nimport dayjsDuration from \"dayjs/plugin/duration.js\";\nimport dayjsLocalizedFormat from \"dayjs/plugin/localizedFormat.js\";\nimport dayjsRelativeTime from \"dayjs/plugin/relativeTime.js\";\nimport dayjsTimezone from \"dayjs/plugin/timezone.js\";\nimport dayjsUtc from \"dayjs/plugin/utc.js\";\n\nexport type DateTime = DayjsApi.Dayjs;\nexport type Duration = dayjsDuration.Duration;\nexport type DurationLike =\n | number\n | dayjsDuration.Duration\n | [number, ManipulateType];\n\nexport const dayjs = DayjsApi;\nexport const isDateTime = (value: unknown): value is DateTime => {\n return dayjs.isDayjs(value);\n};\n\nexport class DateTimeProvider {\n public static PLUGINS: Array<PluginFunc<any>> = [\n dayjsDuration,\n dayjsRelativeTime,\n dayjsUtc,\n dayjsTimezone,\n dayjsLocalizedFormat,\n ];\n\n protected alepha = $inject(Alepha);\n protected ref: DateTime | null = null;\n protected readonly timeouts: Timeout[] = [];\n protected readonly intervals: Interval[] = [];\n\n constructor() {\n for (const plugin of DateTimeProvider.PLUGINS) {\n dayjs.extend(plugin);\n }\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: async () => {\n // we start intervals now but first tick will be rejected as App is not ready yet\n await Promise.all(\n this.intervals.map(async (interval) => {\n if (interval.timer != null) {\n return;\n }\n await interval.run();\n interval.timer = setInterval(interval.run, interval.duration);\n }),\n );\n },\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: () => {\n for (const timeout of this.timeouts) {\n this.clearTimeout(timeout);\n }\n\n for (const interval of this.intervals) {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n },\n });\n\n public setLocale(locale: string): void {\n dayjs.locale(locale);\n }\n\n public isDateTime(value: unknown): value is DateTime {\n return dayjs.isDayjs(value);\n }\n\n /**\n * Create a new UTC DateTime instance.\n */\n public utc(\n date: string | number | Date | Dayjs | null | undefined,\n ): DateTime {\n return dayjs.utc(date);\n }\n\n /**\n * Create a new DateTime instance.\n */\n public of(date: string | number | Date | Dayjs | null | undefined): DateTime {\n return dayjs(date);\n }\n\n /**\n * Get the current date as a string.\n */\n public toISOString(date: Date | string | DateTime = this.now()): string {\n return this.of(date).toISOString();\n }\n\n /**\n * Get the current date.\n */\n public now(): DateTime {\n return this.getCurrentDate();\n }\n\n /**\n * Get the current date as a string.\n *\n * This is much faster than `DateTimeProvider.now().toISOString()` as it avoids creating a DateTime instance.\n */\n public nowISOString(): string {\n if (this.ref) {\n return this.ref.toISOString();\n }\n return new Date().toISOString();\n }\n\n /**\n * Get the current date as milliseconds since epoch.\n *\n * This is much faster than `DateTimeProvider.now().valueOf()` as it avoids creating a DateTime instance.\n */\n public nowMillis(): number {\n if (this.ref) {\n return this.ref.valueOf();\n }\n return Date.now();\n }\n\n /**\n * Get the current date as a string.\n *\n * @protected\n */\n protected getCurrentDate(): DateTime {\n if (this.ref) {\n return this.ref;\n }\n\n return dayjs();\n }\n\n /**\n * Create a new Duration instance.\n */\n public duration = (\n duration: DurationLike,\n unit?: ManipulateType,\n ): Duration => {\n if (Array.isArray(duration)) {\n return dayjs.duration(duration[0], duration[1]);\n }\n\n if (typeof duration === \"number\") {\n return dayjs.duration(duration, unit || \"milliseconds\");\n }\n\n return duration;\n };\n\n public isDurationLike(value: unknown): value is DurationLike {\n return dayjs.isDuration(this.duration(value as DurationLike));\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Timer Management\n\n /**\n * Return a promise that resolves after the next tick.\n * It uses `setTimeout` with 0 ms delay.\n */\n public async tick(): Promise<void> {\n await new Promise((resolve) => setTimeout(resolve, 0));\n }\n\n /**\n * Wait for a certain duration.\n *\n * You can clear the timeout by using the `AbortSignal` API.\n * Aborted signal will resolve the promise immediately, it does not reject it.\n */\n public wait(\n duration: DurationLike,\n options: {\n signal?: AbortSignal;\n now?: number;\n } = {},\n ): Promise<void> {\n return new Promise((resolve) => {\n let clearTimeout: any;\n let callback: any;\n\n const timeout = this.createTimeout(\n () => {\n if (options.signal && clearTimeout) {\n options.signal.removeEventListener(\"abort\", callback);\n }\n resolve();\n },\n duration,\n options.now,\n );\n\n if (options.signal) {\n clearTimeout = () => this.clearTimeout(timeout);\n callback = () => {\n clearTimeout();\n resolve();\n };\n options.signal.addEventListener(\"abort\", callback);\n }\n });\n }\n\n public createInterval(\n run: () => unknown,\n duration: DurationLike,\n start = false,\n ): Interval {\n const interval: Interval = {\n run,\n duration: this.duration(duration).asMilliseconds(),\n };\n\n this.intervals.push(interval);\n\n if (start) {\n interval.timer = setInterval(interval.run, interval.duration);\n }\n\n return interval;\n }\n\n /**\n * Run a callback after a certain duration.\n */\n public createTimeout(\n callback: () => void,\n duration: DurationLike,\n now?: number,\n ): Timeout {\n if (this.ref && now) {\n const next = this.of(now).add(this.duration(duration));\n if (next < this.now()) {\n callback();\n }\n return {\n now,\n duration: 0,\n callback: () => {},\n clear: () => {},\n };\n }\n\n const timeout: Timeout = {\n now: now ?? this.now().valueOf(),\n duration: this.duration(duration).asMilliseconds(),\n callback,\n clear: () => this.clearTimeout(timeout),\n };\n\n timeout.timer = setTimeout(() => {\n timeout.callback();\n }, timeout.duration);\n\n this.timeouts.push(timeout);\n\n return timeout;\n }\n\n public clearTimeout(timeout: Timeout): void {\n clearTimeout(timeout.timer);\n timeout.duration = 0;\n timeout.timer = null;\n }\n\n public clearInterval(interval: Interval): void {\n clearInterval(interval.timer);\n interval.duration = 0;\n interval.timer = null;\n }\n\n /**\n * Run a function with a deadline.\n */\n public async deadline<T>(\n fn: (signal: AbortSignal) => Promise<T>,\n duration: DurationLike,\n ): Promise<T> {\n const abort = new AbortController();\n const timeout = this.createTimeout(() => abort.abort(), duration);\n try {\n return await fn(abort.signal);\n } finally {\n this.clearTimeout(timeout);\n }\n }\n\n // -------------------------------------------------------------------------------------------------------------------\n\n // Testing\n\n /**\n * Add time to the current date.\n */\n public async travel(\n duration: DurationLike,\n unit?: ManipulateType,\n ): Promise<void> {\n this.ref = this.ref || this.now();\n this.ref = this.ref.add(this.duration(duration, unit));\n const ms = this.duration(duration, unit).asMilliseconds();\n const now = Date.now();\n\n for (const timeout of this.timeouts) {\n if (!timeout.timer) {\n continue;\n }\n\n clearTimeout(timeout.timer);\n timeout.timer = null;\n\n const spent = now - timeout.now;\n timeout.duration = timeout.duration - spent - ms;\n\n if (timeout.duration <= 0) {\n timeout.callback();\n } else {\n timeout.timer = setTimeout(() => {\n timeout.callback();\n }, timeout.duration);\n }\n }\n\n for (const interval of this.intervals) {\n if (!interval.timer) {\n continue;\n }\n\n clearInterval(interval.timer);\n interval.timer = null;\n\n const repeat = Math.floor(ms / interval.duration);\n for (let i = 0; i < repeat; i++) {\n await interval.run();\n }\n }\n\n await this.tick();\n }\n\n /**\n * Stop the time.\n */\n public pause(): DateTime {\n this.ref = this.ref || this.now();\n return this.ref;\n }\n\n /**\n * Reset the reference date.\n */\n public reset(): void {\n this.ref = null;\n }\n}\n\nexport interface Interval {\n timer?: any;\n duration: number;\n run: () => unknown;\n}\n\nexport interface Timeout {\n now: number;\n timer?: any;\n duration: number;\n callback: () => void;\n clear: () => void;\n}\n","import { $inject, createPrimitive, KIND, Primitive } from \"alepha\";\nimport {\n DateTimeProvider,\n type DurationLike,\n} from \"../providers/DateTimeProvider.ts\";\n\n/**\n * Run a function periodically.\n * It uses the `setInterval` internally.\n * It starts by default when the context starts and stops when the context stops.\n */\nexport const $interval = (options: IntervalPrimitiveOptions) =>\n createPrimitive(IntervalPrimitive, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface IntervalPrimitiveOptions {\n /**\n * The interval handler.\n */\n handler: () => unknown;\n\n /**\n * The interval duration.\n */\n duration: DurationLike;\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class IntervalPrimitive extends Primitive<IntervalPrimitiveOptions> {\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n\n public called = 0;\n\n protected onInit() {\n this.dateTimeProvider.createInterval(async () => {\n await this.options.handler();\n this.called += 1;\n }, this.options.duration);\n }\n}\n\n$interval[KIND] = IntervalPrimitive;\n","import { $module } from \"alepha\";\nimport { $interval } from \"./primitives/$interval.ts\";\nimport { DateTimeProvider } from \"./providers/DateTimeProvider.ts\";\n\nexport * from \"./primitives/$interval.ts\";\nexport * from \"./providers/DateTimeProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const AlephaDateTime = $module({\n name: \"alepha.datetime\",\n primitives: [$interval],\n services: [DateTimeProvider],\n});\n"],"mappings":"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"}
|
package/dist/email/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import * as
|
|
2
|
-
import { InstantiableClass, KIND, Primitive } from "alepha";
|
|
1
|
+
import * as alepha15 from "alepha";
|
|
2
|
+
import { InstantiableClass, KIND, Primitive, Static } from "alepha";
|
|
3
3
|
import * as alepha_logger0 from "alepha/logger";
|
|
4
|
+
import { FileSystemProvider } from "alepha/file";
|
|
4
5
|
import { Transporter } from "nodemailer";
|
|
5
6
|
|
|
6
7
|
//#region ../../src/email/providers/EmailProvider.d.ts
|
|
@@ -66,16 +67,26 @@ declare class EmailPrimitive extends Primitive<EmailPrimitiveOptions> {
|
|
|
66
67
|
}
|
|
67
68
|
//#endregion
|
|
68
69
|
//#region ../../src/email/providers/LocalEmailProvider.d.ts
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
directory
|
|
70
|
+
/**
|
|
71
|
+
* Local email provider configuration atom
|
|
72
|
+
*/
|
|
73
|
+
declare const localEmailOptions: alepha15.Atom<alepha15.TObject<{
|
|
74
|
+
directory: alepha15.TString;
|
|
75
|
+
}>, "alepha.email.local.options">;
|
|
76
|
+
type LocalEmailProviderOptions = Static<typeof localEmailOptions.schema>;
|
|
77
|
+
declare module "alepha" {
|
|
78
|
+
interface State {
|
|
79
|
+
[localEmailOptions.key]: LocalEmailProviderOptions;
|
|
80
|
+
}
|
|
74
81
|
}
|
|
75
82
|
declare class LocalEmailProvider implements EmailProvider {
|
|
76
83
|
protected readonly log: alepha_logger0.Logger;
|
|
77
|
-
protected readonly
|
|
78
|
-
|
|
84
|
+
protected readonly fs: FileSystemProvider;
|
|
85
|
+
protected readonly options: Readonly<{
|
|
86
|
+
directory: string;
|
|
87
|
+
}>;
|
|
88
|
+
protected get directory(): string;
|
|
89
|
+
protected onStart: alepha15.HookPrimitive<"start">;
|
|
79
90
|
send(options: EmailSendOptions): Promise<void>;
|
|
80
91
|
createEmailHtml(options: {
|
|
81
92
|
to: string;
|
|
@@ -103,42 +114,78 @@ declare class MemoryEmailProvider implements EmailProvider {
|
|
|
103
114
|
}
|
|
104
115
|
//#endregion
|
|
105
116
|
//#region ../../src/email/providers/NodemailerEmailProvider.d.ts
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
pool?: boolean;
|
|
122
|
-
maxConnections?: number;
|
|
123
|
-
maxMessages?: number;
|
|
124
|
-
rateDelta?: number;
|
|
125
|
-
rateLimit?: number;
|
|
126
|
-
};
|
|
117
|
+
/**
|
|
118
|
+
* Nodemailer connection pooling and rate limiting options
|
|
119
|
+
*/
|
|
120
|
+
declare const nodemailerEmailOptions: alepha15.Atom<alepha15.TObject<{
|
|
121
|
+
pool: alepha15.TOptional<alepha15.TBoolean>;
|
|
122
|
+
maxConnections: alepha15.TOptional<alepha15.TNumber>;
|
|
123
|
+
maxMessages: alepha15.TOptional<alepha15.TNumber>;
|
|
124
|
+
rateDelta: alepha15.TOptional<alepha15.TNumber>;
|
|
125
|
+
rateLimit: alepha15.TOptional<alepha15.TNumber>;
|
|
126
|
+
}>, "alepha.email.nodemailer.options">;
|
|
127
|
+
type NodemailerEmailProviderOptions = Static<typeof nodemailerEmailOptions.schema>;
|
|
128
|
+
declare module "alepha" {
|
|
129
|
+
interface State {
|
|
130
|
+
[nodemailerEmailOptions.key]: NodemailerEmailProviderOptions;
|
|
131
|
+
}
|
|
127
132
|
}
|
|
133
|
+
/**
|
|
134
|
+
* Email provider using Nodemailer for SMTP transport.
|
|
135
|
+
*
|
|
136
|
+
* Configuration is provided via environment variables:
|
|
137
|
+
* - EMAIL_HOST: SMTP server host
|
|
138
|
+
* - EMAIL_PORT: SMTP server port (default: 587)
|
|
139
|
+
* - EMAIL_USER: SMTP authentication username
|
|
140
|
+
* - EMAIL_PASS: SMTP authentication password
|
|
141
|
+
* - EMAIL_FROM: Default from email address
|
|
142
|
+
* - EMAIL_SECURE: Use secure connection (default: false)
|
|
143
|
+
*
|
|
144
|
+
* Advanced pooling/rate limiting options can be configured via atom:
|
|
145
|
+
* @see {@link nodemailerEmailOptions}
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```typescript
|
|
149
|
+
* // Configure via environment variables
|
|
150
|
+
* // EMAIL_HOST=smtp.example.com
|
|
151
|
+
* // EMAIL_PORT=587
|
|
152
|
+
* // EMAIL_USER=user@example.com
|
|
153
|
+
* // EMAIL_PASS=secret
|
|
154
|
+
* // EMAIL_FROM=noreply@example.com
|
|
155
|
+
*
|
|
156
|
+
* // Optionally configure pooling via atom
|
|
157
|
+
* alepha.state.set(nodemailerEmailOptions.key, {
|
|
158
|
+
* pool: true,
|
|
159
|
+
* maxConnections: 5,
|
|
160
|
+
* rateLimit: 10,
|
|
161
|
+
* });
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
128
164
|
declare class NodemailerEmailProvider implements EmailProvider {
|
|
129
165
|
protected readonly env: {
|
|
130
|
-
EMAIL_HOST
|
|
166
|
+
EMAIL_HOST?: string | undefined;
|
|
167
|
+
EMAIL_USER?: string | undefined;
|
|
168
|
+
EMAIL_PASS?: string | undefined;
|
|
169
|
+
EMAIL_FROM?: string | undefined;
|
|
131
170
|
EMAIL_PORT: number;
|
|
132
|
-
EMAIL_USER: string;
|
|
133
|
-
EMAIL_PASS: string;
|
|
134
|
-
EMAIL_FROM: string;
|
|
135
171
|
EMAIL_SECURE: boolean;
|
|
136
172
|
};
|
|
137
173
|
protected readonly log: alepha_logger0.Logger;
|
|
138
|
-
protected
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
174
|
+
protected readonly options: Readonly<{
|
|
175
|
+
pool?: boolean | undefined;
|
|
176
|
+
maxConnections?: number | undefined;
|
|
177
|
+
maxMessages?: number | undefined;
|
|
178
|
+
rateDelta?: number | undefined;
|
|
179
|
+
rateLimit?: number | undefined;
|
|
180
|
+
}>;
|
|
181
|
+
protected transporter: Transporter | null;
|
|
182
|
+
protected get host(): string;
|
|
183
|
+
protected get port(): number;
|
|
184
|
+
protected get secure(): boolean;
|
|
185
|
+
protected get user(): string | undefined;
|
|
186
|
+
protected get pass(): string | undefined;
|
|
187
|
+
protected get fromAddress(): string;
|
|
188
|
+
protected getTransporter(): Transporter;
|
|
142
189
|
send(options: EmailSendOptions): Promise<void>;
|
|
143
190
|
protected createTransporter(): Transporter;
|
|
144
191
|
/**
|
|
@@ -149,8 +196,8 @@ declare class NodemailerEmailProvider implements EmailProvider {
|
|
|
149
196
|
* Close the transporter connection.
|
|
150
197
|
*/
|
|
151
198
|
close(): void;
|
|
152
|
-
protected readonly onStart:
|
|
153
|
-
protected readonly onStop:
|
|
199
|
+
protected readonly onStart: alepha15.HookPrimitive<"start">;
|
|
200
|
+
protected readonly onStop: alepha15.HookPrimitive<"stop">;
|
|
154
201
|
}
|
|
155
202
|
//#endregion
|
|
156
203
|
//#region ../../src/email/index.d.ts
|
|
@@ -180,7 +227,7 @@ declare module "alepha" {
|
|
|
180
227
|
* @see {@link EmailProvider}
|
|
181
228
|
* @module alepha.email
|
|
182
229
|
*/
|
|
183
|
-
declare const AlephaEmail:
|
|
230
|
+
declare const AlephaEmail: alepha15.Service<alepha15.Module>;
|
|
184
231
|
//#endregion
|
|
185
|
-
export { $email, AlephaEmail, EmailError, EmailPrimitive, EmailPrimitiveOptions, EmailProvider, EmailRecord, EmailSendOptions, LocalEmailProvider, LocalEmailProviderOptions, MemoryEmailProvider, NodemailerEmailProvider, NodemailerEmailProviderOptions };
|
|
232
|
+
export { $email, AlephaEmail, EmailError, EmailPrimitive, EmailPrimitiveOptions, EmailProvider, EmailRecord, EmailSendOptions, LocalEmailProvider, LocalEmailProviderOptions, MemoryEmailProvider, NodemailerEmailProvider, NodemailerEmailProviderOptions, localEmailOptions, nodemailerEmailOptions };
|
|
186
233
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/email/providers/EmailProvider.ts","../../src/email/errors/EmailError.ts","../../src/email/primitives/$email.ts","../../src/email/providers/LocalEmailProvider.ts","../../src/email/providers/MemoryEmailProvider.ts","../../src/email/providers/NodemailerEmailProvider.ts","../../src/email/index.ts"],"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/email/providers/EmailProvider.ts","../../src/email/errors/EmailError.ts","../../src/email/primitives/$email.ts","../../src/email/providers/LocalEmailProvider.ts","../../src/email/providers/MemoryEmailProvider.ts","../../src/email/providers/NodemailerEmailProvider.ts","../../src/email/index.ts"],"mappings":";;;;;;;;;;;;uBAKsB,aAAA;;AAAtB;;;;WAMkB,IAAA,CAAK,OAAA,EAAS,gBAAA,GAAmB,OAAA;AAAA;AAAA,KAGvC,gBAAA;EACV,EAAA;EACA,OAAA;EACA,IAAA;AAAA;;;cCjBW,UAAA,SAAmB,KAAA;cAClB,OAAA,UAAiB,KAAA,GAAQ,KAAA;AAAA;;;cCW1B,MAAA;EAAA,WAAmB,qBAAA,GAAqB,cAAA;EAAA;;UAKpC,qBAAA;EACf,IAAA;EACA,QAAA,GAAW,iBAAA,CAAkB,aAAA;AAAA;;;;;;;AFL/B;;;;;;;;;;;;cE4Ba,cAAA,SAAuB,SAAA,CAAU,qBAAA;EAAA,mBACzB,QAAA,EAAQ,aAAA;EAAA,IAEhB,IAAA,CAAA;ED7CwB;;;ECoDtB,IAAA,CAAK,OAAA,EAAS,gBAAA,GAAmB,OAAA;EAAA,UAoBpC,SAAA,CAAA,GAAa,aAAA;AAAA;;;;;;cC7DZ,iBAAA,EAAiB,QAAA,CAAA,IAAA,UAAA,OAAA;aAU5B,QAAA,CAAA,OAAA;AAAA;AAAA,KAEU,yBAAA,GAA4B,MAAA,QAAc,iBAAA,CAAkB,MAAA;AAAA;EAAA,UAG5D,KAAA;IAAA,CACP,iBAAA,CAAkB,GAAA,GAAM,yBAAA;EAAA;AAAA;AAAA,cAMhB,kBAAA,YAA8B,aAAA;EAAA,mBACtB,GAAA,EADW,cAAA,CACR,MAAA;EAAA,mBACH,EAAA,EAAE,kBAAA;EAAA,mBACF,OAAA,EAAO,QAAA;;;gBAEZ,SAAA,CAAA;EAAA,UAIJ,OAAA,EANgB,QAAA,CAMT,aAAA;EAmBJ,IAAA,CAAK,OAAA,EAAS,gBAAA,GAAmB,OAAA;EAoCvC,eAAA,CAAgB,OAAA;IACrB,EAAA;IACA,OAAA;IACA,IAAA;EAAA;EA+BK,UAAA,CAAW,IAAA;AAAA;;;UChIH,WAAA;EACf,EAAA;EACA,OAAA;EACA,IAAA;EACA,MAAA,EAAQ,IAAA;AAAA;AAAA,cAGG,mBAAA,YAA+B,aAAA;EAAA,mBACvB,GAAA,EADY,cAAA,CACT,MAAA;EACf,OAAA,EAAS,WAAA;EAEH,IAAA,CAAK,OAAA,EAAS,gBAAA,GAAmB,OAAA;EJH9B;;;EAAA,IIoBL,IAAA,CAAA,GAAQ,WAAA;AAAA;;;;;;cCiBR,sBAAA,EAAsB,QAAA,CAAA,IAAA,UAAA,OAAA;2BA8BjC,QAAA,CAAA,QAAA;;;;;;KAEU,8BAAA,GAAiC,MAAA,QACpC,sBAAA,CAAuB,MAAA;AAAA;EAAA,UAIpB,KAAA;IAAA,CACP,sBAAA,CAAuB,GAAA,GAAM,8BAAA;EAAA;AAAA;;;;;;;;;;;AJtFlC;;;;;;;;;;;;;;ACYA;;;;;;;cG+Ga,uBAAA,YAAmC,aAAA;EAAA,mBAC3B,GAAA;;;;;;;;qBACA,GAAA,EAFgB,cAAA,CAEb,MAAA;EAAA,mBACH,OAAA,EAAO,QAAA;;;;;;;YAChB,WAAA,EAAa,WAAA;EAAA,cAET,IAAA,CAAA;EAAA,cAUA,IAAA,CAAA;EAAA,cAIA,MAAA,CAAA;EAAA,cAIA,IAAA,CAAA;EAAA,cAIA,IAAA,CAAA;EAAA,cAIA,WAAA,CAAA;EAAA,UAUJ,cAAA,CAAA,GAAkB,WAAA;EAOf,IAAA,CAAK,OAAA,EAAS,gBAAA,GAAmB,OAAA;EAAA,UAyBpC,iBAAA,CAAA,GAAqB,WAAA;EH3JG;;;EG4LrB,MAAA,CAAA,GAAU,OAAA;EH5LqB;;;EG0MrC,KAAA,CAAA;EAAA,mBAOY,OAAA,EArBW,QAAA,CAqBJ,aAAA;EAAA,mBAKP,MAAA,EALO,QAAA,CAKD,aAAA;AAAA;;;;YC7Of,KAAA;IACR,eAAA;MACE,EAAA;MACA,QAAA;MACA,SAAA,EAAW,MAAA;MACX,QAAA,EAAU,aAAA;MACV,KAAA;IAAA;IAEF,YAAA;MACE,EAAA;MACA,QAAA;MACA,QAAA,EAAU,aAAA;IAAA;EAAA;AAAA;;;;;;;AL9BhB;;;;cK+Ca,WAAA,EAAW,QAAA,CAAA,OAAA,CAsCtB,QAAA,CAtCsB,MAAA"}
|
package/dist/email/index.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { $env, $hook, $module, KIND, Primitive, createPrimitive, t } from "alepha";
|
|
1
|
+
import { $atom, $env, $hook, $inject, $module, $use, KIND, Primitive, createPrimitive, t } from "alepha";
|
|
2
2
|
import { $logger } from "alepha/logger";
|
|
3
|
-
import
|
|
4
|
-
import * as path from "node:path";
|
|
3
|
+
import { FileSystemProvider } from "alepha/file";
|
|
5
4
|
import nodemailer from "nodemailer";
|
|
6
5
|
|
|
7
6
|
//#region ../../src/email/providers/EmailProvider.ts
|
|
@@ -104,12 +103,34 @@ var EmailError = class extends Error {
|
|
|
104
103
|
|
|
105
104
|
//#endregion
|
|
106
105
|
//#region ../../src/email/providers/LocalEmailProvider.ts
|
|
106
|
+
/**
|
|
107
|
+
* Local email provider configuration atom
|
|
108
|
+
*/
|
|
109
|
+
const localEmailOptions = $atom({
|
|
110
|
+
name: "alepha.email.local.options",
|
|
111
|
+
schema: t.object({ directory: t.string({ description: "Directory path where email files will be stored" }) }),
|
|
112
|
+
default: { directory: "node_modules/.alepha/emails" }
|
|
113
|
+
});
|
|
107
114
|
var LocalEmailProvider = class {
|
|
108
115
|
log = $logger();
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
116
|
+
fs = $inject(FileSystemProvider);
|
|
117
|
+
options = $use(localEmailOptions);
|
|
118
|
+
get directory() {
|
|
119
|
+
return this.options.directory;
|
|
112
120
|
}
|
|
121
|
+
onStart = $hook({
|
|
122
|
+
on: "start",
|
|
123
|
+
handler: async () => {
|
|
124
|
+
try {
|
|
125
|
+
await this.fs.mkdir(this.directory, { recursive: true });
|
|
126
|
+
this.log.info("Email directory OK", { directory: this.directory });
|
|
127
|
+
} catch (error) {
|
|
128
|
+
const message = `Failed to create email directory: ${error instanceof Error ? error.message : String(error)}`;
|
|
129
|
+
this.log.error(message, { directory: this.directory });
|
|
130
|
+
throw new EmailError(message, error instanceof Error ? error : void 0);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
});
|
|
113
134
|
async send(options) {
|
|
114
135
|
const { to, subject, body } = options;
|
|
115
136
|
this.log.debug("Sending email to local file", {
|
|
@@ -118,17 +139,16 @@ var LocalEmailProvider = class {
|
|
|
118
139
|
directory: this.directory
|
|
119
140
|
});
|
|
120
141
|
try {
|
|
121
|
-
await fs.mkdir(this.directory, { recursive: true });
|
|
122
142
|
const timestamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
123
143
|
for (const recipient of Array.isArray(to) ? to : [to]) {
|
|
124
144
|
const filename = `${recipient.replace(/[^a-zA-Z0-9@.-]/g, "_")}+${timestamp}.html`;
|
|
125
|
-
const filepath =
|
|
145
|
+
const filepath = this.fs.join(this.directory, filename);
|
|
126
146
|
const htmlContent = this.createEmailHtml({
|
|
127
147
|
to: recipient,
|
|
128
148
|
subject,
|
|
129
149
|
body
|
|
130
150
|
});
|
|
131
|
-
await fs.writeFile(filepath, htmlContent
|
|
151
|
+
await this.fs.writeFile(filepath, htmlContent);
|
|
132
152
|
this.log.info("Email saved to local file", {
|
|
133
153
|
filepath,
|
|
134
154
|
to,
|
|
@@ -180,29 +200,98 @@ var LocalEmailProvider = class {
|
|
|
180
200
|
|
|
181
201
|
//#endregion
|
|
182
202
|
//#region ../../src/email/providers/NodemailerEmailProvider.ts
|
|
203
|
+
/**
|
|
204
|
+
* Environment variables for nodemailer configuration
|
|
205
|
+
*/
|
|
183
206
|
const envSchema = t.object({
|
|
184
|
-
EMAIL_HOST: t.text({ description: "SMTP server host" }),
|
|
207
|
+
EMAIL_HOST: t.optional(t.text({ description: "SMTP server host" })),
|
|
185
208
|
EMAIL_PORT: t.number({
|
|
186
209
|
default: 587,
|
|
187
210
|
description: "SMTP server port"
|
|
188
211
|
}),
|
|
189
|
-
EMAIL_USER: t.text({ description: "SMTP authentication username" }),
|
|
190
|
-
EMAIL_PASS: t.text({ description: "SMTP authentication password" }),
|
|
191
|
-
EMAIL_FROM: t.text({ description: "Default from email address" }),
|
|
212
|
+
EMAIL_USER: t.optional(t.text({ description: "SMTP authentication username" })),
|
|
213
|
+
EMAIL_PASS: t.optional(t.text({ description: "SMTP authentication password" })),
|
|
214
|
+
EMAIL_FROM: t.optional(t.text({ description: "Default from email address" })),
|
|
192
215
|
EMAIL_SECURE: t.boolean({
|
|
193
216
|
default: false,
|
|
194
217
|
description: "Use secure connection (TLS)"
|
|
195
218
|
})
|
|
196
219
|
});
|
|
220
|
+
/**
|
|
221
|
+
* Nodemailer connection pooling and rate limiting options
|
|
222
|
+
*/
|
|
223
|
+
const nodemailerEmailOptions = $atom({
|
|
224
|
+
name: "alepha.email.nodemailer.options",
|
|
225
|
+
schema: t.object({
|
|
226
|
+
pool: t.optional(t.boolean({ description: "Enable connection pooling" })),
|
|
227
|
+
maxConnections: t.optional(t.number({ description: "Maximum number of connections in pool" })),
|
|
228
|
+
maxMessages: t.optional(t.number({ description: "Maximum messages per connection" })),
|
|
229
|
+
rateDelta: t.optional(t.number({ description: "Time in milliseconds between message sends" })),
|
|
230
|
+
rateLimit: t.optional(t.number({ description: "Maximum number of messages per rateDelta" }))
|
|
231
|
+
}),
|
|
232
|
+
default: {}
|
|
233
|
+
});
|
|
234
|
+
/**
|
|
235
|
+
* Email provider using Nodemailer for SMTP transport.
|
|
236
|
+
*
|
|
237
|
+
* Configuration is provided via environment variables:
|
|
238
|
+
* - EMAIL_HOST: SMTP server host
|
|
239
|
+
* - EMAIL_PORT: SMTP server port (default: 587)
|
|
240
|
+
* - EMAIL_USER: SMTP authentication username
|
|
241
|
+
* - EMAIL_PASS: SMTP authentication password
|
|
242
|
+
* - EMAIL_FROM: Default from email address
|
|
243
|
+
* - EMAIL_SECURE: Use secure connection (default: false)
|
|
244
|
+
*
|
|
245
|
+
* Advanced pooling/rate limiting options can be configured via atom:
|
|
246
|
+
* @see {@link nodemailerEmailOptions}
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```typescript
|
|
250
|
+
* // Configure via environment variables
|
|
251
|
+
* // EMAIL_HOST=smtp.example.com
|
|
252
|
+
* // EMAIL_PORT=587
|
|
253
|
+
* // EMAIL_USER=user@example.com
|
|
254
|
+
* // EMAIL_PASS=secret
|
|
255
|
+
* // EMAIL_FROM=noreply@example.com
|
|
256
|
+
*
|
|
257
|
+
* // Optionally configure pooling via atom
|
|
258
|
+
* alepha.state.set(nodemailerEmailOptions.key, {
|
|
259
|
+
* pool: true,
|
|
260
|
+
* maxConnections: 5,
|
|
261
|
+
* rateLimit: 10,
|
|
262
|
+
* });
|
|
263
|
+
* ```
|
|
264
|
+
*/
|
|
197
265
|
var NodemailerEmailProvider = class {
|
|
198
266
|
env = $env(envSchema);
|
|
199
267
|
log = $logger();
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
268
|
+
options = $use(nodemailerEmailOptions);
|
|
269
|
+
transporter = null;
|
|
270
|
+
get host() {
|
|
271
|
+
const host = this.env.EMAIL_HOST;
|
|
272
|
+
if (!host) throw new EmailError("Email host not configured. Set EMAIL_HOST env var.");
|
|
273
|
+
return host;
|
|
274
|
+
}
|
|
275
|
+
get port() {
|
|
276
|
+
return this.env.EMAIL_PORT;
|
|
277
|
+
}
|
|
278
|
+
get secure() {
|
|
279
|
+
return this.env.EMAIL_SECURE;
|
|
280
|
+
}
|
|
281
|
+
get user() {
|
|
282
|
+
return this.env.EMAIL_USER;
|
|
283
|
+
}
|
|
284
|
+
get pass() {
|
|
285
|
+
return this.env.EMAIL_PASS;
|
|
286
|
+
}
|
|
287
|
+
get fromAddress() {
|
|
288
|
+
const from = this.env.EMAIL_FROM;
|
|
289
|
+
if (!from) throw new EmailError("Email from address not configured. Set EMAIL_FROM env var.");
|
|
290
|
+
return from;
|
|
291
|
+
}
|
|
292
|
+
getTransporter() {
|
|
293
|
+
if (!this.transporter) this.transporter = this.createTransporter();
|
|
294
|
+
return this.transporter;
|
|
206
295
|
}
|
|
207
296
|
async send(options) {
|
|
208
297
|
const { to, subject, body } = options;
|
|
@@ -211,7 +300,7 @@ var NodemailerEmailProvider = class {
|
|
|
211
300
|
subject
|
|
212
301
|
});
|
|
213
302
|
try {
|
|
214
|
-
const result = await this.
|
|
303
|
+
const result = await this.getTransporter().sendMail({
|
|
215
304
|
from: this.fromAddress,
|
|
216
305
|
to,
|
|
217
306
|
subject,
|
|
@@ -233,22 +322,26 @@ var NodemailerEmailProvider = class {
|
|
|
233
322
|
}
|
|
234
323
|
}
|
|
235
324
|
createTransporter() {
|
|
236
|
-
if (this.options.transporter) return this.options.transporter;
|
|
237
325
|
const transporterConfig = {
|
|
238
|
-
host: this.
|
|
239
|
-
port: this.
|
|
240
|
-
secure: this.
|
|
241
|
-
auth: {
|
|
242
|
-
user: this.
|
|
243
|
-
pass: this.
|
|
244
|
-
},
|
|
245
|
-
|
|
326
|
+
host: this.host,
|
|
327
|
+
port: this.port,
|
|
328
|
+
secure: this.secure,
|
|
329
|
+
auth: this.user && this.pass ? {
|
|
330
|
+
user: this.user,
|
|
331
|
+
pass: this.pass
|
|
332
|
+
} : void 0,
|
|
333
|
+
pool: this.options.pool,
|
|
334
|
+
maxConnections: this.options.maxConnections,
|
|
335
|
+
maxMessages: this.options.maxMessages,
|
|
336
|
+
rateDelta: this.options.rateDelta,
|
|
337
|
+
rateLimit: this.options.rateLimit
|
|
246
338
|
};
|
|
247
339
|
this.log.debug("Creating Nodemailer transporter", {
|
|
248
340
|
host: transporterConfig.host,
|
|
249
341
|
port: transporterConfig.port,
|
|
250
342
|
secure: transporterConfig.secure,
|
|
251
|
-
user: transporterConfig.auth
|
|
343
|
+
user: transporterConfig.auth?.user,
|
|
344
|
+
pool: transporterConfig.pool
|
|
252
345
|
});
|
|
253
346
|
return nodemailer.createTransport(transporterConfig);
|
|
254
347
|
}
|
|
@@ -257,7 +350,7 @@ var NodemailerEmailProvider = class {
|
|
|
257
350
|
*/
|
|
258
351
|
async verify() {
|
|
259
352
|
try {
|
|
260
|
-
await this.
|
|
353
|
+
await this.getTransporter().verify();
|
|
261
354
|
this.log.info("Email server connection verified");
|
|
262
355
|
return true;
|
|
263
356
|
} catch (error) {
|
|
@@ -269,7 +362,10 @@ var NodemailerEmailProvider = class {
|
|
|
269
362
|
* Close the transporter connection.
|
|
270
363
|
*/
|
|
271
364
|
close() {
|
|
272
|
-
this.transporter
|
|
365
|
+
if (this.transporter) {
|
|
366
|
+
this.transporter.close();
|
|
367
|
+
this.transporter = null;
|
|
368
|
+
}
|
|
273
369
|
}
|
|
274
370
|
onStart = $hook({
|
|
275
371
|
on: "start",
|
|
@@ -327,5 +423,5 @@ const AlephaEmail = $module({
|
|
|
327
423
|
});
|
|
328
424
|
|
|
329
425
|
//#endregion
|
|
330
|
-
export { $email, AlephaEmail, EmailError, EmailPrimitive, EmailProvider, LocalEmailProvider, MemoryEmailProvider, NodemailerEmailProvider };
|
|
426
|
+
export { $email, AlephaEmail, EmailError, EmailPrimitive, EmailProvider, LocalEmailProvider, MemoryEmailProvider, NodemailerEmailProvider, localEmailOptions, nodemailerEmailOptions };
|
|
331
427
|
//# sourceMappingURL=index.js.map
|