🚀 Socket Launch Week Day 5:Introducing Repository Access Permissions and Custom Roles.Learn more
Sign In

@fluojs/email

Package Overview
Dependencies
Maintainers
1
Versions
8
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@fluojs/email - npm Package Compare versions

Comparing version
1.0.0-beta.3
to
1.0.0-beta.4
+1
-1
dist/service.d.ts.map

@@ -1,1 +0,1 @@

{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAM3E,OAAO,KAAK,EACV,KAAK,EAGL,YAAY,EACZ,gCAAgC,EAC9B,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EAKf,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AA2CtB;;;;;;;GAOG;AACH,qBACa,YAAa,YAAW,KAAK,EAAE,YAAY,EAAE,qBAAqB;IAKjE,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,cAAc,CAAmF;IACzG,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,gBAAgB,CAAsC;gBAEjC,OAAO,EAAE,4BAA4B;IAE5D,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAetC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBnC;;;;OAIG;IACH,4BAA4B;IAY5B;;;;;;;;;;;;;;;;;OAiBG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IAoB3F;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA6BpH;;;;;;;;;;;;;;;;;OAiBG;IACG,gBAAgB,CACpB,YAAY,EAAE,gCAAgC,EAC9C,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC;YA0Bb,eAAe;IAe7B,OAAO,CAAC,gBAAgB;YAuBV,kBAAkB;CAejC"}
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,qBAAqB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAM3E,OAAO,KAAK,EACV,KAAK,EAGL,YAAY,EACZ,gCAAgC,EAC9B,oBAAoB,EAEpB,oBAAoB,EACpB,gBAAgB,EAChB,eAAe,EAKf,4BAA4B,EAC7B,MAAM,YAAY,CAAC;AAyDtB;;;;;;;GAOG;AACH,qBACa,YAAa,YAAW,KAAK,EAAE,YAAY,EAAE,qBAAqB;IAKjE,OAAO,CAAC,QAAQ,CAAC,OAAO;IAJpC,OAAO,CAAC,cAAc,CAAmF;IACzG,OAAO,CAAC,iBAAiB,CAA6B;IACtD,OAAO,CAAC,gBAAgB,CAAsC;gBAEjC,OAAO,EAAE,4BAA4B;IAE5D,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC;IAetC,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC;IAiBnC;;;;OAIG;IACH,4BAA4B;IAY5B;;;;;;;;;;;;;;;;;OAiBG;IACG,IAAI,CAAC,OAAO,EAAE,YAAY,EAAE,OAAO,GAAE,gBAAqB,GAAG,OAAO,CAAC,eAAe,CAAC;IAmB3F;;;;;;;;;;;;OAYG;IACG,QAAQ,CAAC,QAAQ,EAAE,SAAS,YAAY,EAAE,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,oBAAoB,CAAC;IA6BpH;;;;;;;;;;;;;;;;;OAiBG;IACG,gBAAgB,CACpB,YAAY,EAAE,gCAAgC,EAC9C,OAAO,GAAE,gBAAqB,GAC7B,OAAO,CAAC,eAAe,CAAC;YA4Bb,eAAe;IAe7B,OAAO,CAAC,gBAAgB;YAuBV,kBAAkB;CAkBjC"}

@@ -38,2 +38,12 @@ let _initClass;

}
function assertNotAborted(signal) {
if (signal?.aborted) {
throw createAbortError();
}
}
function createLifecycleError(message, cause) {
return new Error(message, {
cause
});
}
function assertMessageContent(message) {

@@ -43,2 +53,5 @@ if (message.to.length === 0) {

}
if (message.to.some(entry => entry.address.length === 0)) {
throw new EmailMessageValidationError('Email messages require non-empty recipients in `to`.');
}
if (!message.from.address) {

@@ -78,5 +91,5 @@ throw new EmailMessageValidationError('Email messages require a resolved `from` address.');

this.lifecycleState = 'stopped';
} catch {
} catch (error) {
this.lifecycleState = 'failed';
throw new Error('Email transport failed to close cleanly.');
throw createLifecycleError('Email transport failed to close cleanly.', error);
}

@@ -92,5 +105,5 @@ }

this.lifecycleState = 'ready';
} catch {
} catch (error) {
this.lifecycleState = 'failed';
throw new Error('Email transport failed to initialize.');
throw createLifecycleError('Email transport failed to initialize.', error);
}

@@ -135,8 +148,7 @@ }

