alepha 0.14.3 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -5
- package/dist/api/audits/index.d.ts +620 -811
- package/dist/api/audits/index.d.ts.map +1 -1
- package/dist/api/files/index.d.ts +185 -377
- package/dist/api/files/index.d.ts.map +1 -1
- package/dist/api/files/index.js +0 -1
- package/dist/api/files/index.js.map +1 -1
- package/dist/api/jobs/index.d.ts +245 -435
- package/dist/api/jobs/index.d.ts.map +1 -1
- package/dist/api/notifications/index.d.ts +238 -429
- package/dist/api/notifications/index.d.ts.map +1 -1
- package/dist/api/parameters/index.d.ts +236 -427
- 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 +1010 -1196
- package/dist/api/users/index.d.ts.map +1 -1
- package/dist/api/users/index.js +178 -151
- package/dist/api/users/index.js.map +1 -1
- package/dist/api/verifications/index.d.ts +17 -17
- package/dist/api/verifications/index.d.ts.map +1 -1
- package/dist/batch/index.d.ts +122 -122
- 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 +163 -163
- package/dist/bucket/index.d.ts.map +1 -1
- package/dist/cache/core/index.d.ts +46 -46
- package/dist/cache/core/index.d.ts.map +1 -1
- package/dist/cache/redis/index.d.ts.map +1 -1
- package/dist/cli/index.d.ts +384 -285
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +1113 -623
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +299 -300
- package/dist/command/index.d.ts.map +1 -1
- package/dist/command/index.js +13 -9
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +445 -103
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +733 -625
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +446 -103
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +445 -103
- package/dist/core/index.native.js.map +1 -1
- package/dist/datetime/index.d.ts +44 -44
- 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 +97 -50
- 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 +7981 -14
- package/dist/fake/index.d.ts.map +1 -1
- package/dist/file/index.d.ts +523 -390
- 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 +208 -208
- 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 +25 -26
- package/dist/logger/index.d.ts.map +1 -1
- package/dist/logger/index.js +12 -2
- package/dist/logger/index.js.map +1 -1
- package/dist/mcp/index.d.ts +197 -197
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +1 -1
- package/dist/mcp/index.js.map +1 -1
- package/dist/orm/chunk-DtkW-qnP.js +38 -0
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.bun.js +2814 -0
- package/dist/orm/index.bun.js.map +1 -0
- package/dist/orm/index.d.ts +1228 -1216
- package/dist/orm/index.d.ts.map +1 -1
- package/dist/orm/index.js +2041 -1967
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/core/index.d.ts +248 -248
- 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 +118 -136
- 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 +69 -69
- package/dist/retry/index.d.ts.map +1 -1
- package/dist/router/index.d.ts +6 -6
- package/dist/router/index.d.ts.map +1 -1
- package/dist/scheduler/index.d.ts +25 -25
- package/dist/scheduler/index.d.ts.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 +417 -254
- package/dist/security/index.d.ts.map +1 -1
- package/dist/security/index.js +386 -86
- package/dist/security/index.js.map +1 -1
- package/dist/server/auth/index.d.ts +110 -110
- package/dist/server/auth/index.d.ts.map +1 -1
- package/dist/server/auth/index.js +20 -20
- package/dist/server/auth/index.js.map +1 -1
- package/dist/server/cache/index.d.ts +62 -47
- package/dist/server/cache/index.d.ts.map +1 -1
- package/dist/server/cache/index.js +56 -3
- package/dist/server/cache/index.js.map +1 -1
- package/dist/server/compress/index.d.ts +6 -0
- package/dist/server/compress/index.d.ts.map +1 -1
- package/dist/server/compress/index.js +36 -1
- package/dist/server/compress/index.js.map +1 -1
- package/dist/server/cookies/index.d.ts +6 -6
- 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.browser.js +2 -2
- package/dist/server/core/index.browser.js.map +1 -1
- package/dist/server/core/index.d.ts +242 -150
- package/dist/server/core/index.d.ts.map +1 -1
- package/dist/server/core/index.js +294 -125
- package/dist/server/core/index.js.map +1 -1
- package/dist/server/cors/index.d.ts +11 -12
- 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 +2 -2
- package/dist/server/helmet/index.d.ts.map +1 -1
- package/dist/server/links/index.browser.js.map +1 -1
- package/dist/server/links/index.d.ts +123 -124
- package/dist/server/links/index.d.ts.map +1 -1
- package/dist/server/links/index.js +1 -2
- package/dist/server/links/index.js.map +1 -1
- package/dist/server/metrics/index.d.ts.map +1 -1
- package/dist/server/multipart/index.d.ts +6 -6
- package/dist/server/multipart/index.d.ts.map +1 -1
- package/dist/server/proxy/index.d.ts +102 -103
- package/dist/server/proxy/index.d.ts.map +1 -1
- package/dist/server/rate-limit/index.d.ts +16 -16
- package/dist/server/rate-limit/index.d.ts.map +1 -1
- package/dist/server/static/index.d.ts +44 -44
- package/dist/server/static/index.d.ts.map +1 -1
- package/dist/server/static/index.js +4 -0
- package/dist/server/static/index.js.map +1 -1
- package/dist/server/swagger/index.d.ts +48 -49
- package/dist/server/swagger/index.d.ts.map +1 -1
- package/dist/server/swagger/index.js +3 -5
- package/dist/server/swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +13 -11
- package/dist/sms/index.d.ts.map +1 -1
- package/dist/sms/index.js +7 -7
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +71 -72
- package/dist/thread/index.d.ts.map +1 -1
- package/dist/topic/core/index.d.ts +318 -318
- package/dist/topic/core/index.d.ts.map +1 -1
- package/dist/topic/redis/index.d.ts +6 -6
- package/dist/topic/redis/index.d.ts.map +1 -1
- package/dist/vite/index.d.ts +5805 -249
- package/dist/vite/index.d.ts.map +1 -1
- package/dist/vite/index.js +599 -513
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +6 -6
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +247 -247
- package/dist/websocket/index.d.ts.map +1 -1
- package/dist/websocket/index.js +6 -6
- package/dist/websocket/index.js.map +1 -1
- package/package.json +9 -14
- 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 +28 -9
- package/src/api/users/services/UserService.ts +7 -7
- package/src/batch/providers/BatchProvider.ts +1 -2
- package/src/cli/apps/AlephaCli.ts +0 -2
- package/src/cli/apps/AlephaPackageBuilderCli.ts +38 -19
- package/src/cli/assets/apiHelloControllerTs.ts +18 -0
- package/src/cli/assets/apiIndexTs.ts +16 -0
- package/src/cli/assets/claudeMd.ts +303 -0
- package/src/cli/assets/mainBrowserTs.ts +2 -2
- package/src/cli/assets/mainServerTs.ts +24 -0
- package/src/cli/assets/webAppRouterTs.ts +15 -0
- package/src/cli/assets/webHelloComponentTsx.ts +16 -0
- package/src/cli/assets/webIndexTs.ts +16 -0
- package/src/cli/atoms/buildOptions.ts +88 -0
- package/src/cli/commands/build.ts +70 -87
- package/src/cli/commands/db.ts +21 -22
- package/src/cli/commands/deploy.ts +17 -5
- package/src/cli/commands/dev.ts +22 -14
- package/src/cli/commands/format.ts +8 -2
- package/src/cli/commands/gen/env.ts +53 -0
- package/src/cli/commands/gen/openapi.ts +1 -1
- package/src/cli/commands/gen/resource.ts +15 -0
- package/src/cli/commands/gen.ts +7 -1
- package/src/cli/commands/init.ts +74 -30
- package/src/cli/commands/lint.ts +8 -2
- package/src/cli/commands/test.ts +8 -3
- package/src/cli/commands/typecheck.ts +5 -1
- package/src/cli/commands/verify.ts +5 -3
- package/src/cli/defineConfig.ts +49 -7
- package/src/cli/index.ts +0 -1
- package/src/cli/services/AlephaCliUtils.ts +39 -589
- package/src/cli/services/PackageManagerUtils.ts +301 -0
- package/src/cli/services/ProjectScaffolder.ts +306 -0
- package/src/command/helpers/Runner.spec.ts +2 -2
- package/src/command/helpers/Runner.ts +16 -4
- package/src/command/primitives/$command.ts +0 -6
- package/src/command/providers/CliProvider.ts +1 -3
- package/src/core/Alepha.ts +42 -0
- 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/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 +621 -0
- package/src/core/providers/KeylessJsonSchemaCodec.ts +407 -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/index.ts +15 -3
- package/src/mcp/transports/StdioMcpTransport.ts +1 -1
- 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 +13 -39
- 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 +8 -0
- package/src/queue/core/providers/WorkerProvider.spec.ts +48 -32
- 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.spec.ts +183 -0
- package/src/server/cache/providers/ServerCacheProvider.ts +95 -10
- package/src/server/compress/providers/ServerCompressProvider.ts +61 -2
- package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -3
- package/src/server/core/helpers/ServerReply.ts +2 -2
- package/src/server/core/providers/NodeHttpServerProvider.ts +25 -6
- 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 +155 -22
- package/src/server/core/providers/ServerRouterProvider.ts +259 -115
- package/src/server/core/providers/ServerTimingProvider.ts +2 -2
- package/src/server/links/index.ts +1 -1
- package/src/server/links/providers/LinkProvider.ts +1 -1
- package/src/server/static/providers/ServerStaticProvider.ts +10 -0
- package/src/server/swagger/index.ts +1 -1
- package/src/server/swagger/providers/ServerSwaggerProvider.ts +5 -8
- package/src/sms/providers/LocalSmsProvider.spec.ts +153 -111
- package/src/sms/providers/LocalSmsProvider.ts +8 -7
- package/src/vite/helpers/boot.ts +28 -17
- package/src/vite/helpers/importViteReact.ts +13 -0
- package/src/vite/index.ts +1 -21
- package/src/vite/plugins/viteAlephaDev.ts +16 -1
- package/src/vite/plugins/viteAlephaSsrPreload.ts +222 -0
- package/src/vite/tasks/buildClient.ts +11 -0
- package/src/vite/tasks/buildServer.ts +59 -4
- package/src/vite/tasks/devServer.ts +71 -0
- package/src/vite/tasks/generateCloudflare.ts +7 -0
- package/src/vite/tasks/index.ts +2 -1
- 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/mainTs.ts +0 -13
- package/src/cli/assets/viteConfigTs.ts +0 -14
- package/src/cli/commands/run.ts +0 -24
- package/src/server/security/index.browser.ts +0 -10
- package/src/server/security/index.ts +0 -94
- package/src/vite/plugins/viteAlepha.ts +0 -37
- package/src/vite/plugins/viteAlephaBuild.ts +0 -281
- /package/src/{server/security → security}/primitives/$basicAuth.ts +0 -0
- /package/src/{server/security → security}/providers/ServerBasicAuthProvider.ts +0 -0
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
|
package/dist/email/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../src/email/providers/EmailProvider.ts","../../src/email/providers/MemoryEmailProvider.ts","../../src/email/primitives/$email.ts","../../src/email/errors/EmailError.ts","../../src/email/providers/LocalEmailProvider.ts","../../src/email/providers/NodemailerEmailProvider.ts","../../src/email/index.ts"],"sourcesContent":["/**\n * Email provider interface.\n *\n * All methods are asynchronous and return promises.\n */\nexport abstract class EmailProvider {\n /**\n * Send an email.\n *\n * @return Promise that resolves when the email is sent.\n */\n public abstract send(options: EmailSendOptions): Promise<void>;\n}\n\nexport type EmailSendOptions = {\n to: string | string[];\n subject: string;\n body: string;\n};\n","import { $logger } from \"alepha/logger\";\nimport type { EmailProvider, EmailSendOptions } from \"./EmailProvider.ts\";\n\nexport interface EmailRecord {\n to: string;\n subject: string;\n body: string;\n sentAt: Date;\n}\n\nexport class MemoryEmailProvider implements EmailProvider {\n protected readonly log = $logger();\n public records: EmailRecord[] = [];\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n this.log.debug(\"Sending email to memory store\", { to, subject });\n\n for (const recipient of Array.isArray(to) ? to : [to]) {\n this.records.push({\n to: recipient,\n subject,\n body,\n sentAt: new Date(),\n });\n }\n }\n\n /**\n * Get the last email sent (for testing purposes).\n */\n public get last(): EmailRecord | undefined {\n return this.records[this.records.length - 1];\n }\n}\n","import {\n createPrimitive,\n type InstantiableClass,\n KIND,\n Primitive,\n} from \"alepha\";\nimport type { EmailSendOptions } from \"../providers/EmailProvider.ts\";\nimport { EmailProvider } from \"../providers/EmailProvider.ts\";\nimport { MemoryEmailProvider } from \"../providers/MemoryEmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const $email = (options: EmailPrimitiveOptions = {}) =>\n createPrimitive(EmailPrimitive, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface EmailPrimitiveOptions {\n name?: string;\n provider?: InstantiableClass<EmailProvider> | \"memory\";\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Email primitive for sending emails through various providers.\n *\n * Usage:\n * ```typescript\n * class MyService {\n * private readonly welcomeEmail = $email({ name: \"welcome\" });\n *\n * async sendWelcome(userEmail: string, userName: string) {\n * await this.welcomeEmail.send({\n * to: userEmail,\n * subject: \"Welcome!\",\n * body: `<p>Hello ${userName}!</p>`\n * });\n * }\n * }\n * ```\n */\nexport class EmailPrimitive extends Primitive<EmailPrimitiveOptions> {\n protected readonly provider = this.$provider();\n\n public get name() {\n return this.options.name ?? `${this.config.propertyKey}`;\n }\n\n /**\n * Send an email using the configured provider.\n */\n public async send(options: EmailSendOptions): Promise<void> {\n await this.alepha.events.emit(\"email:sending\", {\n to: options.to,\n template: this.name,\n variables: {},\n provider: this.provider,\n abort: () => {\n throw new Error(\"Email sending aborted by hook\");\n },\n });\n\n await this.provider.send(options);\n\n await this.alepha.events.emit(\"email:sent\", {\n to: options.to,\n template: this.name,\n provider: this.provider,\n });\n }\n\n protected $provider(): EmailProvider {\n if (!this.options.provider) {\n return this.alepha.inject(EmailProvider);\n }\n if (this.options.provider === \"memory\") {\n return this.alepha.inject(MemoryEmailProvider);\n }\n return this.alepha.inject(this.options.provider);\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n$email[KIND] = EmailPrimitive;\n","export class EmailError extends Error {\n constructor(message: string, cause?: Error) {\n super(message);\n this.name = \"EmailError\";\n this.cause = cause;\n }\n}\n","import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\nimport { $logger } from \"alepha/logger\";\nimport { EmailError } from \"../errors/EmailError.ts\";\nimport type { EmailProvider, EmailSendOptions } from \"./EmailProvider.ts\";\n\nexport interface LocalEmailProviderOptions {\n /**\n * Directory to save email files.\n */\n directory?: string;\n}\n\nexport class LocalEmailProvider implements EmailProvider {\n protected readonly log = $logger();\n protected readonly directory: string;\n\n constructor(options: LocalEmailProviderOptions = {}) {\n this.directory = options.directory ?? \"node_modules/.alepha/emails\";\n }\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n\n this.log.debug(\"Sending email to local file\", {\n to,\n subject,\n directory: this.directory,\n });\n\n try {\n // Ensure directory exists\n await fs.mkdir(this.directory, { recursive: true });\n\n // Create filename: emailcontact+date\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n for (const recipient of Array.isArray(to) ? to : [to]) {\n const sanitizedEmail = recipient.replace(/[^a-zA-Z0-9@.-]/g, \"_\");\n const filename = `${sanitizedEmail}+${timestamp}.html`;\n const filepath = path.join(this.directory, filename);\n\n // Create HTML content\n const htmlContent = this.createEmailHtml({\n to: recipient,\n subject,\n body,\n });\n\n // Write to file\n await fs.writeFile(filepath, htmlContent, \"utf8\");\n\n this.log.info(\"Email saved to local file\", { filepath, to, subject });\n }\n } catch (error) {\n const message = `Failed to save email to local file: ${error instanceof Error ? error.message : String(error)}`;\n this.log.error(message, { to, subject, directory: this.directory });\n throw new EmailError(message, error instanceof Error ? error : undefined);\n }\n }\n\n public createEmailHtml(options: {\n to: string;\n subject: string;\n body: string;\n }): string {\n const { to, subject, body } = options;\n const timestamp = new Date().toISOString();\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.escapeHtml(subject)}</title>\n <style>\n body { font-family: Arial, sans-serif; margin: 20px; }\n .email-header { background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin-bottom: 20px; }\n .email-body { background-color: #ffffff; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }\n .meta { font-size: 12px; color: #666; margin-bottom: 10px; }\n </style>\n</head>\n<body>\n <div class=\"email-header\">\n <div class=\"meta\">Sent: ${timestamp}</div>\n <div class=\"meta\">To: ${this.escapeHtml(to)}</div>\n <h1>${this.escapeHtml(subject)}</h1>\n </div>\n <div class=\"email-body\">\n ${body}\n </div>\n</body>\n</html>`;\n }\n\n public escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n }\n}\n","import { $env, $hook, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { Transporter } from \"nodemailer\";\nimport nodemailer from \"nodemailer\";\nimport { EmailError } from \"../errors/EmailError.ts\";\nimport type { EmailProvider, EmailSendOptions } from \"./EmailProvider.ts\";\n\nconst envSchema = t.object({\n EMAIL_HOST: t.text({\n description: \"SMTP server host\",\n }),\n EMAIL_PORT: t.number({\n default: 587,\n description: \"SMTP server port\",\n }),\n EMAIL_USER: t.text({\n description: \"SMTP authentication username\",\n }),\n EMAIL_PASS: t.text({\n description: \"SMTP authentication password\",\n }),\n EMAIL_FROM: t.text({\n description: \"Default from email address\",\n }),\n EMAIL_SECURE: t.boolean({\n default: false,\n description: \"Use secure connection (TLS)\",\n }),\n});\n\nexport interface NodemailerEmailProviderOptions {\n /**\n * Custom transporter configuration.\n * If provided, will override environment variables.\n */\n transporter?: Transporter;\n\n /**\n * Custom from email address.\n * If not provided, will use EMAIL_FROM from environment.\n */\n from?: string;\n\n /**\n * Additional nodemailer options.\n */\n options?: {\n pool?: boolean;\n maxConnections?: number;\n maxMessages?: number;\n rateDelta?: number;\n rateLimit?: number;\n };\n}\n\nexport class NodemailerEmailProvider implements EmailProvider {\n protected readonly env = $env(envSchema);\n protected readonly log = $logger();\n protected transporter: Transporter;\n protected fromAddress: string;\n\n public readonly options: NodemailerEmailProviderOptions = {};\n\n constructor() {\n this.fromAddress = this.options.from ?? this.env.EMAIL_FROM;\n this.transporter = this.createTransporter();\n }\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n this.log.debug(\"Sending email via Nodemailer\", { to, subject });\n\n try {\n const result = await this.transporter.sendMail({\n from: this.fromAddress,\n to,\n subject,\n html: body,\n });\n\n this.log.info(\"Email sent successfully\", {\n to,\n subject,\n messageId: result.messageId,\n response: result.response,\n });\n } catch (error) {\n const message = `Failed to send email via Nodemailer: ${error instanceof Error ? error.message : String(error)}`;\n this.log.error(message, { to, subject });\n throw new EmailError(message, error instanceof Error ? error : undefined);\n }\n }\n\n protected createTransporter(): Transporter {\n if (this.options.transporter) {\n return this.options.transporter;\n }\n\n const transporterConfig = {\n host: this.env.EMAIL_HOST,\n port: this.env.EMAIL_PORT,\n secure: this.env.EMAIL_SECURE,\n auth: {\n user: this.env.EMAIL_USER,\n pass: this.env.EMAIL_PASS,\n },\n ...this.options.options,\n };\n\n this.log.debug(\"Creating Nodemailer transporter\", {\n host: transporterConfig.host,\n port: transporterConfig.port,\n secure: transporterConfig.secure,\n user: transporterConfig.auth.user,\n });\n\n return nodemailer.createTransport(transporterConfig);\n }\n\n /**\n * Verify the connection to the email server.\n */\n public async verify(): Promise<boolean> {\n try {\n await this.transporter.verify();\n this.log.info(\"Email server connection verified\");\n return true;\n } catch (error) {\n this.log.error(\"Email server connection failed\", { error });\n return false;\n }\n }\n\n /**\n * Close the transporter connection.\n */\n public close(): void {\n this.transporter.close();\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: () => this.verify(),\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n}\n","import { $module } from \"alepha\";\nimport { $email } from \"./primitives/$email.ts\";\nimport { EmailProvider } from \"./providers/EmailProvider.ts\";\nimport { LocalEmailProvider } from \"./providers/LocalEmailProvider.ts\";\nimport { MemoryEmailProvider } from \"./providers/MemoryEmailProvider.ts\";\nimport { NodemailerEmailProvider } from \"./providers/NodemailerEmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./errors/EmailError.ts\";\nexport * from \"./primitives/$email.ts\";\nexport * from \"./providers/EmailProvider.ts\";\nexport * from \"./providers/LocalEmailProvider.ts\";\nexport * from \"./providers/MemoryEmailProvider.ts\";\nexport * from \"./providers/NodemailerEmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n \"email:sending\": {\n to: string | string[];\n template: string;\n variables: Record<string, unknown>;\n provider: EmailProvider;\n abort(): void;\n };\n \"email:sent\": {\n to: string | string[];\n template: string;\n provider: EmailProvider;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides email sending capabilities for Alepha applications with multiple provider backends.\n *\n * The email module enables declarative email sending through the `$email` primitive, allowing you to send\n * emails through different providers: memory (for testing), local file system, or SMTP via Nodemailer.\n * It supports HTML email content and automatic provider selection based on environment configuration.\n *\n * @see {@link EmailProvider}\n * @module alepha.email\n */\nexport const AlephaEmail = $module({\n name: \"alepha.email\",\n primitives: [$email],\n services: [\n EmailProvider,\n MemoryEmailProvider,\n LocalEmailProvider,\n NodemailerEmailProvider,\n ],\n register: (alepha) => {\n if (alepha.isTest()) {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: MemoryEmailProvider,\n });\n } else if (alepha.env.EMAIL_HOST) {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: NodemailerEmailProvider,\n });\n } else {\n if (alepha.isServerless()) {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: MemoryEmailProvider,\n });\n } else {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: LocalEmailProvider,\n });\n }\n }\n },\n});\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../src/email/providers/EmailProvider.ts","../../src/email/providers/MemoryEmailProvider.ts","../../src/email/primitives/$email.ts","../../src/email/errors/EmailError.ts","../../src/email/providers/LocalEmailProvider.ts","../../src/email/providers/NodemailerEmailProvider.ts","../../src/email/index.ts"],"sourcesContent":["/**\n * Email provider interface.\n *\n * All methods are asynchronous and return promises.\n */\nexport abstract class EmailProvider {\n /**\n * Send an email.\n *\n * @return Promise that resolves when the email is sent.\n */\n public abstract send(options: EmailSendOptions): Promise<void>;\n}\n\nexport type EmailSendOptions = {\n to: string | string[];\n subject: string;\n body: string;\n};\n","import { $logger } from \"alepha/logger\";\nimport type { EmailProvider, EmailSendOptions } from \"./EmailProvider.ts\";\n\nexport interface EmailRecord {\n to: string;\n subject: string;\n body: string;\n sentAt: Date;\n}\n\nexport class MemoryEmailProvider implements EmailProvider {\n protected readonly log = $logger();\n public records: EmailRecord[] = [];\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n this.log.debug(\"Sending email to memory store\", { to, subject });\n\n for (const recipient of Array.isArray(to) ? to : [to]) {\n this.records.push({\n to: recipient,\n subject,\n body,\n sentAt: new Date(),\n });\n }\n }\n\n /**\n * Get the last email sent (for testing purposes).\n */\n public get last(): EmailRecord | undefined {\n return this.records[this.records.length - 1];\n }\n}\n","import {\n createPrimitive,\n type InstantiableClass,\n KIND,\n Primitive,\n} from \"alepha\";\nimport type { EmailSendOptions } from \"../providers/EmailProvider.ts\";\nimport { EmailProvider } from \"../providers/EmailProvider.ts\";\nimport { MemoryEmailProvider } from \"../providers/MemoryEmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport const $email = (options: EmailPrimitiveOptions = {}) =>\n createPrimitive(EmailPrimitive, options);\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface EmailPrimitiveOptions {\n name?: string;\n provider?: InstantiableClass<EmailProvider> | \"memory\";\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Email primitive for sending emails through various providers.\n *\n * Usage:\n * ```typescript\n * class MyService {\n * private readonly welcomeEmail = $email({ name: \"welcome\" });\n *\n * async sendWelcome(userEmail: string, userName: string) {\n * await this.welcomeEmail.send({\n * to: userEmail,\n * subject: \"Welcome!\",\n * body: `<p>Hello ${userName}!</p>`\n * });\n * }\n * }\n * ```\n */\nexport class EmailPrimitive extends Primitive<EmailPrimitiveOptions> {\n protected readonly provider = this.$provider();\n\n public get name() {\n return this.options.name ?? `${this.config.propertyKey}`;\n }\n\n /**\n * Send an email using the configured provider.\n */\n public async send(options: EmailSendOptions): Promise<void> {\n await this.alepha.events.emit(\"email:sending\", {\n to: options.to,\n template: this.name,\n variables: {},\n provider: this.provider,\n abort: () => {\n throw new Error(\"Email sending aborted by hook\");\n },\n });\n\n await this.provider.send(options);\n\n await this.alepha.events.emit(\"email:sent\", {\n to: options.to,\n template: this.name,\n provider: this.provider,\n });\n }\n\n protected $provider(): EmailProvider {\n if (!this.options.provider) {\n return this.alepha.inject(EmailProvider);\n }\n if (this.options.provider === \"memory\") {\n return this.alepha.inject(MemoryEmailProvider);\n }\n return this.alepha.inject(this.options.provider);\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n$email[KIND] = EmailPrimitive;\n","export class EmailError extends Error {\n constructor(message: string, cause?: Error) {\n super(message);\n this.name = \"EmailError\";\n this.cause = cause;\n }\n}\n","import { $atom, $hook, $inject, $use, type Static, t } from \"alepha\";\nimport { FileSystemProvider } from \"alepha/file\";\nimport { $logger } from \"alepha/logger\";\nimport { EmailError } from \"../errors/EmailError.ts\";\nimport type { EmailProvider, EmailSendOptions } from \"./EmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Local email provider configuration atom\n */\nexport const localEmailOptions = $atom({\n name: \"alepha.email.local.options\",\n schema: t.object({\n directory: t.string({\n description: \"Directory path where email files will be stored\",\n }),\n }),\n default: {\n directory: \"node_modules/.alepha/emails\",\n },\n});\n\nexport type LocalEmailProviderOptions = Static<typeof localEmailOptions.schema>;\n\ndeclare module \"alepha\" {\n interface State {\n [localEmailOptions.key]: LocalEmailProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class LocalEmailProvider implements EmailProvider {\n protected readonly log = $logger();\n protected readonly fs = $inject(FileSystemProvider);\n protected readonly options = $use(localEmailOptions);\n\n protected get directory(): string {\n return this.options.directory;\n }\n\n protected onStart = $hook({\n on: \"start\",\n handler: async () => {\n try {\n await this.fs.mkdir(this.directory, { recursive: true });\n this.log.info(\"Email directory OK\", {\n directory: this.directory,\n });\n } catch (error) {\n const message = `Failed to create email directory: ${error instanceof Error ? error.message : String(error)}`;\n this.log.error(message, { directory: this.directory });\n throw new EmailError(\n message,\n error instanceof Error ? error : undefined,\n );\n }\n },\n });\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n\n this.log.debug(\"Sending email to local file\", {\n to,\n subject,\n directory: this.directory,\n });\n\n try {\n // Create filename: emailcontact+date\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\n for (const recipient of Array.isArray(to) ? to : [to]) {\n const sanitizedEmail = recipient.replace(/[^a-zA-Z0-9@.-]/g, \"_\");\n const filename = `${sanitizedEmail}+${timestamp}.html`;\n const filepath = this.fs.join(this.directory, filename);\n\n // Create HTML content\n const htmlContent = this.createEmailHtml({\n to: recipient,\n subject,\n body,\n });\n\n // Write to file\n await this.fs.writeFile(filepath, htmlContent);\n\n this.log.info(\"Email saved to local file\", { filepath, to, subject });\n }\n } catch (error) {\n const message = `Failed to save email to local file: ${error instanceof Error ? error.message : String(error)}`;\n this.log.error(message, { to, subject, directory: this.directory });\n throw new EmailError(message, error instanceof Error ? error : undefined);\n }\n }\n\n public createEmailHtml(options: {\n to: string;\n subject: string;\n body: string;\n }): string {\n const { to, subject, body } = options;\n const timestamp = new Date().toISOString();\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${this.escapeHtml(subject)}</title>\n <style>\n body { font-family: Arial, sans-serif; margin: 20px; }\n .email-header { background-color: #f5f5f5; padding: 15px; border-radius: 5px; margin-bottom: 20px; }\n .email-body { background-color: #ffffff; padding: 15px; border: 1px solid #ddd; border-radius: 5px; }\n .meta { font-size: 12px; color: #666; margin-bottom: 10px; }\n </style>\n</head>\n<body>\n <div class=\"email-header\">\n <div class=\"meta\">Sent: ${timestamp}</div>\n <div class=\"meta\">To: ${this.escapeHtml(to)}</div>\n <h1>${this.escapeHtml(subject)}</h1>\n </div>\n <div class=\"email-body\">\n ${body}\n </div>\n</body>\n</html>`;\n }\n\n public escapeHtml(text: string): string {\n return text\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n }\n}\n","import { $atom, $env, $hook, $use, type Static, t } from \"alepha\";\nimport { $logger } from \"alepha/logger\";\nimport type { Transporter } from \"nodemailer\";\nimport nodemailer from \"nodemailer\";\nimport { EmailError } from \"../errors/EmailError.ts\";\nimport type { EmailProvider, EmailSendOptions } from \"./EmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Environment variables for nodemailer configuration\n */\nconst envSchema = t.object({\n EMAIL_HOST: t.optional(\n t.text({\n description: \"SMTP server host\",\n }),\n ),\n EMAIL_PORT: t.number({\n default: 587,\n description: \"SMTP server port\",\n }),\n EMAIL_USER: t.optional(\n t.text({\n description: \"SMTP authentication username\",\n }),\n ),\n EMAIL_PASS: t.optional(\n t.text({\n description: \"SMTP authentication password\",\n }),\n ),\n EMAIL_FROM: t.optional(\n t.text({\n description: \"Default from email address\",\n }),\n ),\n EMAIL_SECURE: t.boolean({\n default: false,\n description: \"Use secure connection (TLS)\",\n }),\n});\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Nodemailer connection pooling and rate limiting options\n */\nexport const nodemailerEmailOptions = $atom({\n name: \"alepha.email.nodemailer.options\",\n schema: t.object({\n pool: t.optional(\n t.boolean({\n description: \"Enable connection pooling\",\n }),\n ),\n maxConnections: t.optional(\n t.number({\n description: \"Maximum number of connections in pool\",\n }),\n ),\n maxMessages: t.optional(\n t.number({\n description: \"Maximum messages per connection\",\n }),\n ),\n rateDelta: t.optional(\n t.number({\n description: \"Time in milliseconds between message sends\",\n }),\n ),\n rateLimit: t.optional(\n t.number({\n description: \"Maximum number of messages per rateDelta\",\n }),\n ),\n }),\n default: {},\n});\n\nexport type NodemailerEmailProviderOptions = Static<\n typeof nodemailerEmailOptions.schema\n>;\n\ndeclare module \"alepha\" {\n interface State {\n [nodemailerEmailOptions.key]: NodemailerEmailProviderOptions;\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Email provider using Nodemailer for SMTP transport.\n *\n * Configuration is provided via environment variables:\n * - EMAIL_HOST: SMTP server host\n * - EMAIL_PORT: SMTP server port (default: 587)\n * - EMAIL_USER: SMTP authentication username\n * - EMAIL_PASS: SMTP authentication password\n * - EMAIL_FROM: Default from email address\n * - EMAIL_SECURE: Use secure connection (default: false)\n *\n * Advanced pooling/rate limiting options can be configured via atom:\n * @see {@link nodemailerEmailOptions}\n *\n * @example\n * ```typescript\n * // Configure via environment variables\n * // EMAIL_HOST=smtp.example.com\n * // EMAIL_PORT=587\n * // EMAIL_USER=user@example.com\n * // EMAIL_PASS=secret\n * // EMAIL_FROM=noreply@example.com\n *\n * // Optionally configure pooling via atom\n * alepha.state.set(nodemailerEmailOptions.key, {\n * pool: true,\n * maxConnections: 5,\n * rateLimit: 10,\n * });\n * ```\n */\nexport class NodemailerEmailProvider implements EmailProvider {\n protected readonly env = $env(envSchema);\n protected readonly log = $logger();\n protected readonly options = $use(nodemailerEmailOptions);\n protected transporter: Transporter | null = null;\n\n protected get host(): string {\n const host = this.env.EMAIL_HOST;\n if (!host) {\n throw new EmailError(\n \"Email host not configured. Set EMAIL_HOST env var.\",\n );\n }\n return host;\n }\n\n protected get port(): number {\n return this.env.EMAIL_PORT;\n }\n\n protected get secure(): boolean {\n return this.env.EMAIL_SECURE;\n }\n\n protected get user(): string | undefined {\n return this.env.EMAIL_USER;\n }\n\n protected get pass(): string | undefined {\n return this.env.EMAIL_PASS;\n }\n\n protected get fromAddress(): string {\n const from = this.env.EMAIL_FROM;\n if (!from) {\n throw new EmailError(\n \"Email from address not configured. Set EMAIL_FROM env var.\",\n );\n }\n return from;\n }\n\n protected getTransporter(): Transporter {\n if (!this.transporter) {\n this.transporter = this.createTransporter();\n }\n return this.transporter;\n }\n\n public async send(options: EmailSendOptions): Promise<void> {\n const { to, subject, body } = options;\n this.log.debug(\"Sending email via Nodemailer\", { to, subject });\n\n try {\n const result = await this.getTransporter().sendMail({\n from: this.fromAddress,\n to,\n subject,\n html: body,\n });\n\n this.log.info(\"Email sent successfully\", {\n to,\n subject,\n messageId: result.messageId,\n response: result.response,\n });\n } catch (error) {\n const message = `Failed to send email via Nodemailer: ${error instanceof Error ? error.message : String(error)}`;\n this.log.error(message, { to, subject });\n throw new EmailError(message, error instanceof Error ? error : undefined);\n }\n }\n\n protected createTransporter(): Transporter {\n const transporterConfig = {\n host: this.host,\n port: this.port,\n secure: this.secure,\n auth:\n this.user && this.pass\n ? {\n user: this.user,\n pass: this.pass,\n }\n : undefined,\n pool: this.options.pool,\n maxConnections: this.options.maxConnections,\n maxMessages: this.options.maxMessages,\n rateDelta: this.options.rateDelta,\n rateLimit: this.options.rateLimit,\n };\n\n this.log.debug(\"Creating Nodemailer transporter\", {\n host: transporterConfig.host,\n port: transporterConfig.port,\n secure: transporterConfig.secure,\n user: transporterConfig.auth?.user,\n pool: transporterConfig.pool,\n });\n\n return nodemailer.createTransport(transporterConfig);\n }\n\n /**\n * Verify the connection to the email server.\n */\n public async verify(): Promise<boolean> {\n try {\n await this.getTransporter().verify();\n this.log.info(\"Email server connection verified\");\n return true;\n } catch (error) {\n this.log.error(\"Email server connection failed\", { error });\n return false;\n }\n }\n\n /**\n * Close the transporter connection.\n */\n public close(): void {\n if (this.transporter) {\n this.transporter.close();\n this.transporter = null;\n }\n }\n\n protected readonly onStart = $hook({\n on: \"start\",\n handler: () => this.verify(),\n });\n\n protected readonly onStop = $hook({\n on: \"stop\",\n handler: () => this.close(),\n });\n}\n","import { $module } from \"alepha\";\nimport { $email } from \"./primitives/$email.ts\";\nimport { EmailProvider } from \"./providers/EmailProvider.ts\";\nimport { LocalEmailProvider } from \"./providers/LocalEmailProvider.ts\";\nimport { MemoryEmailProvider } from \"./providers/MemoryEmailProvider.ts\";\nimport { NodemailerEmailProvider } from \"./providers/NodemailerEmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./errors/EmailError.ts\";\nexport * from \"./primitives/$email.ts\";\nexport * from \"./providers/EmailProvider.ts\";\nexport * from \"./providers/LocalEmailProvider.ts\";\nexport * from \"./providers/MemoryEmailProvider.ts\";\nexport * from \"./providers/NodemailerEmailProvider.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\ndeclare module \"alepha\" {\n interface Hooks {\n \"email:sending\": {\n to: string | string[];\n template: string;\n variables: Record<string, unknown>;\n provider: EmailProvider;\n abort(): void;\n };\n \"email:sent\": {\n to: string | string[];\n template: string;\n provider: EmailProvider;\n };\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides email sending capabilities for Alepha applications with multiple provider backends.\n *\n * The email module enables declarative email sending through the `$email` primitive, allowing you to send\n * emails through different providers: memory (for testing), local file system, or SMTP via Nodemailer.\n * It supports HTML email content and automatic provider selection based on environment configuration.\n *\n * @see {@link EmailProvider}\n * @module alepha.email\n */\nexport const AlephaEmail = $module({\n name: \"alepha.email\",\n primitives: [$email],\n services: [\n EmailProvider,\n MemoryEmailProvider,\n LocalEmailProvider,\n NodemailerEmailProvider,\n ],\n register: (alepha) => {\n if (alepha.isTest()) {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: MemoryEmailProvider,\n });\n } else if (alepha.env.EMAIL_HOST) {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: NodemailerEmailProvider,\n });\n } else {\n if (alepha.isServerless()) {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: MemoryEmailProvider,\n });\n } else {\n alepha.with({\n optional: true,\n provide: EmailProvider,\n use: LocalEmailProvider,\n });\n }\n }\n },\n});\n"],"mappings":"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"}
|