@softure-ai/mailing 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +48 -0
- package/README.md +85 -6
- package/dist/contract.d.ts +13 -1
- package/dist/contract.d.ts.map +1 -1
- package/dist/contract.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/jobs/delivery-job.d.ts +72 -0
- package/dist/jobs/delivery-job.d.ts.map +1 -0
- package/dist/jobs/delivery-job.js +85 -0
- package/dist/jobs/delivery-job.js.map +1 -0
- package/dist/jobs/index.d.ts +2 -0
- package/dist/jobs/index.d.ts.map +1 -0
- package/dist/jobs/index.js +4 -0
- package/dist/jobs/index.js.map +1 -0
- package/dist/messages/en.d.ts +2 -0
- package/dist/messages/en.d.ts.map +1 -1
- package/dist/messages/en.js +2 -0
- package/dist/messages/en.js.map +1 -1
- package/dist/messages/index.d.ts +4 -2
- package/dist/messages/index.d.ts.map +1 -1
- package/dist/messages/index.js.map +1 -1
- package/dist/next/actions.d.ts.map +1 -1
- package/dist/next/actions.js +8 -26
- package/dist/next/actions.js.map +1 -1
- package/dist/next/page-submit.d.ts +12 -0
- package/dist/next/page-submit.d.ts.map +1 -0
- package/dist/next/page-submit.js +30 -0
- package/dist/next/page-submit.js.map +1 -0
- package/dist/next/pages.d.ts.map +1 -1
- package/dist/next/pages.js +8 -5
- package/dist/next/pages.js.map +1 -1
- package/dist/next/route.d.ts +4 -1
- package/dist/next/route.d.ts.map +1 -1
- package/dist/next/route.js +58 -2
- package/dist/next/route.js.map +1 -1
- package/dist/next/strip-link-query.d.ts +11 -0
- package/dist/next/strip-link-query.d.ts.map +1 -0
- package/dist/next/strip-link-query.js +25 -0
- package/dist/next/strip-link-query.js.map +1 -0
- package/dist/providers/resend.d.ts +5 -0
- package/dist/providers/resend.d.ts.map +1 -1
- package/dist/providers/resend.js +23 -3
- package/dist/providers/resend.js.map +1 -1
- package/dist/server/deliveries.d.ts +6 -1
- package/dist/server/deliveries.d.ts.map +1 -1
- package/dist/server/deliveries.js +3 -2
- package/dist/server/deliveries.js.map +1 -1
- package/dist/server/send-mail.d.ts +2 -1
- package/dist/server/send-mail.d.ts.map +1 -1
- package/dist/server/send-mail.js +17 -5
- package/dist/server/send-mail.js.map +1 -1
- package/module.json +2 -2
- package/package.json +12 -1
- package/src/contract.ts +14 -3
- package/src/index.ts +4 -3
- package/src/jobs/delivery-job.ts +129 -0
- package/src/jobs/index.ts +12 -0
- package/src/messages/en.ts +2 -0
- package/src/messages/index.ts +2 -2
- package/src/next/actions.ts +8 -24
- package/src/next/page-submit.ts +35 -0
- package/src/next/pages.tsx +9 -5
- package/src/next/route.ts +59 -4
- package/src/next/strip-link-query.tsx +30 -0
- package/src/providers/resend.ts +22 -3
- package/src/server/deliveries.ts +9 -5
- package/src/server/send-mail.ts +18 -5
package/src/server/send-mail.ts
CHANGED
|
@@ -37,7 +37,8 @@ export interface MailContext {
|
|
|
37
37
|
* `invalid_input` (fix the input), `rejected` (do not retry), `unavailable` (retry later with the
|
|
38
38
|
* same `idempotencyKey`), `suppressed` (a list mail to someone who unsubscribed; do not retry),
|
|
39
39
|
* `provider_refused` / `quota_exceeded` (the account cannot send: stop, fix or wait, then retry). A
|
|
40
|
-
* failure the provider answered with an HTTP status carries it as `httpStatus
|
|
40
|
+
* failure the provider answered with an HTTP status carries it as `httpStatus`, and the wait it asked for
|
|
41
|
+
* (`Retry-After`) as `retryAfterSeconds`.
|
|
41
42
|
* Throws only when the module is not enabled, or for list mail without `context.db`.
|
|
42
43
|
*/
|
|
43
44
|
export async function sendMail(context: MailContext, mail: OutgoingMail, options: SendMailOptions = {}): Promise<SendMailResult> {
|
|
@@ -64,7 +65,11 @@ export async function sendMail(context: MailContext, mail: OutgoingMail, options
|
|
|
64
65
|
}
|
|
65
66
|
const code = FAILURE_CODES[outcome.status];
|
|
66
67
|
logFailure(provider, code, { status: outcome.httpStatus });
|
|
67
|
-
return
|
|
68
|
+
return {
|
|
69
|
+
...err(code),
|
|
70
|
+
...(outcome.httpStatus === undefined ? {} : { httpStatus: outcome.httpStatus }),
|
|
71
|
+
...(outcome.retryAfterSeconds === undefined ? {} : { retryAfterSeconds: outcome.retryAfterSeconds }),
|
|
72
|
+
};
|
|
68
73
|
}
|
|
69
74
|
|
|
70
75
|
/** Why `previewMail` cannot render a mail: invalid input (with the fields), or list mail without the secret. */
|
|
@@ -171,17 +176,25 @@ async function callProvider(provider: MailProvider, message: Parameters<MailProv
|
|
|
171
176
|
/** A provider's answer, narrowed: anything that is not a known outcome reads as `unavailable`. */
|
|
172
177
|
function readOutcome(outcome: unknown): ProviderOutcome {
|
|
173
178
|
if (typeof outcome !== "object" || outcome === null) return { status: "unavailable" };
|
|
174
|
-
const { status, id, httpStatus } = outcome as { status?: unknown; id?: unknown; httpStatus?: unknown };
|
|
179
|
+
const { status, id, httpStatus, retryAfterSeconds } = outcome as { status?: unknown; id?: unknown; httpStatus?: unknown; retryAfterSeconds?: unknown };
|
|
175
180
|
if (status === "sent") {
|
|
176
181
|
return typeof id === "string" && id !== "" ? { status, id } : { status: "unavailable" };
|
|
177
182
|
}
|
|
178
183
|
if (typeof status === "string" && Object.hasOwn(FAILURE_CODES, status)) {
|
|
179
|
-
|
|
180
|
-
|
|
184
|
+
return {
|
|
185
|
+
status: status as ProviderFailureStatus,
|
|
186
|
+
...(isHttpStatus(httpStatus) ? { httpStatus } : {}),
|
|
187
|
+
...(isRetryAfter(retryAfterSeconds) ? { retryAfterSeconds } : {}),
|
|
188
|
+
};
|
|
181
189
|
}
|
|
182
190
|
return { status: "unavailable" };
|
|
183
191
|
}
|
|
184
192
|
|
|
193
|
+
/** A provider's `Retry-After` in whole seconds; anything else is dropped. */
|
|
194
|
+
function isRetryAfter(value: unknown): value is number {
|
|
195
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0;
|
|
196
|
+
}
|
|
197
|
+
|
|
185
198
|
function isHttpStatus(value: unknown): value is number {
|
|
186
199
|
return typeof value === "number" && Number.isInteger(value) && value >= 100 && value <= 599;
|
|
187
200
|
}
|