Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,3 +71,9 @@ npm run dev
npm test
npm run typecheck
```

The test suite covers the Resend seam with an injected fake `fetch`, so it never
touches the network. Before cutting a release, run a manual smoke test against
real Resend in staging: point `RESEND_API_KEY` + `RESEND_FROM` (or an inline
`apiKey`/`from`) at a Resend test key and confirm `POST /ops/send-email` returns
a real `email_...` id.
8 changes: 4 additions & 4 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export class ValidationError extends ResendToolError {
) {
super(`This request couldn't be processed: ${reason}`);
}
protected extraFields() {
protected override extraFields() {
return { field: this.field, reason: this.reason };
}
}
Expand All @@ -40,7 +40,7 @@ export class ProviderUnauthorizedError extends ResendToolError {
constructor(public providerStatus: number) {
super(`Resend rejected the configured credentials (HTTP ${providerStatus}).`);
}
protected extraFields() {
protected override extraFields() {
return { providerStatus: this.providerStatus };
}
}
Expand All @@ -51,7 +51,7 @@ export class ProviderRejectedError extends ResendToolError {
constructor(public providerStatus: number) {
super(`Resend rejected the email (HTTP ${providerStatus}).`);
}
protected extraFields() {
protected override extraFields() {
return { providerStatus: this.providerStatus };
}
}
Expand All @@ -78,7 +78,7 @@ export class UpstreamTimeoutError extends ResendToolError {
constructor(public timeoutSeconds: number) {
super(`The Resend request timed out after ${timeoutSeconds}s.`);
}
protected extraFields() {
protected override extraFields() {
return { timeoutSeconds: this.timeoutSeconds };
}
}
Expand Down
3 changes: 3 additions & 0 deletions src/resend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export async function sendEmail(
payload = (await res.json()) as Record<string, unknown> | null;
} catch {
if (controller.signal.aborted) throw new Error('timed out mid-body');
// Non-JSON provider response. Downstream id-extraction maps this to
// upstream_unreachable; log the status (never the body) to aid debugging.
logger.warn('resend response body was not JSON', { status: res.status });
payload = null;
}
} catch (err) {
Expand Down
1 change: 1 addition & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"sourceMap": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitOverride": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src/**/*.ts"],
Expand Down
Loading