@hogsend/engine 0.13.0 → 0.13.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/package.json +7 -7
- package/src/env.ts +10 -2
- package/src/index.ts +1 -0
- package/src/lib/domain-status.ts +6 -7
- package/src/lib/from-address.ts +29 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hogsend/engine",
|
|
3
|
-
"version": "0.13.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -40,14 +40,14 @@
|
|
|
40
40
|
"svix": "^1.95.1",
|
|
41
41
|
"winston": "^3.19.0",
|
|
42
42
|
"zod": "^4.4.3",
|
|
43
|
-
"@hogsend/core": "^0.13.
|
|
44
|
-
"@hogsend/db": "^0.13.
|
|
45
|
-
"@hogsend/email": "^0.13.
|
|
46
|
-
"@hogsend/plugin-posthog": "^0.13.
|
|
47
|
-
"@hogsend/plugin-resend": "^0.13.
|
|
43
|
+
"@hogsend/core": "^0.13.1",
|
|
44
|
+
"@hogsend/db": "^0.13.1",
|
|
45
|
+
"@hogsend/email": "^0.13.1",
|
|
46
|
+
"@hogsend/plugin-posthog": "^0.13.1",
|
|
47
|
+
"@hogsend/plugin-resend": "^0.13.1"
|
|
48
48
|
},
|
|
49
49
|
"optionalDependencies": {
|
|
50
|
-
"@hogsend/plugin-postmark": "^0.13.
|
|
50
|
+
"@hogsend/plugin-postmark": "^0.13.1"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
53
|
"@types/node": "^22.15.3",
|
package/src/env.ts
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
import { createEnv } from "@t3-oss/env-core";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
+
import { addrSpecOf } from "./lib/from-address.js";
|
|
4
|
+
|
|
5
|
+
// A from address may be bare ("doug@hogsend.com") or carry a display name
|
|
6
|
+
// ("Doug at Hogsend <doug@hogsend.com>") — both are valid provider wire
|
|
7
|
+
// formats. Domain derivation (lib/from-address.ts) parses either form.
|
|
8
|
+
const fromAddress = z.string().refine((value) => addrSpecOf(value) !== null, {
|
|
9
|
+
message: 'Must be an email address or "Display Name <email>"',
|
|
10
|
+
});
|
|
3
11
|
|
|
4
12
|
/**
|
|
5
13
|
* The HTTP API contract version — surfaced in the OpenAPI document
|
|
@@ -52,7 +60,7 @@ export const env = createEnv({
|
|
|
52
60
|
// (container.ts) and the future `emailProvidersFromEnv` preset. With this
|
|
53
61
|
// optional, a Postmark-only deploy boots without a Resend key.
|
|
54
62
|
RESEND_API_KEY: z.string().min(1).optional(),
|
|
55
|
-
RESEND_FROM_EMAIL:
|
|
63
|
+
RESEND_FROM_EMAIL: fromAddress.default("noreply@hogsend.com"),
|
|
56
64
|
// --- Provider-neutral email config (BYO email provider) ---
|
|
57
65
|
// The active email provider id the container resolves from the
|
|
58
66
|
// EmailProviderRegistry. Absent → "resend" (today's byte-for-byte default).
|
|
@@ -60,7 +68,7 @@ export const env = createEnv({
|
|
|
60
68
|
// Neutral default-from address. The mailer's `defaultFrom` is
|
|
61
69
|
// `EMAIL_FROM ?? RESEND_FROM_EMAIL`, so an unset EMAIL_FROM keeps today's
|
|
62
70
|
// Resend-named default.
|
|
63
|
-
EMAIL_FROM:
|
|
71
|
+
EMAIL_FROM: fromAddress.optional(),
|
|
64
72
|
// The sending domain the domain-status service reports on. OVERRIDES the
|
|
65
73
|
// default derivation (host part of EMAIL_FROM, falling back to the host of
|
|
66
74
|
// RESEND_FROM_EMAIL) — set it when you send from a subaddress domain that
|
package/src/index.ts
CHANGED
|
@@ -203,6 +203,7 @@ export type {
|
|
|
203
203
|
// --- Enrollment guards ---
|
|
204
204
|
export { checkEmailPreferences } from "./lib/enrollment-guards.js";
|
|
205
205
|
export { isFrequencyCapped } from "./lib/frequency-cap.js";
|
|
206
|
+
export { addrSpecOf, hostOfFromAddress } from "./lib/from-address.js";
|
|
206
207
|
export { hatchet } from "./lib/hatchet.js";
|
|
207
208
|
// --- Ingestion pipeline ---
|
|
208
209
|
export {
|
package/src/lib/domain-status.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { DomainStatus, EmailProvider } from "@hogsend/core";
|
|
2
2
|
import type { env as envSchema } from "../env.js";
|
|
3
|
+
import { hostOfFromAddress } from "./from-address.js";
|
|
3
4
|
import type { Logger } from "./logger.js";
|
|
4
5
|
|
|
5
6
|
/**
|
|
@@ -91,13 +92,11 @@ function isPermissionDeniedMessage(message: string): boolean {
|
|
|
91
92
|
return /\bdomains API (?:request failed with status )?40[13]\b/.test(message);
|
|
92
93
|
}
|
|
93
94
|
|
|
94
|
-
/**
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
return email.slice(at + 1).toLowerCase();
|
|
100
|
-
}
|
|
95
|
+
/**
|
|
96
|
+
* Extract the host part of a configured from address ("hello@x.com" or
|
|
97
|
+
* "Name <hello@x.com>" → "x.com") — display-name aware via from-address.ts.
|
|
98
|
+
*/
|
|
99
|
+
const hostPartOf = hostOfFromAddress;
|
|
101
100
|
|
|
102
101
|
/** The Resend unverified-domain from-address fallback (so a redirected mail
|
|
103
102
|
* still delivers while the real sending domain isn't verified yet). */
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* From-address helpers. A configured from address may be a bare addr-spec
|
|
3
|
+
* ("doug@hogsend.com") or carry a display name ("Doug at Hogsend
|
|
4
|
+
* <doug@hogsend.com>") — both are valid on the wire for every supported
|
|
5
|
+
* provider. These helpers parse either form so env validation and
|
|
6
|
+
* domain derivation agree on what the address part is.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
const ADDR_SPEC_RE = /^[^\s@<>]+@[^\s@<>]+\.[^\s@<>]+$/;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Extract the addr-spec from a from address ("Doug <d@x.com>" → "d@x.com",
|
|
13
|
+
* "d@x.com" → "d@x.com"). Returns null when no valid address is present.
|
|
14
|
+
*/
|
|
15
|
+
export function addrSpecOf(value: string | undefined): string | null {
|
|
16
|
+
if (!value) return null;
|
|
17
|
+
const match = value.trim().match(/^[^<>]*<([^<>]+)>$/);
|
|
18
|
+
const addr = (match?.[1] ?? value).trim();
|
|
19
|
+
return ADDR_SPEC_RE.test(addr) ? addr.toLowerCase() : null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** Host part of a from address ("Doug <d@x.com>" → "x.com"). */
|
|
23
|
+
export function hostOfFromAddress(value: string | undefined): string | null {
|
|
24
|
+
const addr = addrSpecOf(value);
|
|
25
|
+
if (!addr) return null;
|
|
26
|
+
const at = addr.lastIndexOf("@");
|
|
27
|
+
if (at === -1 || at === addr.length - 1) return null;
|
|
28
|
+
return addr.slice(at + 1);
|
|
29
|
+
}
|