@pattern-js/mod-email 0.3.0 → 0.4.0-main.c8eb671
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/dist/config.d.ts +1 -1
- package/dist/delivery.d.ts.map +1 -1
- package/dist/delivery.js +5 -3
- package/dist/delivery.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/mod.d.ts.map +1 -1
- package/dist/mod.js +2 -1
- package/dist/mod.js.map +1 -1
- package/dist/ops/inbound.d.ts +14 -0
- package/dist/ops/inbound.d.ts.map +1 -0
- package/dist/ops/inbound.js +93 -0
- package/dist/ops/inbound.js.map +1 -0
- package/dist/service.d.ts +13 -3
- package/dist/service.d.ts.map +1 -1
- package/dist/service.js +55 -14
- package/dist/service.js.map +1 -1
- package/dist/types.d.ts +51 -9
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +3 -7
- package/dist/types.js.map +1 -1
- package/dist/webhook.d.ts +33 -0
- package/dist/webhook.d.ts.map +1 -0
- package/dist/webhook.js +56 -0
- package/dist/webhook.js.map +1 -0
- package/dist/well-known.d.ts +11 -9
- package/dist/well-known.d.ts.map +1 -1
- package/dist/well-known.js +3 -7
- package/dist/well-known.js.map +1 -1
- package/docs/index.md +23 -0
- package/docs/ops/email.inbound.md +12 -0
- package/docs/ops/email.reply.md +10 -0
- package/package.json +5 -5
package/dist/config.d.ts
CHANGED
|
@@ -18,8 +18,8 @@ export declare const emailSettingsSchema: z.ZodObject<{
|
|
|
18
18
|
from: z.ZodString;
|
|
19
19
|
secrets: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
20
20
|
source: z.ZodDefault<z.ZodEnum<{
|
|
21
|
-
vault: "vault";
|
|
22
21
|
env: "env";
|
|
22
|
+
vault: "vault";
|
|
23
23
|
}>>;
|
|
24
24
|
key: z.ZodString;
|
|
25
25
|
}, z.core.$strip>>>;
|
package/dist/delivery.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,wBAAgB,oBAAoB,IAAI,QAAQ,
|
|
1
|
+
{"version":3,"file":"delivery.d.ts","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEjD,wBAAgB,oBAAoB,IAAI,QAAQ,CA6D/C"}
|
package/dist/delivery.js
CHANGED
|
@@ -37,13 +37,15 @@ export function deliverTokenWorkflow() {
|
|
|
37
37
|
{ id: "should", op: "core.bool.and" },
|
|
38
38
|
{ id: "gate", op: "core.flow.branch" },
|
|
39
39
|
{ id: "to", op: "core.object.get", config: { path: "email" } },
|
|
40
|
-
|
|
40
|
+
// Subject + message arrive READY-MADE on the payload (identity writes
|
|
41
|
+
// purpose- and expiry-aware copy — "You've been invited … valid for 7
|
|
42
|
+
// days"). Reword here, or replace the whole template with your own.
|
|
43
|
+
{ id: "subj", op: "core.string.template", config: { template: "{{subject}}" } },
|
|
41
44
|
{
|
|
42
45
|
id: "body",
|
|
43
46
|
op: "core.string.template",
|
|
44
47
|
config: {
|
|
45
|
-
template: "#
|
|
46
|
-
"This link is single-use and expires soon. If you didn't request it, you can safely ignore this email.",
|
|
48
|
+
template: "# {{subject}}\n\n{{message}}\n\n{{url}}\n\nIf you didn't expect this email, you can safely ignore it.",
|
|
47
49
|
},
|
|
48
50
|
},
|
|
49
51
|
{ id: "send", op: "email.send" },
|
package/dist/delivery.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,EAAE,EAAE,qBAAqB;QACzB,IAAI,EAAE,uDAAuD;QAC7D,WAAW,EACT,wFAAwF;YACxF,8DAA8D;QAChE,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,uBAAuB,EAAE,EAAE;YAC5E,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACpF,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;YACnE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,EAAE;YACpC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,eAAe,EAAE;YACrC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,kBAAkB,EAAE;YACtC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;YAC9D,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,sBAAsB,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"delivery.js","sourceRoot":"","sources":["../src/delivery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAIH,MAAM,UAAU,oBAAoB;IAClC,OAAO;QACL,EAAE,EAAE,qBAAqB;QACzB,IAAI,EAAE,uDAAuD;QAC7D,WAAW,EACT,wFAAwF;YACxF,8DAA8D;QAChE,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,KAAK;QACf,KAAK,EAAE;YACL,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,uBAAuB,EAAE,EAAE;YAC5E,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,eAAe,EAAE,MAAM,EAAE,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE;YACpF,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;YACnE,EAAE,EAAE,EAAE,OAAO,EAAE,EAAE,EAAE,eAAe,EAAE;YACpC,EAAE,EAAE,EAAE,QAAQ,EAAE,EAAE,EAAE,eAAe,EAAE;YACrC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,kBAAkB,EAAE;YACtC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;YAC9D,sEAAsE;YACtE,sEAAsE;YACtE,oEAAoE;YACpE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,sBAAsB,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,EAAE;YAC/E;gBACE,EAAE,EAAE,MAAM;gBACV,EAAE,EAAE,sBAAsB;gBAC1B,MAAM,EAAE;oBACN,QAAQ,EAAE,uGAAuG;iBAClH;aACF;YACD,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,YAAY,EAAE;YAChC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,oBAAoB,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACjE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,iBAAiB,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;YACnE,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,sBAAsB,EAAE;YAC1C,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,sBAAsB,EAAE;SAC3C;QACD,KAAK,EAAE;YACL,2DAA2D;YAC3D,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YAC9E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YACxE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YACjF,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,EAAE;YAC3E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,EAAE;YAClF,4DAA4D;YAC5D,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YAC7E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YAC7E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE;YAC7E,iDAAiD;YACjD,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;YAClF,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YACvE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;YAC9E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,EAAE;YAC/E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YAC1E,gEAAgE;YAChE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YAC9E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE;YAC3E,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;YACxE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;YAC7E,yDAAyD;YACzD,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,EAAE;YAChF,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE;SAC3E;KACF,CAAC;AACJ,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -12,5 +12,6 @@ export { EmailConfigService, DEFAULT_ACCOUNT, emailSettingsSchema, type EmailSet
|
|
|
12
12
|
export { DefaultEmailService, type EmailService, type SendResult, type TestResult } from "./service.js";
|
|
13
13
|
export { renderEmailMarkdown } from "./markdown.js";
|
|
14
14
|
export { deliverTokenWorkflow } from "./delivery.js";
|
|
15
|
-
export {
|
|
15
|
+
export { verifySvix, type VerifySvixInput } from "./webhook.js";
|
|
16
|
+
export { secretRefSchema, accountSchema, accountRefSchema, attachmentInputSchema, type SecretRef, type EmailAccount, type EmailAccountRef, type AttachmentInput, type EmailAttachment, type EmailMessage, type EmailDriverSpec, type EmailDriverInfo, type InboundAttachment, type InboundEmailMessage, type InboundInput, type SendInput, } from "./types.js";
|
|
16
17
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5G,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAE,KAAK,eAAe,EAAE,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAC5G,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhE,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAE,KAAK,YAAY,EAAE,KAAK,UAAU,EAAE,KAAK,UAAU,EAAE,MAAM,cAAc,CAAC;AACxG,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAEhE,OAAO,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EACrB,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,YAAY,EACjB,KAAK,eAAe,EACpB,KAAK,eAAe,EACpB,KAAK,iBAAiB,EACtB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,SAAS,GACf,MAAM,YAAY,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,5 +11,6 @@ export { EmailConfigService, DEFAULT_ACCOUNT, emailSettingsSchema } from "./conf
|
|
|
11
11
|
export { DefaultEmailService } from "./service.js";
|
|
12
12
|
export { renderEmailMarkdown } from "./markdown.js";
|
|
13
13
|
export { deliverTokenWorkflow } from "./delivery.js";
|
|
14
|
+
export { verifySvix } from "./webhook.js";
|
|
14
15
|
export { secretRefSchema, accountSchema, accountRefSchema, attachmentInputSchema, } from "./types.js";
|
|
15
16
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAwB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAG5G,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAsB,MAAM,aAAa,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAuD,MAAM,cAAc,CAAC;AACxG,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,QAAQ,EAAwB,MAAM,UAAU,CAAC;AAC1D,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,aAAa,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAG5G,OAAO,EAAE,kBAAkB,EAAE,eAAe,EAAE,mBAAmB,EAAsB,MAAM,aAAa,CAAC;AAC3G,OAAO,EAAE,mBAAmB,EAAuD,MAAM,cAAc,CAAC;AACxG,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,UAAU,EAAwB,MAAM,cAAc,CAAC;AAEhE,OAAO,EACL,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,qBAAqB,GAatB,MAAM,YAAY,CAAC"}
|
package/dist/mod.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"mod.d.ts","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAKH,OAAO,EAA0B,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAU3E,MAAM,WAAW,eAAe;IAC9B,yEAAyE;IACzE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAYD,wBAAgB,QAAQ,CAAC,OAAO,GAAE,eAAoB,GAAG,UAAU,CAqBlE;AAED,gEAAgE;;AAChE,wBAA0B"}
|
package/dist/mod.js
CHANGED
|
@@ -16,6 +16,7 @@ import { EmailConfigService } from "./config.js";
|
|
|
16
16
|
import { DefaultEmailService } from "./service.js";
|
|
17
17
|
import { EMAIL_CONFIG_SERVICE, EMAIL_SERVICE } from "./well-known.js";
|
|
18
18
|
import { accountOp } from "./ops/account.js";
|
|
19
|
+
import { inboundOps } from "./ops/inbound.js";
|
|
19
20
|
import { sendOp } from "./ops/send.js";
|
|
20
21
|
import { deliverTokenWorkflow } from "./delivery.js";
|
|
21
22
|
import { emailAdminRoutes, emailFrontend, settingsOps } from "./settings.js";
|
|
@@ -36,7 +37,7 @@ export function emailMod(options = {}) {
|
|
|
36
37
|
return defineMod({
|
|
37
38
|
name: "@pattern-js/mod-email",
|
|
38
39
|
docs: { filesystem: "email-docs", title: "Email", order: 43 },
|
|
39
|
-
ops: [sendOp, accountOp, ...settingsOps],
|
|
40
|
+
ops: [sendOp, accountOp, ...inboundOps, ...settingsOps],
|
|
40
41
|
// The delivery workflow registers unconditionally: without mod-identity its
|
|
41
42
|
// hook is auto-declared and never invoked (inert); with it, delivery starts
|
|
42
43
|
// the moment a "default" account exists.
|
package/dist/mod.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,SAAS,EAAgC,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAO7E,mFAAmF;AACnF,SAAS,YAAY,CAAC,MAAc;IAClC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;IAClE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,UAA2B,EAAE;IACpD,MAAM,MAAM,GAAG,IAAI,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChD,OAAO,SAAS,CAAC;QACf,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;QAC7D,GAAG,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"mod.js","sourceRoot":"","sources":["../src/mod.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,SAAS,EAAgC,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACrD,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAO7E,mFAAmF;AACnF,SAAS,YAAY,CAAC,MAAc;IAClC,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,aAAa,CAAC,IAAI,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QAC/D,IAAI,UAAU,CAAC,GAAG,CAAC;YAAE,iBAAiB,CAAC,MAAM,EAAE,YAAY,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC;IAC7E,CAAC;IAAC,MAAM,CAAC;QACP,gEAAgE;IAClE,CAAC;AACH,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,UAA2B,EAAE;IACpD,MAAM,MAAM,GAAG,IAAI,kBAAkB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,MAAM,OAAO,GAAG,IAAI,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChD,OAAO,SAAS,CAAC;QACf,IAAI,EAAE,uBAAuB;QAC7B,IAAI,EAAE,EAAE,UAAU,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE;QAC7D,GAAG,EAAE,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,UAAU,EAAE,GAAG,WAAW,CAAC;QACvD,4EAA4E;QAC5E,4EAA4E;QAC5E,yCAAyC;QACzC,SAAS,EAAE,CAAC,oBAAoB,EAAE,EAAE,GAAG,gBAAgB,EAAE,CAAC;QAC1D,QAAQ,EAAE,aAAa,EAAE;QACzB,KAAK,EAAE,CAAC,MAAc,EAAE,EAAE;YACxB,YAAY,CAAC,MAAM,CAAC,CAAC;YACrB,MAAM,CAAC,cAAc,CAAC,oBAAoB,EAAE,MAAM,CAAC,CAAC;YACpD,MAAM,CAAC,cAAc,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;QAChD,CAAC;QACD,KAAK,EAAE,KAAK,IAAI,EAAE;YAChB,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;KACF,CAAC,CAAC;AACL,CAAC;AAED,gEAAgE;AAChE,eAAe,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-email — inbound: the `email.inbound` trigger + `email.reply`.
|
|
3
|
+
*
|
|
4
|
+
* The trigger rides core's generic trigger seam (0.4.0): it declares its
|
|
5
|
+
* event subscriptions via `triggerEvents` and tolerates a missing out-gate
|
|
6
|
+
* via `outgateOptional` — no host wiring anywhere. A webhook driver verifies
|
|
7
|
+
* + parses + calls `EmailService.ingestInbound`, which emits the events; a
|
|
8
|
+
* workflow starting with `email.inbound` runs once per message.
|
|
9
|
+
*/
|
|
10
|
+
import { type OpDefinition } from "@pattern-js/core";
|
|
11
|
+
export declare const inboundTrigger: OpDefinition;
|
|
12
|
+
export declare const replyOp: OpDefinition;
|
|
13
|
+
export declare const inboundOps: OpDefinition[];
|
|
14
|
+
//# sourceMappingURL=inbound.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound.d.ts","sourceRoot":"","sources":["../../src/ops/inbound.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAY,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAI/D,eAAO,MAAM,cAAc,EAAE,YAwB5B,CAAC;AAKF,eAAO,MAAM,OAAO,EAAE,YA2DrB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,YAAY,EAA8B,CAAC"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-email — inbound: the `email.inbound` trigger + `email.reply`.
|
|
3
|
+
*
|
|
4
|
+
* The trigger rides core's generic trigger seam (0.4.0): it declares its
|
|
5
|
+
* event subscriptions via `triggerEvents` and tolerates a missing out-gate
|
|
6
|
+
* via `outgateOptional` — no host wiring anywhere. A webhook driver verifies
|
|
7
|
+
* + parses + calls `EmailService.ingestInbound`, which emits the events; a
|
|
8
|
+
* workflow starting with `email.inbound` runs once per message.
|
|
9
|
+
*/
|
|
10
|
+
import { value, z } from "@pattern-js/core";
|
|
11
|
+
import { emailService, maybe } from "./shared.js";
|
|
12
|
+
export const inboundTrigger = {
|
|
13
|
+
type: "email.inbound",
|
|
14
|
+
title: "email.inbound",
|
|
15
|
+
description: "Inbound email trigger: fires once per received message. config.account narrows to one receiving account " +
|
|
16
|
+
"(empty = every account). Outputs { message, account } — attachments arrive as blob references.",
|
|
17
|
+
boundary: "trigger",
|
|
18
|
+
pair: "boundary.return",
|
|
19
|
+
// The sender's mail server never reads the run result — fire-and-forget.
|
|
20
|
+
outgateOptional: true,
|
|
21
|
+
triggerEvents: (config) => [
|
|
22
|
+
{
|
|
23
|
+
event: config.account?.trim() ? `email.inbound.${config.account.trim()}` : "email.inbound",
|
|
24
|
+
map: (payload) => ({
|
|
25
|
+
message: payload,
|
|
26
|
+
account: payload.account,
|
|
27
|
+
}),
|
|
28
|
+
},
|
|
29
|
+
],
|
|
30
|
+
inputs: {},
|
|
31
|
+
configInputs: { account: value(z.string()) },
|
|
32
|
+
outputs: { message: value(), account: value(z.string()) },
|
|
33
|
+
config: z.object({ account: z.string().optional() }),
|
|
34
|
+
execute: () => ({}),
|
|
35
|
+
};
|
|
36
|
+
const replyBodyDoc = "Write the body once in `markdown` (rendered to styled HTML + text) or pass explicit `html`/`text`.";
|
|
37
|
+
export const replyOp = {
|
|
38
|
+
type: "email.reply",
|
|
39
|
+
title: "email.reply",
|
|
40
|
+
description: `Reply to an inbound message with proper threading: wires In-Reply-To/References from the original and ` +
|
|
41
|
+
`prefixes "Re:" when needed. Wire \`message\` from email.inbound; the reply goes to its sender ` +
|
|
42
|
+
`(reply-to header respected). ${replyBodyDoc}`,
|
|
43
|
+
config: z.object({
|
|
44
|
+
/** Account to send through; default = the account the message arrived on. */
|
|
45
|
+
account: z.string().optional(),
|
|
46
|
+
}),
|
|
47
|
+
inputs: {
|
|
48
|
+
message: value(),
|
|
49
|
+
markdown: value(z.string()),
|
|
50
|
+
html: value(z.string()),
|
|
51
|
+
text: value(z.string()),
|
|
52
|
+
subject: value(z.string()),
|
|
53
|
+
},
|
|
54
|
+
outputs: {
|
|
55
|
+
result: value(z.object({ messageId: z.string().optional(), provider: z.string(), account: z.string() })),
|
|
56
|
+
},
|
|
57
|
+
execute: async (ctx) => {
|
|
58
|
+
const cfg = ctx.config;
|
|
59
|
+
const [message, markdown, html, text, subjectIn] = await Promise.all([
|
|
60
|
+
ctx.input.value("message"),
|
|
61
|
+
maybe(ctx, "markdown"),
|
|
62
|
+
maybe(ctx, "html"),
|
|
63
|
+
maybe(ctx, "text"),
|
|
64
|
+
maybe(ctx, "subject"),
|
|
65
|
+
]);
|
|
66
|
+
if (!message?.from)
|
|
67
|
+
throw new Error("email.reply: wire `message` from an email.inbound trigger");
|
|
68
|
+
// Threading per RFC 5322: References = the original's references + its id.
|
|
69
|
+
const headers = {};
|
|
70
|
+
if (message.messageId) {
|
|
71
|
+
headers["In-Reply-To"] = message.messageId;
|
|
72
|
+
headers["References"] = [...(message.references ?? []), message.messageId].join(" ");
|
|
73
|
+
}
|
|
74
|
+
else if (message.references?.length) {
|
|
75
|
+
headers["References"] = message.references.join(" ");
|
|
76
|
+
}
|
|
77
|
+
const baseSubject = subjectIn ?? message.subject ?? "";
|
|
78
|
+
const subject = /^re:/i.test(baseSubject.trim()) ? baseSubject : `Re: ${baseSubject}`.trim();
|
|
79
|
+
const to = message.headers["reply-to"]?.trim() || message.from;
|
|
80
|
+
const result = await emailService(ctx).send({
|
|
81
|
+
account: cfg.account ?? message.account,
|
|
82
|
+
to,
|
|
83
|
+
subject,
|
|
84
|
+
markdown,
|
|
85
|
+
html,
|
|
86
|
+
text,
|
|
87
|
+
headers: Object.keys(headers).length ? headers : undefined,
|
|
88
|
+
}, ctx);
|
|
89
|
+
return { result };
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
export const inboundOps = [inboundTrigger, replyOp];
|
|
93
|
+
//# sourceMappingURL=inbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbound.js","sourceRoot":"","sources":["../../src/ops/inbound.ts"],"names":[],"mappings":"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"}
|
package/dist/service.d.ts
CHANGED
|
@@ -8,9 +8,9 @@
|
|
|
8
8
|
* secrets (vault/env), markdown → html+text, attachments → bytes, then the
|
|
9
9
|
* driver. Secret VALUES never sit in workflow values or persisted config.
|
|
10
10
|
*/
|
|
11
|
-
import type
|
|
11
|
+
import { type OpContext } from "@pattern-js/core";
|
|
12
12
|
import { type EmailConfigService } from "./config.js";
|
|
13
|
-
import type { EmailAccount, EmailDriverInfo, EmailDriverSpec, SendInput } from "./types.js";
|
|
13
|
+
import type { EmailAccount, EmailDriverInfo, EmailDriverSpec, InboundEmailMessage, InboundInput, SendInput } from "./types.js";
|
|
14
14
|
export interface SendResult {
|
|
15
15
|
messageId?: string;
|
|
16
16
|
provider: string;
|
|
@@ -30,6 +30,15 @@ export interface EmailService {
|
|
|
30
30
|
send(input: SendInput, ctx: OpContext): Promise<SendResult>;
|
|
31
31
|
/** REAL test send of a canned message to `to`, from an (unsaved) draft account. */
|
|
32
32
|
testAccount(draft: EmailAccount, to: string, ctx: OpContext): Promise<TestResult>;
|
|
33
|
+
/**
|
|
34
|
+
* Inbound (0.4.0): webhook drivers hand a verified, parsed message here.
|
|
35
|
+
* Attachments land in the blob store (meta-only when mod-store is absent),
|
|
36
|
+
* then `email.inbound` and `email.inbound.<account>` fire on the event bus —
|
|
37
|
+
* the `email.inbound` trigger op subscribes to exactly those.
|
|
38
|
+
*/
|
|
39
|
+
ingestInbound(input: InboundInput, ctx: OpContext): Promise<InboundEmailMessage>;
|
|
40
|
+
/** Resolve ONE of an account's sourced secrets (webhook drivers verify signatures with this). */
|
|
41
|
+
accountSecret(accountName: string, field: string, ctx: OpContext): Promise<string | undefined>;
|
|
33
42
|
}
|
|
34
43
|
export declare class DefaultEmailService implements EmailService {
|
|
35
44
|
private readonly config;
|
|
@@ -40,10 +49,11 @@ export declare class DefaultEmailService implements EmailService {
|
|
|
40
49
|
driver(id: string): EmailDriverSpec | undefined;
|
|
41
50
|
send(input: SendInput, ctx: OpContext): Promise<SendResult>;
|
|
42
51
|
testAccount(draft: EmailAccount, to: string, ctx: OpContext): Promise<TestResult>;
|
|
52
|
+
ingestInbound(input: InboundInput, ctx: OpContext): Promise<InboundEmailMessage>;
|
|
53
|
+
accountSecret(accountName: string, field: string, ctx: OpContext): Promise<string | undefined>;
|
|
43
54
|
private sendVia;
|
|
44
55
|
/** Resolve every sourced secret the account carries; enforce the driver's required fields. */
|
|
45
56
|
private resolveSecrets;
|
|
46
|
-
private resolveSourced;
|
|
47
57
|
/** to/cc/bcc listed, bodies final (explicit html/text win over markdown per part), attachments as bytes. */
|
|
48
58
|
private normalize;
|
|
49
59
|
private resolveAttachment;
|
package/dist/service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAkB,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElE,OAAO,EAAmB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEvE,OAAO,KAAK,EAEV,YAAY,EAEZ,eAAe,EACf,eAAe,EAGf,mBAAmB,EACnB,YAAY,EACZ,SAAS,EACV,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,YAAY;IAC3B,kFAAkF;IAClF,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI,CAAC;IAC5C,OAAO,IAAI,eAAe,EAAE,CAAC;IAC7B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS,CAAC;IAChD,qFAAqF;IACrF,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5D,mFAAmF;IACnF,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAClF;;;;;OAKG;IACH,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACjF,iGAAiG;IACjG,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAChG;AAED,qBAAa,mBAAoB,YAAW,YAAY;IAG1C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAFnC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsC;gBAElC,MAAM,EAAE,kBAAkB;IAEvD,cAAc,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAI3C,OAAO,IAAI,eAAe,EAAE;IAI5B,MAAM,CAAC,EAAE,EAAE,MAAM,GAAG,eAAe,GAAG,SAAS;IAIzC,IAAI,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IAS3D,WAAW,CAAC,KAAK,EAAE,YAAY,EAAE,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC;IAqBjF,aAAa,CAAC,KAAK,EAAE,YAAY,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,mBAAmB,CAAC;IA8ChF,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC;YAStF,OAAO;IAcrB,8FAA8F;YAChF,cAAc;IAmB5B,4GAA4G;YAC9F,SAAS;YAoCT,iBAAiB;CAqBhC"}
|
package/dist/service.js
CHANGED
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
* secrets (vault/env), markdown → html+text, attachments → bytes, then the
|
|
9
9
|
* driver. Secret VALUES never sit in workflow values or persisted config.
|
|
10
10
|
*/
|
|
11
|
+
import { resolveSourced } from "@pattern-js/core";
|
|
11
12
|
import { renderEmailMarkdown } from "./markdown.js";
|
|
12
13
|
import { DEFAULT_ACCOUNT } from "./config.js";
|
|
13
|
-
import { blobStore,
|
|
14
|
+
import { blobStore, STORE_SERVICE_KEY } from "./well-known.js";
|
|
14
15
|
export class DefaultEmailService {
|
|
15
16
|
config;
|
|
16
17
|
registry = new Map();
|
|
@@ -48,6 +49,57 @@ export class DefaultEmailService {
|
|
|
48
49
|
return { ok: false, detail: err instanceof Error ? err.message : String(err) };
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
/* ── inbound ───────────────────────────────────────────────────────── */
|
|
53
|
+
async ingestInbound(input, ctx) {
|
|
54
|
+
const list = (v) => v === undefined ? [] : (Array.isArray(v) ? v : [v]).filter((s) => s.trim().length > 0);
|
|
55
|
+
// Attachments → blobs. Without mod-store the META survives (filename/mime/
|
|
56
|
+
// size) so workflows still see what arrived; only the bytes are dropped.
|
|
57
|
+
const attachments = [];
|
|
58
|
+
for (const [i, a] of (input.attachments ?? []).entries()) {
|
|
59
|
+
const filename = a.filename ?? `attachment-${i + 1}`;
|
|
60
|
+
const mime = a.mime ?? "application/octet-stream";
|
|
61
|
+
let blobId;
|
|
62
|
+
try {
|
|
63
|
+
const store = ctx.services[STORE_SERVICE_KEY];
|
|
64
|
+
if (store?.blobs && typeof store.blobs.put === "function") {
|
|
65
|
+
blobId = (await store.blobs.put(a.content, { mime })).id;
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
console.warn(`[pattern/mod-email] inbound attachment "${filename}" dropped — install @pattern-js/mod-store to keep attachment bytes`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
catch (err) {
|
|
72
|
+
console.warn(`[pattern/mod-email] inbound attachment "${filename}" failed to store: ${err.message}`);
|
|
73
|
+
}
|
|
74
|
+
attachments.push({ blobId, filename, mime, size: a.content.byteLength });
|
|
75
|
+
}
|
|
76
|
+
const message = {
|
|
77
|
+
account: input.account,
|
|
78
|
+
from: input.from,
|
|
79
|
+
to: list(input.to),
|
|
80
|
+
cc: list(input.cc).length ? list(input.cc) : undefined,
|
|
81
|
+
subject: input.subject ?? "",
|
|
82
|
+
text: input.text,
|
|
83
|
+
html: input.html,
|
|
84
|
+
headers: input.headers ?? {},
|
|
85
|
+
messageId: input.messageId,
|
|
86
|
+
inReplyTo: input.inReplyTo,
|
|
87
|
+
references: input.references,
|
|
88
|
+
attachments,
|
|
89
|
+
receivedAt: input.receivedAt ?? Date.now(),
|
|
90
|
+
};
|
|
91
|
+
// Both the generic event and the per-account one — the trigger op picks.
|
|
92
|
+
ctx.services.events.emit("email.inbound", message);
|
|
93
|
+
ctx.services.events.emit(`email.inbound.${message.account}`, message);
|
|
94
|
+
return message;
|
|
95
|
+
}
|
|
96
|
+
async accountSecret(accountName, field, ctx) {
|
|
97
|
+
const account = this.config.account(accountName);
|
|
98
|
+
const ref = account?.secrets[field];
|
|
99
|
+
if (!ref?.key)
|
|
100
|
+
return undefined;
|
|
101
|
+
return resolveSourced(ctx, ref, "mod-email");
|
|
102
|
+
}
|
|
51
103
|
/* ── internals ─────────────────────────────────────────────────────── */
|
|
52
104
|
async sendVia(account, input, ctx) {
|
|
53
105
|
const driver = this.registry.get(account.provider);
|
|
@@ -69,22 +121,10 @@ export class DefaultEmailService {
|
|
|
69
121
|
}
|
|
70
122
|
const creds = {};
|
|
71
123
|
for (const [field, ref] of Object.entries(account.secrets)) {
|
|
72
|
-
creds[field] = await
|
|
124
|
+
creds[field] = await resolveSourced(ctx, ref, "mod-email");
|
|
73
125
|
}
|
|
74
126
|
return creds;
|
|
75
127
|
}
|
|
76
|
-
async resolveSourced(ctx, ref) {
|
|
77
|
-
if (ref.source === "env") {
|
|
78
|
-
const v = ctx.env[ref.key];
|
|
79
|
-
if (v)
|
|
80
|
-
return v;
|
|
81
|
-
throw new Error(`mod-email: env var "${ref.key}" is not set.`);
|
|
82
|
-
}
|
|
83
|
-
const vault = vaultLike(ctx);
|
|
84
|
-
if (vault?.unlocked() && (await vault.has(ref.key).catch(() => false)))
|
|
85
|
-
return vault.read(ref.key);
|
|
86
|
-
throw new Error(`mod-email: no vault secret "${ref.key}" — add it in admin → System → Secrets (vault must be unlocked).`);
|
|
87
|
-
}
|
|
88
128
|
/** to/cc/bcc listed, bodies final (explicit html/text win over markdown per part), attachments as bytes. */
|
|
89
129
|
async normalize(input, account, ctx) {
|
|
90
130
|
const list = (v) => v === undefined ? undefined : (Array.isArray(v) ? v : [v]).filter((s) => s.trim().length > 0);
|
|
@@ -114,6 +154,7 @@ export class DefaultEmailService {
|
|
|
114
154
|
html,
|
|
115
155
|
text,
|
|
116
156
|
attachments,
|
|
157
|
+
headers: input.headers && Object.keys(input.headers).length ? input.headers : undefined,
|
|
117
158
|
};
|
|
118
159
|
}
|
|
119
160
|
async resolveAttachment(a, index, ctx) {
|
package/dist/service.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,cAAc,EAAkB,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AACpD,OAAO,EAAE,eAAe,EAA2B,MAAM,aAAa,CAAC;AACvE,OAAO,EAAE,SAAS,EAAE,iBAAiB,EAAsB,MAAM,iBAAiB,CAAC;AA8CnF,MAAM,OAAO,mBAAmB;IAGD;IAFZ,QAAQ,GAAG,IAAI,GAAG,EAA2B,CAAC;IAE/D,YAA6B,MAA0B;QAA1B,WAAM,GAAN,MAAM,CAAoB;IAAG,CAAC;IAE3D,cAAc,CAAC,IAAqB;QAClC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,EAAE,IAAI,CAAC,CAAC;IACnC,CAAC;IAED,OAAO;QACL,OAAO,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,CAAC,EAAU;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,KAAgB,EAAE,GAAc;QACzC,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,IAAI,eAAe,CAAC,CAAC;QAC7G,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CAAC,0BAA0B,IAAI,qDAAqD,CAAC,CAAC;QACvG,CAAC;QACD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,WAAW,CAAC,KAAmB,EAAE,EAAU,EAAE,GAAc;QAC/D,IAAI,CAAC;YACH,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,IAAI,CAAC,OAAO,CACtC,KAAK,EACL;gBACE,EAAE;gBACF,OAAO,EAAE,oBAAoB;gBAC7B,QAAQ,EACN,mEAAmE;oBACnE,IAAI,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,QAAQ,iBAAiB;aAC9D,EACD,GAAG,CACJ,CAAC;YACF,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QACjC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;QACjF,CAAC;IACH,CAAC;IAED,0EAA0E;IAE1E,KAAK,CAAC,aAAa,CAAC,KAAmB,EAAE,GAAc;QACrD,MAAM,IAAI,GAAG,CAAC,CAAgC,EAAY,EAAE,CAC1D,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEzF,2EAA2E;QAC3E,yEAAyE;QACzE,MAAM,WAAW,GAAwB,EAAE,CAAC;QAC5C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC;YACzD,MAAM,QAAQ,GAAG,CAAC,CAAC,QAAQ,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;YACrD,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,0BAA0B,CAAC;YAClD,IAAI,MAA0B,CAAC;YAC/B,IAAI,CAAC;gBACH,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAA8B,CAAC;gBAC3E,IAAI,KAAK,EAAE,KAAK,IAAI,OAAO,KAAK,CAAC,KAAK,CAAC,GAAG,KAAK,UAAU,EAAE,CAAC;oBAC1D,MAAM,GAAG,CAAC,MAAM,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3D,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,IAAI,CAAC,2CAA2C,QAAQ,oEAAoE,CAAC,CAAC;gBACxI,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,IAAI,CAAC,2CAA2C,QAAQ,sBAAuB,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;YAClH,CAAC;YACD,WAAW,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,MAAM,OAAO,GAAwB;YACnC,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAClB,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;YACtD,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;YAC5B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,EAAE;YAC5B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,SAAS,EAAE,KAAK,CAAC,SAAS;YAC1B,UAAU,EAAE,KAAK,CAAC,UAAU;YAC5B,WAAW;YACX,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,IAAI,CAAC,GAAG,EAAE;SAC3C,CAAC;QAEF,yEAAyE;QACzE,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QACnD,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,iBAAiB,OAAO,CAAC,OAAO,EAAE,EAAE,OAAO,CAAC,CAAC;QACtE,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,KAAK,CAAC,aAAa,CAAC,WAAmB,EAAE,KAAa,EAAE,GAAc;QACpE,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;QACjD,MAAM,GAAG,GAAG,OAAO,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,EAAE,GAAG;YAAE,OAAO,SAAS,CAAC;QAChC,OAAO,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;IAC/C,CAAC;IAED,0EAA0E;IAElE,KAAK,CAAC,OAAO,CAAC,OAAqB,EAAE,KAAgB,EAAE,GAAc;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;QACnD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,uBAAuB,OAAO,CAAC,IAAI,oBAAoB,OAAO,CAAC,QAAQ,uCAAuC;gBAC5G,+CAA+C,OAAO,CAAC,QAAQ,uCAAuC,CACzG,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,cAAc,CAAC,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,CAAC;QAC1D,MAAM,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC9E,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC;IAC1E,CAAC;IAED,8FAA8F;IACtF,KAAK,CAAC,cAAc,CAC1B,MAAuB,EACvB,OAAqB,EACrB,GAAc;QAEd,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,KAAK,CAAC,EAAE,CAAC;YACvE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBAClC,MAAM,IAAI,KAAK,CACb,uBAAuB,OAAO,CAAC,IAAI,qBAAqB,KAAK,CAAC,KAAK,gBAAgB,MAAM,CAAC,KAAK,mBAAmB,CACnH,CAAC;YACJ,CAAC;QACH,CAAC;QACD,MAAM,KAAK,GAA2B,EAAE,CAAC;QACzC,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC3D,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,cAAc,CAAC,GAAG,EAAE,GAAG,EAAE,WAAW,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,4GAA4G;IACpG,KAAK,CAAC,SAAS,CAAC,KAAgB,EAAE,OAAqB,EAAE,GAAc;QAC7E,MAAM,IAAI,GAAG,CAAC,CAAgC,EAAwB,EAAE,CACtE,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAEhG,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;QAChC,IAAI,CAAC,EAAE,CAAC,MAAM;YAAE,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;QAErF,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACtB,IAAI,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;QACtB,IAAI,KAAK,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;YACjC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YACrD,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC;YACvB,IAAI,KAAK,QAAQ,CAAC,IAAI,CAAC;QACzB,CAAC;QACD,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YAC7C,MAAM,IAAI,KAAK,CAAC,4DAA4D,CAAC,CAAC;QAChF,CAAC;QAED,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,EAAE,MAAM;YAC3C,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC;YACvF,CAAC,CAAC,SAAS,CAAC;QAEd,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,IAAI,IAAI,OAAO,CAAC,IAAI;YAChC,EAAE;YACF,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAClB,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC;YACpB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI;YACJ,IAAI;YACJ,WAAW;YACX,OAAO,EAAE,KAAK,CAAC,OAAO,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS;SACxF,CAAC;IACJ,CAAC;IAEO,KAAK,CAAC,iBAAiB,CAAC,CAAkB,EAAE,KAAa,EAAE,GAAc;QAC/E,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;YAClB,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YACrD,IAAI,CAAC,GAAG;gBAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC,MAAM,oCAAoC,CAAC,CAAC;YAC/F,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,0BAA0B,CAAC;YACnE,OAAO;gBACL,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,eAAe,CAAC,KAAK,EAAE,IAAI,CAAC;gBACpD,OAAO,EAAE,IAAI,UAAU,CAAC,MAAM,IAAI,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;gBACrE,IAAI;aACL,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,IAAI,CAAC,EAAE,CAAC;YACjB,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACpG,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,OAAO,KAAK,QAAQ,CAAC;QAC7C,OAAO;YACL,QAAQ,EAAE,CAAC,CAAC,QAAQ;YACpB,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,OAAiB,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,OAAsB;YAC3F,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,0BAA0B,CAAC;SACrE,CAAC;IACJ,CAAC;CACF;AAED,MAAM,GAAG,GAA2B;IAClC,WAAW,EAAE,MAAM;IACnB,YAAY,EAAE,MAAM;IACpB,YAAY,EAAE,OAAO;IACrB,WAAW,EAAE,MAAM;IACnB,YAAY,EAAE,MAAM;IACpB,WAAW,EAAE,MAAM;IACnB,WAAW,EAAE,MAAM;IACnB,iBAAiB,EAAE,MAAM;IACzB,YAAY,EAAE,MAAM;CACrB,CAAC;AAEF,SAAS,eAAe,CAAC,KAAa,EAAE,IAAY;IAClD,OAAO,cAAc,KAAK,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC;AAC3E,CAAC"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,22 +9,15 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import { z } from "@pattern-js/core";
|
|
11
11
|
import type { OpContext } from "@pattern-js/core";
|
|
12
|
-
export
|
|
13
|
-
source: z.ZodDefault<z.ZodEnum<{
|
|
14
|
-
vault: "vault";
|
|
15
|
-
env: "env";
|
|
16
|
-
}>>;
|
|
17
|
-
key: z.ZodString;
|
|
18
|
-
}, z.core.$strip>;
|
|
19
|
-
export type SecretRef = z.infer<typeof secretRefSchema>;
|
|
12
|
+
export { secretRefSchema, type SecretRef } from "@pattern-js/core";
|
|
20
13
|
export declare const accountSchema: z.ZodObject<{
|
|
21
14
|
name: z.ZodString;
|
|
22
15
|
provider: z.ZodString;
|
|
23
16
|
from: z.ZodString;
|
|
24
17
|
secrets: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
25
18
|
source: z.ZodDefault<z.ZodEnum<{
|
|
26
|
-
vault: "vault";
|
|
27
19
|
env: "env";
|
|
20
|
+
vault: "vault";
|
|
28
21
|
}>>;
|
|
29
22
|
key: z.ZodString;
|
|
30
23
|
}, z.core.$strip>>>;
|
|
@@ -89,6 +82,8 @@ export interface EmailMessage {
|
|
|
89
82
|
html?: string;
|
|
90
83
|
text?: string;
|
|
91
84
|
attachments?: EmailAttachment[];
|
|
85
|
+
/** Extra RFC-5322 headers (In-Reply-To/References for threading, X-* tags). */
|
|
86
|
+
headers?: Record<string, string>;
|
|
92
87
|
}
|
|
93
88
|
/**
|
|
94
89
|
* A driver, registered by a provider mod (`mod-email-resend`, `mod-email-smtp`,
|
|
@@ -129,5 +124,52 @@ export interface SendInput {
|
|
|
129
124
|
html?: string;
|
|
130
125
|
text?: string;
|
|
131
126
|
attachments?: AttachmentInput[];
|
|
127
|
+
/** Extra RFC-5322 headers, passed to the driver verbatim (threading, X-* tags). */
|
|
128
|
+
headers?: Record<string, string>;
|
|
129
|
+
}
|
|
130
|
+
/** What a webhook driver hands `EmailService.ingestInbound` — bytes still inline. */
|
|
131
|
+
export interface InboundInput {
|
|
132
|
+
/** The receiving account name (the webhook route knows which account it serves). */
|
|
133
|
+
account: string;
|
|
134
|
+
from: string;
|
|
135
|
+
to: string | string[];
|
|
136
|
+
cc?: string | string[];
|
|
137
|
+
subject?: string;
|
|
138
|
+
text?: string;
|
|
139
|
+
html?: string;
|
|
140
|
+
headers?: Record<string, string>;
|
|
141
|
+
messageId?: string;
|
|
142
|
+
inReplyTo?: string;
|
|
143
|
+
references?: string[];
|
|
144
|
+
attachments?: Array<{
|
|
145
|
+
filename?: string;
|
|
146
|
+
mime?: string;
|
|
147
|
+
content: Uint8Array;
|
|
148
|
+
}>;
|
|
149
|
+
receivedAt?: number;
|
|
150
|
+
}
|
|
151
|
+
/** An inbound attachment AFTER ingestion: bytes live in the blob store. */
|
|
152
|
+
export interface InboundAttachment {
|
|
153
|
+
/** Absent when mod-store isn't installed (bytes were dropped, meta kept). */
|
|
154
|
+
blobId?: string;
|
|
155
|
+
filename: string;
|
|
156
|
+
mime: string;
|
|
157
|
+
size: number;
|
|
158
|
+
}
|
|
159
|
+
/** What flows out of the `email.inbound` trigger (and rides the event bus). */
|
|
160
|
+
export interface InboundEmailMessage {
|
|
161
|
+
account: string;
|
|
162
|
+
from: string;
|
|
163
|
+
to: string[];
|
|
164
|
+
cc?: string[];
|
|
165
|
+
subject: string;
|
|
166
|
+
text?: string;
|
|
167
|
+
html?: string;
|
|
168
|
+
headers: Record<string, string>;
|
|
169
|
+
messageId?: string;
|
|
170
|
+
inReplyTo?: string;
|
|
171
|
+
references?: string[];
|
|
172
|
+
attachments: InboundAttachment[];
|
|
173
|
+
receivedAt: number;
|
|
132
174
|
}
|
|
133
175
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
CHANGED
|
@@ -7,13 +7,9 @@
|
|
|
7
7
|
* records. What flows on edges is an `EmailAccountRef` (the NAME, never the
|
|
8
8
|
* secrets) — re-pointing an account in admin re-targets every workflow.
|
|
9
9
|
*/
|
|
10
|
-
import { z } from "@pattern-js/core";
|
|
11
|
-
/* ── sourced secrets (
|
|
12
|
-
export
|
|
13
|
-
source: z.enum(["vault", "env"]).default("vault"),
|
|
14
|
-
/** The vault secret name or the env-var name (never the value). */
|
|
15
|
-
key: z.string(),
|
|
16
|
-
});
|
|
10
|
+
import { z, secretRefSchema } from "@pattern-js/core";
|
|
11
|
+
/* ── sourced secrets (hoisted to core; re-exported for drivers) ─────────── */
|
|
12
|
+
export { secretRefSchema } from "@pattern-js/core";
|
|
17
13
|
/* ── accounts ─────────────────────────────────────────────────────────── */
|
|
18
14
|
export const accountSchema = z.object({
|
|
19
15
|
/** "default" is the convention the delivery workflow and agents fall back to. */
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,CAAC,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAGtD,+EAA+E;AAE/E,OAAO,EAAE,eAAe,EAAkB,MAAM,kBAAkB,CAAC;AAEnE,6EAA6E;AAE7E,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,iFAAiF;IACjF,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,mEAAmE;IACnE,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3B,8EAA8E;IAC9E,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;IACvB,gFAAgF;IAChF,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,eAAe,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC1D,+EAA+E;IAC/E,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACtD,CAAC,CAAC;AAGH,2EAA2E;AAC3E,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,IAAI,EAAE,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC;IAC/B,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,6EAA6E;IAC7E,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;CACrB,CAAC,CAAC;AAGH,6EAA6E;AAE7E,MAAM,WAAW,GAAG,CAAC,CAAC,MAAM,CAAa,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,YAAY,UAAU,CAAC,CAAC;AAEzE,iEAAiE;AACjE,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC5C,KAAK,EAAE,WAAW;IAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAEH,qFAAqF;AACrF,MAAM,CAAC,MAAM,wBAAwB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC/C,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAChC,CAAC,CAAC;AAEH,oDAAoD;AACpD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9C,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,EAAE,WAAW,CAAC,CAAC;IAC3C,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;CAC5B,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,CAAC,KAAK,CAAC;IAC3C,wBAAwB;IACxB,qBAAqB;IACrB,uBAAuB;CACxB,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-email — webhook signature verification (Svix scheme).
|
|
3
|
+
*
|
|
4
|
+
* Resend (and many others) sign inbound webhooks the Svix way:
|
|
5
|
+
* `HMAC-SHA256(base64decode(secret without "whsec_"), "{id}.{timestamp}.{body}")`,
|
|
6
|
+
* base64-encoded, in a space-separated multi-signature header
|
|
7
|
+
* (`v1,<sig> v1,<sig2> …` — key rotation sends several). Hand-rolled on
|
|
8
|
+
* node:crypto — ~30 lines beats a dependency — with constant-time comparison
|
|
9
|
+
* and a ±5 minute timestamp window against replays.
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT for callers: verify the RAW request bytes. A JSON-parsed-and-
|
|
12
|
+
* re-stringified body is NOT the signed content — webhook routes must use
|
|
13
|
+
* `bodyMode: "stream"` on their trigger.
|
|
14
|
+
*/
|
|
15
|
+
export interface VerifySvixInput {
|
|
16
|
+
/** The `whsec_…` secret (or its bare base64 tail). */
|
|
17
|
+
secret: string;
|
|
18
|
+
/** svix-id header. */
|
|
19
|
+
id: string;
|
|
20
|
+
/** svix-timestamp header (unix seconds). */
|
|
21
|
+
timestamp: string;
|
|
22
|
+
/** svix-signature header (space-separated `v1,<base64>` candidates). */
|
|
23
|
+
signature: string;
|
|
24
|
+
/** The RAW request body bytes (or their exact utf-8 string). */
|
|
25
|
+
payload: Uint8Array | string;
|
|
26
|
+
/** Clock skew tolerance (default 5 minutes). */
|
|
27
|
+
toleranceMs?: number;
|
|
28
|
+
/** Test seam. */
|
|
29
|
+
now?: number;
|
|
30
|
+
}
|
|
31
|
+
/** True only for a well-formed, in-window, correctly signed webhook. */
|
|
32
|
+
export declare function verifySvix(input: VerifySvixInput): boolean;
|
|
33
|
+
//# sourceMappingURL=webhook.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,MAAM,WAAW,eAAe;IAC9B,sDAAsD;IACtD,MAAM,EAAE,MAAM,CAAC;IACf,sBAAsB;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,4CAA4C;IAC5C,SAAS,EAAE,MAAM,CAAC;IAClB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,OAAO,EAAE,UAAU,GAAG,MAAM,CAAC;IAC7B,gDAAgD;IAChD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,wEAAwE;AACxE,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAkC1D"}
|
package/dist/webhook.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @pattern-js/mod-email — webhook signature verification (Svix scheme).
|
|
3
|
+
*
|
|
4
|
+
* Resend (and many others) sign inbound webhooks the Svix way:
|
|
5
|
+
* `HMAC-SHA256(base64decode(secret without "whsec_"), "{id}.{timestamp}.{body}")`,
|
|
6
|
+
* base64-encoded, in a space-separated multi-signature header
|
|
7
|
+
* (`v1,<sig> v1,<sig2> …` — key rotation sends several). Hand-rolled on
|
|
8
|
+
* node:crypto — ~30 lines beats a dependency — with constant-time comparison
|
|
9
|
+
* and a ±5 minute timestamp window against replays.
|
|
10
|
+
*
|
|
11
|
+
* IMPORTANT for callers: verify the RAW request bytes. A JSON-parsed-and-
|
|
12
|
+
* re-stringified body is NOT the signed content — webhook routes must use
|
|
13
|
+
* `bodyMode: "stream"` on their trigger.
|
|
14
|
+
*/
|
|
15
|
+
import { createHmac, timingSafeEqual } from "node:crypto";
|
|
16
|
+
/** True only for a well-formed, in-window, correctly signed webhook. */
|
|
17
|
+
export function verifySvix(input) {
|
|
18
|
+
const { secret, id, timestamp, signature, payload } = input;
|
|
19
|
+
if (!secret || !id || !timestamp || !signature)
|
|
20
|
+
return false;
|
|
21
|
+
const tsSeconds = Number(timestamp);
|
|
22
|
+
if (!Number.isFinite(tsSeconds))
|
|
23
|
+
return false;
|
|
24
|
+
const toleranceMs = input.toleranceMs ?? 5 * 60 * 1000;
|
|
25
|
+
const now = input.now ?? Date.now();
|
|
26
|
+
if (Math.abs(now - tsSeconds * 1000) > toleranceMs)
|
|
27
|
+
return false;
|
|
28
|
+
let key;
|
|
29
|
+
try {
|
|
30
|
+
key = Buffer.from(secret.startsWith("whsec_") ? secret.slice("whsec_".length) : secret, "base64");
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
return false;
|
|
34
|
+
}
|
|
35
|
+
if (!key.length)
|
|
36
|
+
return false;
|
|
37
|
+
const body = typeof payload === "string" ? Buffer.from(payload, "utf8") : Buffer.from(payload);
|
|
38
|
+
const signed = Buffer.concat([Buffer.from(`${id}.${tsSeconds}.`, "utf8"), body]);
|
|
39
|
+
const expected = createHmac("sha256", key).update(signed).digest();
|
|
40
|
+
for (const candidate of signature.split(/\s+/)) {
|
|
41
|
+
const [version, sig] = candidate.split(",", 2);
|
|
42
|
+
if (version !== "v1" || !sig)
|
|
43
|
+
continue;
|
|
44
|
+
let given;
|
|
45
|
+
try {
|
|
46
|
+
given = Buffer.from(sig, "base64");
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (given.length === expected.length && timingSafeEqual(given, expected))
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webhook.js","sourceRoot":"","sources":["../src/webhook.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAmB1D,wEAAwE;AACxE,MAAM,UAAU,UAAU,CAAC,KAAsB;IAC/C,MAAM,EAAE,MAAM,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,KAAK,CAAC;IAC5D,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,IAAI,CAAC,SAAS,IAAI,CAAC,SAAS;QAAE,OAAO,KAAK,CAAC;IAE7D,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IACpC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,SAAS,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9C,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;IACvD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;IACpC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG,SAAS,GAAG,IAAI,CAAC,GAAG,WAAW;QAAE,OAAO,KAAK,CAAC;IAEjE,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACpG,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAE9B,MAAM,IAAI,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC/F,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,SAAS,GAAG,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;IACjF,MAAM,QAAQ,GAAG,UAAU,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,CAAC;IAEnE,KAAK,MAAM,SAAS,IAAI,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/C,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;QAC/C,IAAI,OAAO,KAAK,IAAI,IAAI,CAAC,GAAG;YAAE,SAAS;QACvC,IAAI,KAAa,CAAC;QAClB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,SAAS;QACX,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,eAAe,CAAC,KAAK,EAAE,QAAQ,CAAC;YAAE,OAAO,IAAI,CAAC;IACxF,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
package/dist/well-known.d.ts
CHANGED
|
@@ -3,21 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* mod-vault (secrets) and mod-store (blob attachments) are looked up by their
|
|
5
5
|
* well-known service keys, never imported — mod-email has no hard dependency
|
|
6
|
-
* on either. (
|
|
7
|
-
* future hoist to core would collapse the three.)
|
|
6
|
+
* on either. (VaultLike now lives in core; BlobStoreLike stays local.)
|
|
8
7
|
*/
|
|
9
8
|
import type { OpContext } from "@pattern-js/core";
|
|
10
9
|
/** Driver registry + account-resolving send/test (the contract surface). */
|
|
11
10
|
export declare const EMAIL_SERVICE = "emailService";
|
|
12
11
|
/** Persisted email accounts (.pattern-data/email-config.json). */
|
|
13
12
|
export declare const EMAIL_CONFIG_SERVICE = "emailConfig";
|
|
14
|
-
export
|
|
15
|
-
export interface VaultLike {
|
|
16
|
-
unlocked(): boolean;
|
|
17
|
-
has(name: string): Promise<boolean>;
|
|
18
|
-
read(name: string): Promise<string>;
|
|
19
|
-
}
|
|
20
|
-
export declare function vaultLike(ctx: OpContext): VaultLike | undefined;
|
|
13
|
+
export { VAULT_SERVICE_KEY, vaultLike, type VaultLike } from "@pattern-js/core";
|
|
21
14
|
export declare const STORE_SERVICE_KEY = "storeService";
|
|
22
15
|
export interface BlobStoreLike {
|
|
23
16
|
blobs: {
|
|
@@ -27,6 +20,15 @@ export interface BlobStoreLike {
|
|
|
27
20
|
};
|
|
28
21
|
stream: ReadableStream<Uint8Array>;
|
|
29
22
|
} | null>;
|
|
23
|
+
/** Inbound attachments land here (mirrors mod-store's BlobStore.put). */
|
|
24
|
+
put(data: Uint8Array | ReadableStream<Uint8Array>, opts?: {
|
|
25
|
+
mime?: string;
|
|
26
|
+
ownerId?: string | null;
|
|
27
|
+
}): Promise<{
|
|
28
|
+
id: string;
|
|
29
|
+
mime: string;
|
|
30
|
+
size: number;
|
|
31
|
+
}>;
|
|
30
32
|
};
|
|
31
33
|
}
|
|
32
34
|
/** Only reached when a MediaRef attachment is wired — hence the lazy throw. */
|
package/dist/well-known.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"well-known.d.ts","sourceRoot":"","sources":["../src/well-known.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"well-known.d.ts","sourceRoot":"","sources":["../src/well-known.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAElD,4EAA4E;AAC5E,eAAO,MAAM,aAAa,iBAAiB,CAAC;AAC5C,kEAAkE;AAClE,eAAO,MAAM,oBAAoB,gBAAgB,CAAC;AAIlD,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAIhF,eAAO,MAAM,iBAAiB,iBAAiB,CAAC;AAEhD,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,CAAA;SAAE,GAAG,IAAI,CAAC,CAAC;QAChG,yEAAyE;QACzE,GAAG,CACD,IAAI,EAAE,UAAU,GAAG,cAAc,CAAC,UAAU,CAAC,EAC7C,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAC;YAAC,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,GAChD,OAAO,CAAC;YAAE,EAAE,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAC;YAAC,IAAI,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACxD,CAAC;CACH;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,GAAG,EAAE,SAAS,GAAG,aAAa,CAQvD"}
|
package/dist/well-known.js
CHANGED
|
@@ -3,18 +3,14 @@
|
|
|
3
3
|
*
|
|
4
4
|
* mod-vault (secrets) and mod-store (blob attachments) are looked up by their
|
|
5
5
|
* well-known service keys, never imported — mod-email has no hard dependency
|
|
6
|
-
* on either. (
|
|
7
|
-
* future hoist to core would collapse the three.)
|
|
6
|
+
* on either. (VaultLike now lives in core; BlobStoreLike stays local.)
|
|
8
7
|
*/
|
|
9
8
|
/** Driver registry + account-resolving send/test (the contract surface). */
|
|
10
9
|
export const EMAIL_SERVICE = "emailService";
|
|
11
10
|
/** Persisted email accounts (.pattern-data/email-config.json). */
|
|
12
11
|
export const EMAIL_CONFIG_SERVICE = "emailConfig";
|
|
13
|
-
/* ── vault (secrets)
|
|
14
|
-
export
|
|
15
|
-
export function vaultLike(ctx) {
|
|
16
|
-
return ctx.services[VAULT_SERVICE_KEY];
|
|
17
|
-
}
|
|
12
|
+
/* ── vault (secrets) — hoisted to core; re-exported for existing importers ── */
|
|
13
|
+
export { VAULT_SERVICE_KEY, vaultLike } from "@pattern-js/core";
|
|
18
14
|
/* ── store (blob attachments) ──────────────────────────────────────────── */
|
|
19
15
|
export const STORE_SERVICE_KEY = "storeService";
|
|
20
16
|
/** Only reached when a MediaRef attachment is wired — hence the lazy throw. */
|
package/dist/well-known.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"well-known.js","sourceRoot":"","sources":["../src/well-known.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"well-known.js","sourceRoot":"","sources":["../src/well-known.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,4EAA4E;AAC5E,MAAM,CAAC,MAAM,aAAa,GAAG,cAAc,CAAC;AAC5C,kEAAkE;AAClE,MAAM,CAAC,MAAM,oBAAoB,GAAG,aAAa,CAAC;AAElD,iFAAiF;AAEjF,OAAO,EAAE,iBAAiB,EAAE,SAAS,EAAkB,MAAM,kBAAkB,CAAC;AAEhF,8EAA8E;AAE9E,MAAM,CAAC,MAAM,iBAAiB,GAAG,cAAc,CAAC;AAahD,+EAA+E;AAC/E,MAAM,UAAU,SAAS,CAAC,GAAc;IACtC,MAAM,GAAG,GAAG,GAAG,CAAC,QAAQ,CAAC,iBAAiB,CAA8B,CAAC;IACzE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CACb,0HAA0H,CAC3H,CAAC;IACJ,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
package/docs/index.md
CHANGED
|
@@ -83,6 +83,29 @@ The declared `secrets`/`options` fields drive the account form in admin — a
|
|
|
83
83
|
driver mod ships zero UI. `mod-email-resend` is the worked example to copy
|
|
84
84
|
(one fetch, ~60 lines).
|
|
85
85
|
|
|
86
|
+
## Receiving (0.4)
|
|
87
|
+
|
|
88
|
+
The contract also receives: a workflow starting with the **`email.inbound`
|
|
89
|
+
trigger** runs once per incoming message (`config.account` narrows to one
|
|
90
|
+
receiving account). The message carries from/to/cc, subject, text/html,
|
|
91
|
+
lower-cased headers, threading ids, and attachments **as blob references**
|
|
92
|
+
(bytes land in mod-store; without it the meta survives and the bytes are
|
|
93
|
+
dropped, loudly). No out-gate needed — the sender's mail server never reads
|
|
94
|
+
your run's result.
|
|
95
|
+
|
|
96
|
+
Delivery comes from a webhook driver. `mod-email-resend` ships a seeded route
|
|
97
|
+
at **POST `/email/inbound/resend`**: point your Resend inbound webhook there,
|
|
98
|
+
paste the `whsec_…` signing secret into the account's *Inbound webhook
|
|
99
|
+
secret* field, done. The route streams the RAW request bytes
|
|
100
|
+
(`bodyMode: "stream"`) because the svix signature covers them exactly —
|
|
101
|
+
verification is constant-time with a ±5 minute replay window, and bad
|
|
102
|
+
signatures bounce with 401 before anything runs.
|
|
103
|
+
|
|
104
|
+
**`email.reply`** closes the loop: wire the inbound `message` in and it
|
|
105
|
+
derives the recipient (reply-to, else sender), prefixes `Re:` exactly once,
|
|
106
|
+
and sets In-Reply-To/References so mail clients thread the exchange — the
|
|
107
|
+
whole email-in → agent → email-out demo is three nodes.
|
|
108
|
+
|
|
86
109
|
## Config
|
|
87
110
|
|
|
88
111
|
Defaults work from the bare config entry. The accounts file lives at
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
The inbound email trigger: a workflow starting here runs once per received
|
|
2
|
+
message. Set `config.account` to listen to one receiving account, or leave it
|
|
3
|
+
empty for every account. Outputs `{ message, account }` — `message` carries
|
|
4
|
+
from/to/cc, subject, text/html bodies, lower-cased headers, threading ids
|
|
5
|
+
(messageId, inReplyTo, references) and `attachments` as blob references
|
|
6
|
+
(`{ blobId, filename, mime, size }`; bytes need mod-store).
|
|
7
|
+
|
|
8
|
+
Fire-and-forget by design: the sender's mail server never reads your run's
|
|
9
|
+
result, so an out-gate is optional — add `boundary.return` only to record an
|
|
10
|
+
outcome on the run. Delivery comes from a webhook driver
|
|
11
|
+
(`@pattern-js/mod-email-resend` ships one, signature-verified); pair with
|
|
12
|
+
`email.reply` for properly threaded answers.
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Reply to an inbound message with real threading: wire `message` straight from
|
|
2
|
+
an `email.inbound` trigger and this op derives everything — the recipient
|
|
3
|
+
(the original's reply-to header, else its sender), the subject (`Re: `
|
|
4
|
+
prefixed once, never `Re: Re:`), and the RFC-5322 threading headers
|
|
5
|
+
(In-Reply-To = the original's message id; References = its references + that
|
|
6
|
+
id), so mail clients stack the exchange as one conversation.
|
|
7
|
+
|
|
8
|
+
Write the body once in `markdown` (rendered to styled HTML + a plain-text
|
|
9
|
+
alternative) or pass explicit `html`/`text`. Sends through the account the
|
|
10
|
+
message arrived on unless `config.account` says otherwise.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pattern-js/mod-email",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-main.c8eb671",
|
|
4
4
|
"description": "Transactional email for Pattern — the contract mod. Admin-configured accounts (provider + sourced secrets + from), driver mods plug in (Resend, SMTP, …), one email.send op, and a packaged workflow that delivers identity sign-in links the moment a default account exists.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pattern",
|
|
@@ -27,14 +27,14 @@
|
|
|
27
27
|
],
|
|
28
28
|
"dependencies": {
|
|
29
29
|
"zod": "^4.0.0",
|
|
30
|
-
"@pattern-js/
|
|
31
|
-
"@pattern-js/
|
|
30
|
+
"@pattern-js/core": "0.4.0-main.c8eb671",
|
|
31
|
+
"@pattern-js/runtime-node": "0.4.0-main.c8eb671"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"@types/node": "^22.0.0",
|
|
35
35
|
"typescript": "^5.6.0",
|
|
36
|
-
"@pattern-js/mod-identity": "0.
|
|
37
|
-
"@pattern-js/mod-auth-magic-link": "0.
|
|
36
|
+
"@pattern-js/mod-identity": "0.4.0-main.c8eb671",
|
|
37
|
+
"@pattern-js/mod-auth-magic-link": "0.4.0-main.c8eb671"
|
|
38
38
|
},
|
|
39
39
|
"engines": {
|
|
40
40
|
"node": ">=22.5"
|