async send(message, options = {}) {
if (options.signal?.aborted) {
throw createAbortError();
}
assertNotAborted(options.signal);
const transport = await this.ensureTransport();
const normalized = this.normalizeMessage(message);
assertMessageContent(normalized);
assertNotAborted(options.signal);
const result = await transport.send(normalized, options);

@@ -211,3 +223,4 @@ return {

const payload = notification.payload;
const rendered = await this.renderNotification(notification);
const rendered = await this.renderNotification(notification, options.signal);
assertNotAborted(options.signal);
return this.send({

@@ -265,6 +278,7 @@ attachments: payload.attachments,

}
async renderNotification(notification) {
async renderNotification(notification, signal) {
if (!notification.template || !this.options.renderer) {
return undefined;
}
assertNotAborted(signal);
return this.options.renderer.render({

@@ -271,0 +285,0 @@ locale: notification.locale,

@@ -13,3 +13,3 @@ {

],
"version": "1.0.0-beta.3",
"version": "1.0.0-beta.4",
"private": false,

@@ -56,10 +56,10 @@ "license": "MIT",

"dependencies": {
"@fluojs/core": "^1.0.0-beta.4",
"@fluojs/di": "^1.0.0-beta.6",
"@fluojs/notifications": "^1.0.0-beta.3",
"@fluojs/runtime": "^1.0.0-beta.11"
"@fluojs/core": "^1.0.0-beta.5",
"@fluojs/di": "^1.0.0-beta.7",
"@fluojs/notifications": "^1.0.0-beta.4",
"@fluojs/runtime": "^1.0.0-beta.12"
},
"peerDependencies": {
"nodemailer": "^6.10.1",
"@fluojs/queue": "^1.0.0-beta.4"
"@fluojs/queue": "^1.0.0-beta.5"
},

@@ -77,3 +77,3 @@ "peerDependenciesMeta": {

"vitest": "^3.2.4",
"@fluojs/queue": "^1.0.0-beta.4"
"@fluojs/queue": "^1.0.0-beta.5"
},

@@ -80,0 +80,0 @@ "scripts": {

@@ -89,4 +89,5 @@ # @fluojs/email

@Inject(EmailService)
export class WelcomeService {
constructor(@Inject(EmailService) private readonly email: EmailService) {}
constructor(private readonly email: EmailService) {}

@@ -166,2 +167,4 @@ async sendWelcome(address: string) {

- `EmailService.send(...)`는 전달 전에 `defaultFrom`과 `defaultReplyTo`를 해석합니다.
- `EmailService.send(...)`는 빈 `to` 수신자를 transport handoff 전에 거부하므로 transport가 빈 전달 대상을 받지 않습니다.
- `EmailService.send(...)`와 `EmailService.sendNotification(...)`은 이미 abort된 `AbortSignal`을 템플릿 렌더링 또는 transport handoff 전에 반영합니다.
- `EmailService.send(...)`는 `accepted`, `pending`, `rejected` 수신자를 분리해 보존하므로 provider의 부분 실패가 호출자에게 그대로 보입니다.

@@ -171,2 +174,3 @@ - `EmailService.sendMany(...)`는 기본적으로 fail-fast입니다. 실패를 batch result에 수집하려면 `continueOnError: true`를 전달합니다.

- 서비스는 모듈 bootstrap 시 transport를 초기화하고, factory가 소유한 리소스만 애플리케이션 shutdown 시 닫습니다.
- transport `verify()`와 `close()`에서 발생한 provider error는 diagnostics를 위해 lifecycle failure의 `cause`로 보존됩니다.
- 모듈 옵션은 provider wiring 전에 trim 및 normalize됩니다. 여기에는 sender 기본값, notification channel 이름, transport factory 소유권이 포함됩니다.

@@ -173,0 +177,0 @@ - 이 패키지는 절대로 `process.env`를 직접 읽지 않습니다. 모든 설정은 명시적인 옵션 또는 DI를 통해 들어와야 합니다.

@@ -89,4 +89,5 @@ # @fluojs/email

@Inject(EmailService)
export class WelcomeService {
constructor(@Inject(EmailService) private readonly email: EmailService) {}
constructor(private readonly email: EmailService) {}

@@ -166,2 +167,4 @@ async sendWelcome(address: string) {

- `EmailService.send(...)` resolves `defaultFrom` and `defaultReplyTo` before delivery.
- `EmailService.send(...)` rejects blank `to` recipients before handoff so transports never receive an empty delivery target.
- `EmailService.send(...)` and `EmailService.sendNotification(...)` honor an already-aborted `AbortSignal` before template rendering or transport handoff.
- `EmailService.send(...)` preserves `accepted`, `pending`, and `rejected` recipients separately so partial provider failures stay caller-visible.

@@ -171,2 +174,3 @@ - `EmailService.sendMany(...)` is fail-fast by default; pass `continueOnError: true` to collect failures in a batch result.

- The service initializes the configured transport during module bootstrap and closes factory-owned resources during application shutdown.
- Transport `verify()` and `close()` provider errors are preserved as the `cause` of lifecycle failures for diagnostics.
- Module options are trimmed and normalized before provider wiring, including sender defaults, notification channel names, and transport factory ownership.

@@ -173,0 +177,0 @@ - The package never reads `process.env` directly. All configuration must enter through explicit options or DI.