@agent-native/core 0.26.9 → 0.27.0
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/agent/run-ownership.d.ts +12 -0
- package/dist/agent/run-ownership.d.ts.map +1 -0
- package/dist/agent/run-ownership.js +39 -0
- package/dist/agent/run-ownership.js.map +1 -0
- package/dist/client/db-admin/DataGrid.d.ts +42 -0
- package/dist/client/db-admin/DataGrid.d.ts.map +1 -0
- package/dist/client/db-admin/DataGrid.js +204 -0
- package/dist/client/db-admin/DataGrid.js.map +1 -0
- package/dist/client/db-admin/DbAdminPage.d.ts +2 -0
- package/dist/client/db-admin/DbAdminPage.d.ts.map +1 -0
- package/dist/client/db-admin/DbAdminPage.js +72 -0
- package/dist/client/db-admin/DbAdminPage.js.map +1 -0
- package/dist/client/db-admin/DevDatabaseLink.d.ts +19 -0
- package/dist/client/db-admin/DevDatabaseLink.d.ts.map +1 -0
- package/dist/client/db-admin/DevDatabaseLink.js +25 -0
- package/dist/client/db-admin/DevDatabaseLink.js.map +1 -0
- package/dist/client/db-admin/EditableCell.d.ts +26 -0
- package/dist/client/db-admin/EditableCell.d.ts.map +1 -0
- package/dist/client/db-admin/EditableCell.js +150 -0
- package/dist/client/db-admin/EditableCell.js.map +1 -0
- package/dist/client/db-admin/FilterBar.d.ts +8 -0
- package/dist/client/db-admin/FilterBar.d.ts.map +1 -0
- package/dist/client/db-admin/FilterBar.js +68 -0
- package/dist/client/db-admin/FilterBar.js.map +1 -0
- package/dist/client/db-admin/ResultsGrid.d.ts +6 -0
- package/dist/client/db-admin/ResultsGrid.d.ts.map +1 -0
- package/dist/client/db-admin/ResultsGrid.js +41 -0
- package/dist/client/db-admin/ResultsGrid.js.map +1 -0
- package/dist/client/db-admin/RowSidePanel.d.ts +18 -0
- package/dist/client/db-admin/RowSidePanel.d.ts.map +1 -0
- package/dist/client/db-admin/RowSidePanel.js +104 -0
- package/dist/client/db-admin/RowSidePanel.js.map +1 -0
- package/dist/client/db-admin/SqlEditor.d.ts +8 -0
- package/dist/client/db-admin/SqlEditor.d.ts.map +1 -0
- package/dist/client/db-admin/SqlEditor.js +350 -0
- package/dist/client/db-admin/SqlEditor.js.map +1 -0
- package/dist/client/db-admin/TableBrowser.d.ts +10 -0
- package/dist/client/db-admin/TableBrowser.d.ts.map +1 -0
- package/dist/client/db-admin/TableBrowser.js +61 -0
- package/dist/client/db-admin/TableBrowser.js.map +1 -0
- package/dist/client/db-admin/TableEditor.d.ts +9 -0
- package/dist/client/db-admin/TableEditor.d.ts.map +1 -0
- package/dist/client/db-admin/TableEditor.js +254 -0
- package/dist/client/db-admin/TableEditor.js.map +1 -0
- package/dist/client/db-admin/cell-format.d.ts +55 -0
- package/dist/client/db-admin/cell-format.d.ts.map +1 -0
- package/dist/client/db-admin/cell-format.js +223 -0
- package/dist/client/db-admin/cell-format.js.map +1 -0
- package/dist/client/db-admin/changeset.d.ts +74 -0
- package/dist/client/db-admin/changeset.d.ts.map +1 -0
- package/dist/client/db-admin/changeset.js +169 -0
- package/dist/client/db-admin/changeset.js.map +1 -0
- package/dist/client/db-admin/export-utils.d.ts +15 -0
- package/dist/client/db-admin/export-utils.d.ts.map +1 -0
- package/dist/client/db-admin/export-utils.js +62 -0
- package/dist/client/db-admin/export-utils.js.map +1 -0
- package/dist/client/db-admin/index.d.ts +7 -0
- package/dist/client/db-admin/index.d.ts.map +1 -0
- package/dist/client/db-admin/index.js +8 -0
- package/dist/client/db-admin/index.js.map +1 -0
- package/dist/client/db-admin/sql-storage.d.ts +35 -0
- package/dist/client/db-admin/sql-storage.d.ts.map +1 -0
- package/dist/client/db-admin/sql-storage.js +117 -0
- package/dist/client/db-admin/sql-storage.js.map +1 -0
- package/dist/client/db-admin/storage.d.ts +24 -0
- package/dist/client/db-admin/storage.d.ts.map +1 -0
- package/dist/client/db-admin/storage.js +50 -0
- package/dist/client/db-admin/storage.js.map +1 -0
- package/dist/client/db-admin/useAgentSync.d.ts +22 -0
- package/dist/client/db-admin/useAgentSync.d.ts.map +1 -0
- package/dist/client/db-admin/useAgentSync.js +120 -0
- package/dist/client/db-admin/useAgentSync.js.map +1 -0
- package/dist/client/db-admin/useDbAdmin.d.ts +20 -0
- package/dist/client/db-admin/useDbAdmin.d.ts.map +1 -0
- package/dist/client/db-admin/useDbAdmin.js +154 -0
- package/dist/client/db-admin/useDbAdmin.js.map +1 -0
- package/dist/client/index.d.ts +1 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +1 -0
- package/dist/client/index.js.map +1 -1
- package/dist/credentials/index.d.ts.map +1 -1
- package/dist/credentials/index.js +25 -5
- package/dist/credentials/index.js.map +1 -1
- package/dist/db-admin/agent-tools.d.ts +15 -0
- package/dist/db-admin/agent-tools.d.ts.map +1 -0
- package/dist/db-admin/agent-tools.js +147 -0
- package/dist/db-admin/agent-tools.js.map +1 -0
- package/dist/db-admin/operations.d.ts +17 -0
- package/dist/db-admin/operations.d.ts.map +1 -0
- package/dist/db-admin/operations.js +541 -0
- package/dist/db-admin/operations.js.map +1 -0
- package/dist/db-admin/routes.d.ts +5 -0
- package/dist/db-admin/routes.d.ts.map +1 -0
- package/dist/db-admin/routes.js +134 -0
- package/dist/db-admin/routes.js.map +1 -0
- package/dist/db-admin/types.d.ts +85 -0
- package/dist/db-admin/types.d.ts.map +1 -0
- package/dist/db-admin/types.js +9 -0
- package/dist/db-admin/types.js.map +1 -0
- package/dist/extensions/url-safety.d.ts +20 -0
- package/dist/extensions/url-safety.d.ts.map +1 -1
- package/dist/extensions/url-safety.js +43 -0
- package/dist/extensions/url-safety.js.map +1 -1
- package/dist/file-upload/actions/upload-image.d.ts.map +1 -1
- package/dist/file-upload/actions/upload-image.js +6 -1
- package/dist/file-upload/actions/upload-image.js.map +1 -1
- package/dist/integrations/adapters/email.d.ts.map +1 -1
- package/dist/integrations/adapters/email.js +112 -0
- package/dist/integrations/adapters/email.js.map +1 -1
- package/dist/integrations/types.d.ts +11 -0
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/scripts/db/exec.d.ts.map +1 -1
- package/dist/scripts/db/exec.js +2 -1
- package/dist/scripts/db/exec.js.map +1 -1
- package/dist/scripts/db/index.d.ts.map +1 -1
- package/dist/scripts/db/index.js +1 -0
- package/dist/scripts/db/index.js.map +1 -1
- package/dist/scripts/db/migrate-encrypt-credentials.d.ts +28 -0
- package/dist/scripts/db/migrate-encrypt-credentials.d.ts.map +1 -0
- package/dist/scripts/db/migrate-encrypt-credentials.js +190 -0
- package/dist/scripts/db/migrate-encrypt-credentials.js.map +1 -0
- package/dist/scripts/db/query.d.ts.map +1 -1
- package/dist/scripts/db/query.js +2 -1
- package/dist/scripts/db/query.js.map +1 -1
- package/dist/scripts/db/safety.d.ts +1 -0
- package/dist/scripts/db/safety.d.ts.map +1 -1
- package/dist/scripts/db/safety.js +32 -0
- package/dist/scripts/db/safety.js.map +1 -1
- package/dist/scripts/db/scoping.d.ts.map +1 -1
- package/dist/scripts/db/scoping.js +11 -1
- package/dist/scripts/db/scoping.js.map +1 -1
- package/dist/secrets/crypto.d.ts +28 -0
- package/dist/secrets/crypto.d.ts.map +1 -0
- package/dist/secrets/crypto.js +81 -0
- package/dist/secrets/crypto.js.map +1 -0
- package/dist/secrets/storage.d.ts.map +1 -1
- package/dist/secrets/storage.js +3 -61
- package/dist/secrets/storage.js.map +1 -1
- package/dist/server/action-discovery.d.ts.map +1 -1
- package/dist/server/action-discovery.js +5 -2
- package/dist/server/action-discovery.js.map +1 -1
- package/dist/server/action-routes.d.ts.map +1 -1
- package/dist/server/action-routes.js +24 -7
- package/dist/server/action-routes.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +39 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js.map +1 -1
- package/dist/server/better-auth-instance.js +3 -3
- package/dist/server/better-auth-instance.js.map +1 -1
- package/dist/server/core-routes-plugin.d.ts.map +1 -1
- package/dist/server/core-routes-plugin.js +5 -0
- package/dist/server/core-routes-plugin.js.map +1 -1
- package/dist/server/csrf.d.ts.map +1 -1
- package/dist/server/csrf.js +9 -1
- package/dist/server/csrf.js.map +1 -1
- package/dist/server/design-token-utils.d.ts +8 -1
- package/dist/server/design-token-utils.d.ts.map +1 -1
- package/dist/server/design-token-utils.js +12 -4
- package/dist/server/design-token-utils.js.map +1 -1
- package/dist/templates/default/AGENTS.md +4 -4
- package/dist/templates/default/app/routes/database.tsx +13 -0
- package/dist/templates/workspace-core/.agents/skills/authentication/SKILL.md +9 -2
- package/dist/templates/workspace-core/.agents/skills/sharing/SKILL.md +7 -1
- package/dist/vite/client.d.ts.map +1 -1
- package/dist/vite/client.js +4 -0
- package/dist/vite/client.js.map +1 -1
- package/docs/content/a2a-protocol.md +2 -2
- package/docs/content/actions.md +2 -54
- package/docs/content/agent-mentions.md +1 -1
- package/docs/content/agent-teams.md +1 -1
- package/docs/content/authentication.md +2 -2
- package/docs/content/cli-adapters.md +33 -17
- package/docs/content/client.md +11 -20
- package/docs/content/code-agents-ui.md +19 -6
- package/docs/content/context-awareness.md +36 -20
- package/docs/content/database.md +3 -3
- package/docs/content/deployment.md +8 -8
- package/docs/content/dispatch.md +1 -1
- package/docs/content/external-agents.md +5 -1
- package/docs/content/faq.md +1 -0
- package/docs/content/frames.md +110 -30
- package/docs/content/getting-started.md +15 -14
- package/docs/content/mcp-clients.md +1 -1
- package/docs/content/mcp-protocol.md +11 -88
- package/docs/content/messaging.md +1 -1
- package/docs/content/migration-workbench.md +13 -87
- package/docs/content/multi-app-workspace.md +2 -38
- package/docs/content/multi-tenancy.md +3 -26
- package/docs/content/onboarding.md +10 -3
- package/docs/content/recurring-jobs.md +2 -2
- package/docs/content/security.md +33 -1
- package/docs/content/server.md +1 -1
- package/docs/content/template-assets.md +9 -9
- package/docs/content/template-brain.md +114 -388
- package/docs/content/template-clips.md +42 -2
- package/docs/content/template-content.md +1 -1
- package/docs/content/template-design.md +27 -0
- package/docs/content/template-dispatch.md +3 -3
- package/docs/content/template-forms.md +6 -6
- package/docs/content/template-starter.md +2 -2
- package/docs/content/using-your-agent.md +56 -0
- package/docs/content/workspace-management.md +6 -6
- package/docs/content/workspace.md +19 -0
- package/package.json +10 -3
- package/src/templates/default/AGENTS.md +4 -4
- package/src/templates/default/app/routes/database.tsx +13 -0
- package/src/templates/workspace-core/.agents/skills/authentication/SKILL.md +9 -2
- package/src/templates/workspace-core/.agents/skills/sharing/SKILL.md +7 -1
|
@@ -167,6 +167,11 @@ export function emailAdapter() {
|
|
|
167
167
|
text: bodyText,
|
|
168
168
|
senderName: parsed.from.name,
|
|
169
169
|
senderId: senderEmail,
|
|
170
|
+
// Carry the message-authentication verdict downstream. Owner
|
|
171
|
+
// resolution (dispatch) must NOT grant a real user's identity /
|
|
172
|
+
// credentials unless the sender is verified — an unverified or
|
|
173
|
+
// spoofed `From:` falls back to a synthetic, credential-less owner.
|
|
174
|
+
senderVerified: parsed.senderVerified,
|
|
170
175
|
platformContext: {
|
|
171
176
|
messageId: parsed.messageId,
|
|
172
177
|
subject: parsed.subject,
|
|
@@ -176,6 +181,7 @@ export function emailAdapter() {
|
|
|
176
181
|
inReplyTo: parsed.inReplyTo,
|
|
177
182
|
references: parsed.references,
|
|
178
183
|
isCC,
|
|
184
|
+
senderVerified: parsed.senderVerified,
|
|
179
185
|
},
|
|
180
186
|
timestamp: parsed.date ? new Date(parsed.date).getTime() : Date.now(),
|
|
181
187
|
};
|
|
@@ -393,6 +399,15 @@ async function parseResendWebhook(event) {
|
|
|
393
399
|
// Parse headers for Message-ID, In-Reply-To, References
|
|
394
400
|
const headers = parseHeadersObject(data.headers);
|
|
395
401
|
const messageId = headers["message-id"] || data.email_id || `resend-${Date.now()}`;
|
|
402
|
+
// Resend forwards the raw `Authentication-Results` header (and may also
|
|
403
|
+
// surface explicit `dkim`/`spf` fields). Derive a verified verdict from
|
|
404
|
+
// whichever is present; absent results fail closed (unverified).
|
|
405
|
+
const senderVerified = computeSenderVerified({
|
|
406
|
+
fromEmail: from.email,
|
|
407
|
+
authResults: headers["authentication-results"],
|
|
408
|
+
dkim: typeof data.dkim === "string" ? data.dkim : undefined,
|
|
409
|
+
spf: typeof data.spf === "string" ? data.spf : undefined,
|
|
410
|
+
});
|
|
396
411
|
return {
|
|
397
412
|
messageId,
|
|
398
413
|
subject: data.subject || "(no subject)",
|
|
@@ -404,6 +419,7 @@ async function parseResendWebhook(event) {
|
|
|
404
419
|
inReplyTo: headers["in-reply-to"] || undefined,
|
|
405
420
|
references: parseReferencesHeader(headers["references"]),
|
|
406
421
|
date: data.created_at || undefined,
|
|
422
|
+
senderVerified,
|
|
407
423
|
};
|
|
408
424
|
}
|
|
409
425
|
async function parseSendGridWebhook(event) {
|
|
@@ -425,6 +441,16 @@ async function parseSendGridWebhook(event) {
|
|
|
425
441
|
const headersStr = body.headers;
|
|
426
442
|
const headers = parseHeadersString(headersStr);
|
|
427
443
|
const messageId = headers["message-id"] || `sendgrid-${Date.now()}`;
|
|
444
|
+
// SendGrid Inbound Parse posts explicit `dkim` (e.g. `{@example.com : pass}`)
|
|
445
|
+
// and `SPF` (e.g. `pass`) form fields, and also carries
|
|
446
|
+
// `Authentication-Results` inside the raw headers blob. Use all available
|
|
447
|
+
// signals; absent results fail closed (unverified).
|
|
448
|
+
const senderVerified = computeSenderVerified({
|
|
449
|
+
fromEmail: from.email,
|
|
450
|
+
authResults: headers["authentication-results"],
|
|
451
|
+
dkim: typeof body.dkim === "string" ? body.dkim : undefined,
|
|
452
|
+
spf: typeof body.SPF === "string" ? body.SPF : undefined,
|
|
453
|
+
});
|
|
428
454
|
return {
|
|
429
455
|
messageId,
|
|
430
456
|
subject: body.subject || "(no subject)",
|
|
@@ -436,9 +462,95 @@ async function parseSendGridWebhook(event) {
|
|
|
436
462
|
inReplyTo: headers["in-reply-to"] || undefined,
|
|
437
463
|
references: parseReferencesHeader(headers["references"]),
|
|
438
464
|
date: headers["date"] || undefined,
|
|
465
|
+
senderVerified,
|
|
439
466
|
};
|
|
440
467
|
}
|
|
441
468
|
// ---------------------------------------------------------------------------
|
|
469
|
+
// Helpers — sender authentication (DKIM / SPF)
|
|
470
|
+
// ---------------------------------------------------------------------------
|
|
471
|
+
/**
|
|
472
|
+
* Extract the registrable-ish domain from an email address (lowercased).
|
|
473
|
+
* We keep the full host rather than collapsing to an eTLD+1 — exact-domain
|
|
474
|
+
* alignment is the conservative choice here, and avoids bundling a public
|
|
475
|
+
* suffix list. Subdomain senders that legitimately DKIM-sign with the parent
|
|
476
|
+
* domain are handled by the suffix check in `domainsAlign`.
|
|
477
|
+
*/
|
|
478
|
+
function emailDomain(email) {
|
|
479
|
+
const at = email.lastIndexOf("@");
|
|
480
|
+
return at >= 0
|
|
481
|
+
? email
|
|
482
|
+
.slice(at + 1)
|
|
483
|
+
.trim()
|
|
484
|
+
.toLowerCase()
|
|
485
|
+
: "";
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* True when `signingDomain` is the From domain or a parent of it (e.g.
|
|
489
|
+
* From `user@mail.example.com` aligned with a `d=example.com` signature).
|
|
490
|
+
* Both directions of subdomain nesting are accepted because senders sign
|
|
491
|
+
* with either the exact From host or the organizational parent.
|
|
492
|
+
*/
|
|
493
|
+
function domainsAlign(fromDomain, signingDomain) {
|
|
494
|
+
if (!fromDomain || !signingDomain)
|
|
495
|
+
return false;
|
|
496
|
+
if (fromDomain === signingDomain)
|
|
497
|
+
return true;
|
|
498
|
+
return (fromDomain.endsWith(`.${signingDomain}`) ||
|
|
499
|
+
signingDomain.endsWith(`.${fromDomain}`));
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Compute whether an inbound email is authenticated as genuinely coming from
|
|
503
|
+
* its `From:` domain. Returns true only when DKIM passes for an aligned
|
|
504
|
+
* domain, or SPF passes for an aligned domain. Anything else — missing
|
|
505
|
+
* results, `fail`, `softfail`, `none`, `neutral`, `temperror`, `permerror`
|
|
506
|
+
* — returns false (fail closed).
|
|
507
|
+
*
|
|
508
|
+
* Inputs may come from provider-specific fields (`dkim`, `spf`) and/or the
|
|
509
|
+
* RFC 8601 `Authentication-Results` header, in any combination. We treat the
|
|
510
|
+
* union: if ANY source shows an aligned pass, the sender is verified.
|
|
511
|
+
*/
|
|
512
|
+
function computeSenderVerified(input) {
|
|
513
|
+
const fromDomain = emailDomain(input.fromEmail);
|
|
514
|
+
if (!fromDomain)
|
|
515
|
+
return false;
|
|
516
|
+
// 1. Provider DKIM field, e.g. SendGrid `{@example.com : pass}` or
|
|
517
|
+
// `{@example.com : pass; @other.com : fail}`.
|
|
518
|
+
if (input.dkim) {
|
|
519
|
+
const dkimEntries = input.dkim.matchAll(/@([a-z0-9.-]+)\s*:\s*(pass|fail|none|neutral|softfail|temperror|permerror)/gi);
|
|
520
|
+
for (const m of dkimEntries) {
|
|
521
|
+
const domain = m[1].toLowerCase();
|
|
522
|
+
const verdict = m[2].toLowerCase();
|
|
523
|
+
if (verdict === "pass" && domainsAlign(fromDomain, domain))
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
// 2. Provider SPF field. SendGrid posts a bare verdict (e.g. `pass`); since
|
|
528
|
+
// SPF authenticates the envelope/MailFrom rather than the header From,
|
|
529
|
+
// a bare `pass` with no domain only counts when we can't tell it's
|
|
530
|
+
// misaligned. We accept a bare `pass` as an aligned SPF pass — this is
|
|
531
|
+
// the same trust level Gmail-style routing assigns to a plain SPF pass.
|
|
532
|
+
if (input.spf) {
|
|
533
|
+
const spfVerdict = input.spf.trim().toLowerCase();
|
|
534
|
+
if (spfVerdict === "pass")
|
|
535
|
+
return true;
|
|
536
|
+
}
|
|
537
|
+
// 3. RFC 8601 `Authentication-Results` header (may list multiple methods).
|
|
538
|
+
if (input.authResults) {
|
|
539
|
+
const ar = input.authResults.toLowerCase();
|
|
540
|
+
// DKIM with an aligned domain.
|
|
541
|
+
const dkimRe = /dkim=pass[^;]*?(?:header\.(?:d|i)=|@)([a-z0-9.-]+)/g;
|
|
542
|
+
for (const m of ar.matchAll(dkimRe)) {
|
|
543
|
+
const domain = m[1].replace(/^@/, "");
|
|
544
|
+
if (domainsAlign(fromDomain, domain))
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
// SPF pass (envelope auth) — accept as an aligned pass.
|
|
548
|
+
if (/spf=pass\b/.test(ar))
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
return false;
|
|
552
|
+
}
|
|
553
|
+
// ---------------------------------------------------------------------------
|
|
442
554
|
// Rate limiting
|
|
443
555
|
// ---------------------------------------------------------------------------
|
|
444
556
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../../src/integrations/adapters/email.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport { getHeader, readRawBody as h3ReadRawBody } from \"h3\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type {\n PlatformAdapter,\n IncomingMessage,\n OutgoingMessage,\n IntegrationStatus,\n OutboundTarget,\n} from \"../types.js\";\nimport type { EnvKeyConfig } from \"../../server/create-server.js\";\nimport { getIntegrationConfig } from \"../config-store.js\";\nimport { getDbExec } from \"../../db/client.js\";\nimport {\n sendEmail,\n isEmailConfigured,\n getEmailProvider,\n} from \"../../server/email.js\";\n\n/** Max body length before truncation */\nconst EMAIL_MAX_BODY_LENGTH = 15000;\n\n/** Rate limit: max emails per sender within the window */\nconst RATE_LIMIT_MAX = 20;\n/** Rate limit window in ms (1 hour) */\nconst RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000;\n\n/**\n * One-shot warning flags so we don't spam logs on every webhook.\n * Cleared per process — one warning per cold start is enough to surface\n * a misconfiguration without leaking config status to anyone with log access\n * (M6 in the webhook security audit).\n */\nlet _resendUnverifiedWarned = false;\nlet _sendgridUnverifiedWarned = false;\n\n/**\n * Returns true when the deployment is running in production mode and the\n * operator has NOT explicitly opted into accepting unverified webhooks for\n * local testing. In production we MUST refuse webhooks whose signature can't\n * be verified — accepting them with attacker-controlled `from:` addresses\n * lets the dispatch owner-resolution path run as the victim (C1 in the\n * webhook security audit).\n */\nfunction shouldRefuseWhenSecretMissing(): boolean {\n if (process.env.AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS === \"1\") return false;\n return process.env.NODE_ENV === \"production\";\n}\n\n/**\n * Create an Email platform adapter for inbound/outbound email via\n * Resend or SendGrid webhooks.\n *\n * Required env vars:\n * - EMAIL_AGENT_ADDRESS — The email address the agent receives mail at\n *\n * One of these must also be set (checked via isEmailConfigured()):\n * - RESEND_API_KEY — For sending/receiving via Resend\n * - SENDGRID_API_KEY — For sending/receiving via SendGrid\n *\n * Optional:\n * - EMAIL_INBOUND_WEBHOOK_SECRET — Webhook signature verification secret\n */\nexport function emailAdapter(): PlatformAdapter {\n return {\n platform: \"email\",\n label: \"Email\",\n\n getRequiredEnvKeys(): EnvKeyConfig[] {\n return [\n {\n key: \"EMAIL_AGENT_ADDRESS\",\n label: \"Agent Email Address\",\n required: true,\n helpText:\n \"The email address people will use to message your agent (e.g. `agent@yourcompany.com`, or pick from your `<slug>.resend.app` sandbox).\",\n },\n {\n key: \"RESEND_API_KEY\",\n label: \"Resend API Key\",\n required: false,\n helpText:\n \"From resend.com → API keys (starts with `re_`). Either Resend or SendGrid is required for sending and receiving mail.\",\n },\n {\n key: \"SENDGRID_API_KEY\",\n label: \"SendGrid API Key\",\n required: false,\n helpText:\n \"From sendgrid.com → Settings → API Keys (starts with `SG.`). Either Resend or SendGrid is required.\",\n },\n {\n key: \"EMAIL_INBOUND_WEBHOOK_SECRET\",\n label: \"Inbound Webhook Secret\",\n required: false,\n helpText:\n \"Optional. From Resend (Webhooks → Signing Secret, starts with `whsec_`) or your SendGrid Inbound Parse basic-auth password. Used to verify inbound webhooks are real.\",\n },\n ];\n },\n\n async handleVerification(\n _event: H3Event,\n ): Promise<{ handled: boolean; response?: unknown }> {\n // Email webhooks don't need challenge handshakes\n return { handled: false };\n },\n\n async verifyWebhook(event: H3Event): Promise<boolean> {\n const secret = process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const provider = getEmailProvider();\n\n if (provider === \"resend\") {\n return verifyResendWebhook(event, secret);\n }\n\n if (provider === \"sendgrid\") {\n return verifySendGridWebhook(event, secret);\n }\n\n // No provider configured — reject\n console.warn(\"[email] No email provider configured, rejecting webhook\");\n return false;\n },\n\n async parseIncomingMessage(\n event: H3Event,\n ): Promise<IncomingMessage | null> {\n const provider = getEmailProvider();\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n if (!agentAddress) {\n console.warn(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return null;\n }\n\n let parsed: ParsedEmail | null = null;\n\n if (provider === \"resend\") {\n parsed = await parseResendWebhook(event);\n } else if (provider === \"sendgrid\") {\n parsed = await parseSendGridWebhook(event);\n }\n\n if (!parsed) return null;\n\n // Rate limiting (SQL-backed heuristic — counts the sender's already-queued\n // tasks within the last hour). The previous in-memory map reset on every\n // serverless cold start, so the actual ceiling per attacker was\n // RATE_LIMIT_MAX × number_of_active_instances. SQL-backed counting holds\n // across instances. See H4 in the webhook security audit.\n const senderEmail = parsed.from.email.toLowerCase();\n if (await isRateLimited(senderEmail)) {\n console.warn(\n `[email] Rate limited sender: ${senderEmail} (>${RATE_LIMIT_MAX}/hr)`,\n );\n return null;\n }\n\n // Check allowed domains\n const config = await getIntegrationConfig(\"email\");\n if (config?.configData?.allowedDomains) {\n const allowed = config.configData.allowedDomains as string[];\n if (allowed.length > 0) {\n const senderDomain = senderEmail.split(\"@\")[1];\n if (!senderDomain || !allowed.includes(senderDomain)) {\n console.warn(\n `[email] Rejected email from ${senderEmail}: domain not in allowedDomains`,\n );\n return null;\n }\n }\n }\n\n // Determine if agent was CC'd (not in To, but in CC)\n const toAddresses = parsed.to.map((a) => a.toLowerCase());\n const ccAddresses = (parsed.cc ?? []).map((a) => a.toLowerCase());\n const isCC =\n !toAddresses.includes(agentAddress) &&\n ccAddresses.includes(agentAddress);\n\n // Build thread ID from References chain (Gmail-style: oldest Message-ID is thread root).\n // Scope the thread root by sender so an attacker who can forge a `References:`\n // header pointing at someone else's thread root can't graft into that thread.\n // Without this scoping, a third party could craft an inbound email whose\n // References chain matches a known victim's Message-ID and inject messages into\n // the victim's existing conversation — leaking prior content via the agent's\n // reply (M1 in the webhooks security audit).\n const threadRootId = scopeThreadIdToSender(\n getThreadRootId(parsed.messageId, parsed.references),\n senderEmail,\n );\n\n // Build body text\n let bodyText = parsed.text || stripHtmlForPlainText(parsed.html || \"\");\n\n // Truncate if needed\n if (bodyText.length > EMAIL_MAX_BODY_LENGTH) {\n bodyText =\n bodyText.slice(0, EMAIL_MAX_BODY_LENGTH) + \"\\n[Message truncated]\";\n }\n\n // Prefix CC'd emails with context\n if (isCC) {\n const otherRecipients = toAddresses\n .filter((a) => a !== agentAddress)\n .join(\", \");\n bodyText =\n `[CC'd on email between ${senderEmail} and ${otherRecipients || \"others\"}]\\n` +\n `Subject: ${parsed.subject}\\n\\n` +\n bodyText;\n }\n\n return {\n platform: \"email\",\n externalThreadId: threadRootId,\n text: bodyText,\n senderName: parsed.from.name,\n senderId: senderEmail,\n platformContext: {\n messageId: parsed.messageId,\n subject: parsed.subject,\n from: senderEmail,\n to: parsed.to,\n cc: parsed.cc,\n inReplyTo: parsed.inReplyTo,\n references: parsed.references,\n isCC,\n },\n timestamp: parsed.date ? new Date(parsed.date).getTime() : Date.now(),\n };\n },\n\n async sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n // EMAIL_FROM overrides the from-address — required when the receiving\n // address is on a sub-domain that can't be a verified sender (e.g.\n // *.resend.app). Inbound and outbound addresses can differ.\n const fromAddress = process.env.EMAIL_FROM\n ? process.env.EMAIL_FROM\n : `${displayName} <${agentAddress}>`;\n\n const subject = context.platformContext.subject as string;\n const reSubject = subject.startsWith(\"Re: \") ? subject : `Re: ${subject}`;\n\n try {\n await sendEmail({\n to: context.senderId!,\n from: fromAddress,\n subject: reSubject,\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n inReplyTo: context.platformContext.messageId as string,\n references: buildReferencesHeader(context.platformContext),\n cc: context.platformContext.isCC\n ? buildReplyAllCc(context)\n : undefined,\n });\n } catch (err) {\n console.error(\"[email] Failed to send response:\", err);\n }\n },\n\n async sendMessageToTarget(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n try {\n await sendEmail({\n to: target.destination,\n from: `${displayName} <${agentAddress}>`,\n subject: target.label || \"Message from Dispatch Agent\",\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n ...(target.threadRef\n ? {\n inReplyTo: target.threadRef,\n references: target.threadRef,\n }\n : {}),\n });\n } catch (err) {\n console.error(\"[email] Failed to send proactive message:\", err);\n throw err;\n }\n },\n\n formatAgentResponse(text: string): OutgoingMessage {\n const bodyHtml = markdownToHtml(text);\n const html = wrapInEmailTemplate(bodyHtml);\n return { text: html, platformContext: {} };\n },\n\n async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {\n const hasAgentAddress = !!process.env.EMAIL_AGENT_ADDRESS;\n const hasEmailProvider = isEmailConfigured();\n const hasWebhookSecret = !!process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const configured = hasAgentAddress && hasEmailProvider;\n\n return {\n platform: \"email\",\n label: \"Email\",\n enabled: false, // overridden by plugin\n configured,\n details: {\n hasAgentAddress,\n hasEmailProvider,\n hasWebhookSecret,\n provider: getEmailProvider(),\n },\n error: !configured\n ? \"Set EMAIL_AGENT_ADDRESS and either RESEND_API_KEY or SENDGRID_API_KEY\"\n : undefined,\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Parsed email shape\n// ---------------------------------------------------------------------------\n\ninterface ParsedEmail {\n messageId: string;\n subject: string;\n from: { name?: string; email: string };\n to: string[];\n cc?: string[];\n text?: string;\n html?: string;\n inReplyTo?: string;\n references?: string[];\n date?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook verification\n// ---------------------------------------------------------------------------\n\nasync function verifyResendWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing Resend webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting Resend webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n const svixId = getHeader(event, \"svix-id\");\n const svixTimestamp = getHeader(event, \"svix-timestamp\");\n const svixSignature = getHeader(event, \"svix-signature\");\n\n if (!svixId || !svixTimestamp || !svixSignature) {\n console.warn(\"[email] Missing Svix signature headers\");\n return false;\n }\n\n // Reject requests older than 5 minutes (replay protection)\n const ts = parseInt(svixTimestamp, 10);\n if (Math.abs(Date.now() / 1000 - ts) > 300) {\n console.warn(\"[email] Svix timestamp too old, rejecting\");\n return false;\n }\n\n const body = await readRawBody(event);\n const crypto = await import(\"node:crypto\");\n\n // Svix signing secret may be prefixed with \"whsec_\"\n const rawSecret = secret.startsWith(\"whsec_\") ? secret.slice(6) : secret;\n const secretBytes = Buffer.from(rawSecret, \"base64\");\n\n const signedContent = `${svixId}.${svixTimestamp}.${body}`;\n const expectedSignature = crypto\n .createHmac(\"sha256\", secretBytes)\n .update(signedContent)\n .digest(\"base64\");\n\n // Svix sends multiple signatures separated by spaces, each prefixed with \"v1,\"\n const signatures = svixSignature.split(\" \");\n for (const sig of signatures) {\n const sigValue = sig.startsWith(\"v1,\") ? sig.slice(3) : sig;\n try {\n if (\n crypto.timingSafeEqual(\n Buffer.from(expectedSignature),\n Buffer.from(sigValue),\n )\n ) {\n return true;\n }\n } catch {\n // Length mismatch — try next signature\n }\n }\n\n console.warn(\"[email] Svix signature verification failed\");\n return false;\n}\n\nfunction safeEq(a: string, b: string): boolean {\n const aBuf = Buffer.from(a);\n const bBuf = Buffer.from(b);\n if (aBuf.length !== bBuf.length) return false;\n return timingSafeEqual(aBuf, bBuf);\n}\n\nasync function verifySendGridWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing SendGrid webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting SendGrid webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n // Check for the secret in a custom header or basic auth\n const authHeader = getHeader(event, \"authorization\");\n if (authHeader) {\n // Basic auth: \"Basic base64(user:pass)\" — secret is the password\n if (authHeader.startsWith(\"Basic \")) {\n const decoded = Buffer.from(authHeader.slice(6), \"base64\").toString();\n const password = decoded.split(\":\")[1];\n if (password !== undefined && safeEq(password, secret)) return true;\n }\n }\n\n // Also check a custom header (common SendGrid Inbound Parse pattern)\n const customSecret = getHeader(event, \"x-webhook-secret\");\n if (customSecret !== undefined && safeEq(customSecret, secret)) return true;\n\n console.warn(\"[email] SendGrid webhook secret verification failed\");\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Inbound email parsing\n// ---------------------------------------------------------------------------\n\nasync function parseResendWebhook(event: H3Event): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body || body.type !== \"email.received\") return null;\n\n const data = body.data;\n if (!data) return null;\n\n // Resend webhook payload provides email metadata directly in data\n // Fields: from, to, cc, subject, text, html, headers, created_at\n const fromRaw = data.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = data.to as string | string[] | undefined;\n const to = normalizeAddressList(toRaw);\n const ccRaw = data.cc as string | string[] | undefined;\n const cc = normalizeAddressList(ccRaw);\n\n // Parse headers for Message-ID, In-Reply-To, References\n const headers = parseHeadersObject(data.headers);\n const messageId =\n headers[\"message-id\"] || data.email_id || `resend-${Date.now()}`;\n\n return {\n messageId,\n subject: (data.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: data.text as string | undefined,\n html: data.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: (data.created_at as string) || undefined,\n };\n}\n\nasync function parseSendGridWebhook(\n event: H3Event,\n): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body) return null;\n\n // SendGrid Inbound Parse sends form data with fields:\n // from, to, cc, subject, text, html, headers, envelope\n const fromRaw = body.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = body.to as string | undefined;\n const to = toRaw ? toRaw.split(\",\").map((a: string) => a.trim()) : [];\n const ccRaw = body.cc as string | undefined;\n const cc = ccRaw ? ccRaw.split(\",\").map((a: string) => a.trim()) : [];\n\n // Parse raw headers string\n const headersStr = body.headers as string | undefined;\n const headers = parseHeadersString(headersStr);\n const messageId = headers[\"message-id\"] || `sendgrid-${Date.now()}`;\n\n return {\n messageId,\n subject: (body.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: body.text as string | undefined,\n html: body.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: headers[\"date\"] || undefined,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Rate limiting\n// ---------------------------------------------------------------------------\n\n/**\n * Rate-limit heuristic backed by the `integration_pending_tasks` queue.\n *\n * Counts how many tasks this sender has produced in the last hour. The count\n * INCLUDES tasks already processed (status = completed/failed) because the\n * rows aren't deleted on completion — that's enough signal to throttle a\n * single noisy/abusive sender without needing a dedicated counter table.\n *\n * Two trade-offs worth knowing:\n * - This is a coarse heuristic, not exact metering. Within one hour the\n * count is correct; rows produced more than an hour ago naturally drop\n * off. We don't try to be precise, only to raise the bar past the\n * \"send 10K emails through one Lambda burst\" failure mode.\n * - The query relies on the `idx_pending_tasks_status_created` index plus\n * a sender substring match. A targeted attacker could amortise the cost\n * by reusing one sender address — that's fine, the goal here is to bound\n * the attack within a single attacker identity, not to detect spoofing.\n *\n * If the table doesn't yet exist on this deployment (no inbound webhook has\n * been processed before), we silently allow the message — the schema is\n * provisioned on first task insert. See H4 in the webhook security audit.\n */\nasync function isRateLimited(senderEmail: string): Promise<boolean> {\n const cutoff = Date.now() - RATE_LIMIT_WINDOW_MS;\n try {\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `\n SELECT COUNT(*) AS c\n FROM integration_pending_tasks\n WHERE platform = ?\n AND created_at >= ?\n AND payload LIKE ?\n `,\n args: [\"email\", cutoff, `%\"senderId\":\"${senderEmail}\"%`],\n });\n const count = Number(\n (rows[0] as Record<string, unknown> | undefined)?.c ?? 0,\n );\n return count >= RATE_LIMIT_MAX;\n } catch {\n // Table doesn't exist yet (first webhook on a fresh deployment) — allow.\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — email address parsing\n// ---------------------------------------------------------------------------\n\n/** Parse \"Name <addr@example.com>\" or plain \"addr@example.com\" */\nfunction parseEmailAddress(raw: string): { name?: string; email: string } {\n const match = raw.match(/^\\s*(.*?)\\s*<([^>]+)>\\s*$/);\n if (match && match[2]) {\n return {\n name: match[1].replace(/^[\"']|[\"']$/g, \"\").trim() || undefined,\n email: match[2].trim(),\n };\n }\n return { email: raw.trim() };\n}\n\n/** Normalize a to/cc field that may be a string, array, or undefined into a string[] of addresses */\nfunction normalizeAddressList(raw: string | string[] | undefined): string[] {\n if (!raw) return [];\n if (Array.isArray(raw)) return raw.map((a) => a.trim());\n return raw.split(\",\").map((a) => a.trim());\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — header parsing\n// ---------------------------------------------------------------------------\n\n/** Parse a headers object (Resend format: array of {name, value} or Record) */\nfunction parseHeadersObject(headers: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n if (Array.isArray(headers)) {\n for (const h of headers) {\n if (h && typeof h === \"object\" && \"name\" in h && \"value\" in h) {\n result[(h.name as string).toLowerCase()] = h.value as string;\n }\n }\n } else if (typeof headers === \"object\") {\n for (const [key, value] of Object.entries(\n headers as Record<string, unknown>,\n )) {\n result[key.toLowerCase()] = String(value);\n }\n }\n return result;\n}\n\n/** Parse a raw headers string (SendGrid format: \"Key: Value\\nKey: Value\\n...\") */\nfunction parseHeadersString(raw: string | undefined): Record<string, string> {\n const result: Record<string, string> = {};\n if (!raw) return result;\n\n const lines = raw.split(/\\r?\\n/);\n let currentKey = \"\";\n let currentValue = \"\";\n\n for (const line of lines) {\n // Continuation line (starts with whitespace)\n if (/^\\s/.test(line) && currentKey) {\n currentValue += \" \" + line.trim();\n continue;\n }\n // Save previous header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n const colonIdx = line.indexOf(\":\");\n if (colonIdx > 0) {\n currentKey = line.slice(0, colonIdx).trim();\n currentValue = line.slice(colonIdx + 1).trim();\n } else {\n currentKey = \"\";\n currentValue = \"\";\n }\n }\n // Save last header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n return result;\n}\n\n/** Parse a References header value into an array of Message-IDs */\nfunction parseReferencesHeader(\n references: string | undefined,\n): string[] | undefined {\n if (!references) return undefined;\n const ids = references.match(/<[^>]+>/g);\n return ids && ids.length > 0 ? ids : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — threading\n// ---------------------------------------------------------------------------\n\n/**\n * Get the thread root ID using a Gmail-style approach:\n * the oldest Message-ID from the References chain is the thread root.\n * If no References, use the current Message-ID.\n */\nfunction getThreadRootId(messageId: string, references?: string[]): string {\n if (references && references.length > 0) {\n return references[0];\n }\n return messageId;\n}\n\n/**\n * Scope a raw thread root id by the sender's email address. Two different\n * senders crafting the same `References:` header value should NOT collide\n * onto the same internal thread mapping — that's the email-side fix for the\n * thread-injection finding (M1 in the webhook security audit).\n *\n * The returned id is opaque to callers and stays stable across messages\n * from the same sender on the same conversation thread, so reply behaviour\n * is unchanged.\n */\nfunction scopeThreadIdToSender(\n rawThreadId: string,\n senderEmail: string,\n): string {\n return `${senderEmail.toLowerCase()}::${rawThreadId}`;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — reply building\n// ---------------------------------------------------------------------------\n\n/** Build a References header from the platform context */\nfunction buildReferencesHeader(ctx: Record<string, unknown>): string {\n const parts: string[] = [];\n\n // Include existing references\n const refs = ctx.references as string[] | undefined;\n if (refs) {\n parts.push(...refs);\n }\n\n // Append the current message ID\n const messageId = ctx.messageId as string | undefined;\n if (messageId) {\n // Avoid duplicates\n if (!parts.includes(messageId)) {\n parts.push(messageId);\n }\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Build CC list for reply-all when agent was CC'd.\n * Include original To addresses and other CC addresses, excluding the agent and the original sender.\n */\nfunction buildReplyAllCc(context: IncomingMessage): string[] | undefined {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n const senderEmail = context.senderId?.toLowerCase();\n const toAddresses = (context.platformContext.to as string[]) || [];\n const ccAddresses = (context.platformContext.cc as string[]) || [];\n\n const allRecipients = new Set<string>();\n for (const addr of [...toAddresses, ...ccAddresses]) {\n const normalized = addr.toLowerCase().trim();\n // Exclude agent address and original sender (sender goes in To)\n if (normalized !== agentAddress && normalized !== senderEmail) {\n allRecipients.add(normalized);\n }\n }\n\n return allRecipients.size > 0 ? Array.from(allRecipients) : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — text conversion\n// ---------------------------------------------------------------------------\n\n/** Strip HTML tags for a plain-text version of the email */\nfunction stripHtmlForPlainText(html: string): string {\n return html\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<li[^>]*>/gi, \"- \")\n .replace(/<\\/h[1-6]>/gi, \"\\n\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction decodeBasicHtmlEntities(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n}\n\nfunction splitTrailingUrlPunctuation(raw: string): {\n url: string;\n trailing: string;\n} {\n let url = raw;\n let trailing = \"\";\n const trailingEntities = [\""\", \"'\"];\n\n for (;;) {\n const entity = trailingEntities.find((candidate) =>\n url.endsWith(candidate),\n );\n if (!entity) break;\n url = url.slice(0, -entity.length);\n trailing = entity + trailing;\n }\n\n while (/[.,!?;:]$/.test(url)) {\n trailing = url.slice(-1) + trailing;\n url = url.slice(0, -1);\n }\n\n while (url.endsWith(\")\") && !url.includes(\"(\")) {\n trailing = \")\" + trailing;\n url = url.slice(0, -1);\n }\n\n return { url, trailing };\n}\n\nfunction labelForUrl(rawUrl: string): string {\n try {\n const parsed = new URL(decodeBasicHtmlEntities(rawUrl));\n const host = parsed.hostname.replace(/^www\\./, \"\");\n return host ? `Open ${host}` : \"Open link\";\n } catch {\n return \"Open link\";\n }\n}\n\nfunction linkifyTextSegment(segment: string): string {\n return segment.replace(/\\bhttps?:\\/\\/[^\\s<>\"']+/gi, (raw) => {\n const { url, trailing } = splitTrailingUrlPunctuation(raw);\n const href = decodeBasicHtmlEntities(url);\n return `<a href=\"${escapeHtml(href)}\" style=\"color:#2563eb;text-decoration:underline;\">${escapeHtml(\n labelForUrl(url),\n )}</a>${trailing}`;\n });\n}\n\nfunction linkifyBareUrlsInHtml(html: string): string {\n const parts = html.split(/(<\\/?[^>]+>)/g);\n let skipDepth = 0;\n\n return parts\n .map((part) => {\n if (part.startsWith(\"<\") && part.endsWith(\">\")) {\n if (/^<\\/\\s*(a|code)\\b/i.test(part)) {\n skipDepth = Math.max(0, skipDepth - 1);\n } else if (/^<\\s*(a|code)\\b/i.test(part)) {\n skipDepth += 1;\n }\n return part;\n }\n return skipDepth > 0 ? part : linkifyTextSegment(part);\n })\n .join(\"\");\n}\n\n/** Convert basic markdown to HTML for email rendering */\nfunction markdownToHtml(md: string): string {\n let html = md;\n\n // Escape HTML entities in the source (but not our generated tags)\n html = escapeHtml(html);\n\n // Bold: **text** or __text__\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\");\n html = html.replace(/__(.+?)__/g, \"<strong>$1</strong>\");\n\n // Italic: *text* or _text_ (but not inside words with underscores)\n html = html.replace(/(?<!\\w)\\*([^*]+?)\\*(?!\\w)/g, \"<em>$1</em>\");\n html = html.replace(/(?<!\\w)_([^_]+?)_(?!\\w)/g, \"<em>$1</em>\");\n\n // Links: [text](url)\n html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label, url) => {\n const visibleLabel = /^https?:\\/\\//i.test(decodeBasicHtmlEntities(label))\n ? escapeHtml(labelForUrl(label))\n : label;\n return `<a href=\"${escapeHtml(\n decodeBasicHtmlEntities(url),\n )}\" style=\"color:#2563eb;text-decoration:underline;\">${visibleLabel}</a>`;\n });\n\n // Inline code: `code`\n html = html.replace(\n /`([^`]+)`/g,\n '<code style=\"background:#f1f5f9;padding:1px 4px;border-radius:3px;font-size:0.9em;\">$1</code>',\n );\n\n // Bare URLs: keep the destination in href but avoid spelling long URLs out.\n html = linkifyBareUrlsInHtml(html);\n\n // Unordered lists: lines starting with \"- \" or \"* \"\n html = html.replace(/^([*-]) (.+)$/gm, \"<li>$2</li>\");\n // Wrap consecutive <li> in <ul>\n html = html.replace(\n /(<li>.*?<\\/li>\\n?)+/g,\n '<ul style=\"margin:8px 0;padding-left:20px;\">$&</ul>',\n );\n\n // Ordered lists: lines starting with \"1. \", \"2. \" etc.\n html = html.replace(/^\\d+\\. (.+)$/gm, \"<li>$1</li>\");\n // Wrap consecutive <li> that aren't in <ul> in <ol>\n html = html.replace(/(?<!<\\/ul>)(<li>.*?<\\/li>\\n?)+/g, (match) => {\n if (match.includes(\"<ul\")) return match;\n return `<ol style=\"margin:8px 0;padding-left:20px;\">${match}</ol>`;\n });\n\n // Headings: # through ###\n html = html.replace(\n /^### (.+)$/gm,\n '<h3 style=\"margin:16px 0 8px;font-size:1.1em;\">$1</h3>',\n );\n html = html.replace(\n /^## (.+)$/gm,\n '<h2 style=\"margin:16px 0 8px;font-size:1.25em;\">$1</h2>',\n );\n html = html.replace(\n /^# (.+)$/gm,\n '<h1 style=\"margin:16px 0 8px;font-size:1.4em;\">$1</h1>',\n );\n\n // Horizontal rules: --- or ***\n html = html.replace(\n /^(-{3,}|\\*{3,})$/gm,\n '<hr style=\"border:none;border-top:1px solid #e2e8f0;margin:16px 0;\">',\n );\n\n // Paragraphs: double newlines\n html = html.replace(/\\n\\n/g, \"</p><p>\");\n // Single newlines → <br>\n html = html.replace(/\\n/g, \"<br>\");\n\n // Wrap in paragraph tags\n html = `<p>${html}</p>`;\n // Clean up empty paragraphs\n html = html.replace(/<p>\\s*<\\/p>/g, \"\");\n\n return html;\n}\n\n/** Wrap body HTML in a minimal email template with inline styles */\nfunction wrapInEmailTemplate(bodyHtml: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin:0;padding:0;background-color:#ffffff;\">\n<div style=\"max-width:600px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.6;color:#1a1a1a;\">\n${bodyHtml}\n</div>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Raw body reader (matches Slack adapter pattern)\n// ---------------------------------------------------------------------------\n\n/**\n * Read the raw request body as a string and cache on the event context.\n * Reads raw bytes from the request stream — never re-stringifies a parsed\n * body, since the Resend / Svix HMAC is computed over the exact bytes sent\n * (M2 in the webhook security audit).\n */\nasync function readRawBody(event: H3Event): Promise<string> {\n const cached = event.context.__rawBody;\n if (typeof cached === \"string\") return cached;\n const raw = (await h3ReadRawBody(event)) ?? \"\";\n event.context.__rawBody = raw;\n return raw;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"email.js","sourceRoot":"","sources":["../../../src/integrations/adapters/email.ts"],"names":[],"mappings":"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","sourcesContent":["import type { H3Event } from \"h3\";\nimport { getHeader, readRawBody as h3ReadRawBody } from \"h3\";\nimport { timingSafeEqual } from \"node:crypto\";\nimport type {\n PlatformAdapter,\n IncomingMessage,\n OutgoingMessage,\n IntegrationStatus,\n OutboundTarget,\n} from \"../types.js\";\nimport type { EnvKeyConfig } from \"../../server/create-server.js\";\nimport { getIntegrationConfig } from \"../config-store.js\";\nimport { getDbExec } from \"../../db/client.js\";\nimport {\n sendEmail,\n isEmailConfigured,\n getEmailProvider,\n} from \"../../server/email.js\";\n\n/** Max body length before truncation */\nconst EMAIL_MAX_BODY_LENGTH = 15000;\n\n/** Rate limit: max emails per sender within the window */\nconst RATE_LIMIT_MAX = 20;\n/** Rate limit window in ms (1 hour) */\nconst RATE_LIMIT_WINDOW_MS = 60 * 60 * 1000;\n\n/**\n * One-shot warning flags so we don't spam logs on every webhook.\n * Cleared per process — one warning per cold start is enough to surface\n * a misconfiguration without leaking config status to anyone with log access\n * (M6 in the webhook security audit).\n */\nlet _resendUnverifiedWarned = false;\nlet _sendgridUnverifiedWarned = false;\n\n/**\n * Returns true when the deployment is running in production mode and the\n * operator has NOT explicitly opted into accepting unverified webhooks for\n * local testing. In production we MUST refuse webhooks whose signature can't\n * be verified — accepting them with attacker-controlled `from:` addresses\n * lets the dispatch owner-resolution path run as the victim (C1 in the\n * webhook security audit).\n */\nfunction shouldRefuseWhenSecretMissing(): boolean {\n if (process.env.AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS === \"1\") return false;\n return process.env.NODE_ENV === \"production\";\n}\n\n/**\n * Create an Email platform adapter for inbound/outbound email via\n * Resend or SendGrid webhooks.\n *\n * Required env vars:\n * - EMAIL_AGENT_ADDRESS — The email address the agent receives mail at\n *\n * One of these must also be set (checked via isEmailConfigured()):\n * - RESEND_API_KEY — For sending/receiving via Resend\n * - SENDGRID_API_KEY — For sending/receiving via SendGrid\n *\n * Optional:\n * - EMAIL_INBOUND_WEBHOOK_SECRET — Webhook signature verification secret\n */\nexport function emailAdapter(): PlatformAdapter {\n return {\n platform: \"email\",\n label: \"Email\",\n\n getRequiredEnvKeys(): EnvKeyConfig[] {\n return [\n {\n key: \"EMAIL_AGENT_ADDRESS\",\n label: \"Agent Email Address\",\n required: true,\n helpText:\n \"The email address people will use to message your agent (e.g. `agent@yourcompany.com`, or pick from your `<slug>.resend.app` sandbox).\",\n },\n {\n key: \"RESEND_API_KEY\",\n label: \"Resend API Key\",\n required: false,\n helpText:\n \"From resend.com → API keys (starts with `re_`). Either Resend or SendGrid is required for sending and receiving mail.\",\n },\n {\n key: \"SENDGRID_API_KEY\",\n label: \"SendGrid API Key\",\n required: false,\n helpText:\n \"From sendgrid.com → Settings → API Keys (starts with `SG.`). Either Resend or SendGrid is required.\",\n },\n {\n key: \"EMAIL_INBOUND_WEBHOOK_SECRET\",\n label: \"Inbound Webhook Secret\",\n required: false,\n helpText:\n \"Optional. From Resend (Webhooks → Signing Secret, starts with `whsec_`) or your SendGrid Inbound Parse basic-auth password. Used to verify inbound webhooks are real.\",\n },\n ];\n },\n\n async handleVerification(\n _event: H3Event,\n ): Promise<{ handled: boolean; response?: unknown }> {\n // Email webhooks don't need challenge handshakes\n return { handled: false };\n },\n\n async verifyWebhook(event: H3Event): Promise<boolean> {\n const secret = process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const provider = getEmailProvider();\n\n if (provider === \"resend\") {\n return verifyResendWebhook(event, secret);\n }\n\n if (provider === \"sendgrid\") {\n return verifySendGridWebhook(event, secret);\n }\n\n // No provider configured — reject\n console.warn(\"[email] No email provider configured, rejecting webhook\");\n return false;\n },\n\n async parseIncomingMessage(\n event: H3Event,\n ): Promise<IncomingMessage | null> {\n const provider = getEmailProvider();\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n if (!agentAddress) {\n console.warn(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return null;\n }\n\n let parsed: ParsedEmail | null = null;\n\n if (provider === \"resend\") {\n parsed = await parseResendWebhook(event);\n } else if (provider === \"sendgrid\") {\n parsed = await parseSendGridWebhook(event);\n }\n\n if (!parsed) return null;\n\n // Rate limiting (SQL-backed heuristic — counts the sender's already-queued\n // tasks within the last hour). The previous in-memory map reset on every\n // serverless cold start, so the actual ceiling per attacker was\n // RATE_LIMIT_MAX × number_of_active_instances. SQL-backed counting holds\n // across instances. See H4 in the webhook security audit.\n const senderEmail = parsed.from.email.toLowerCase();\n if (await isRateLimited(senderEmail)) {\n console.warn(\n `[email] Rate limited sender: ${senderEmail} (>${RATE_LIMIT_MAX}/hr)`,\n );\n return null;\n }\n\n // Check allowed domains\n const config = await getIntegrationConfig(\"email\");\n if (config?.configData?.allowedDomains) {\n const allowed = config.configData.allowedDomains as string[];\n if (allowed.length > 0) {\n const senderDomain = senderEmail.split(\"@\")[1];\n if (!senderDomain || !allowed.includes(senderDomain)) {\n console.warn(\n `[email] Rejected email from ${senderEmail}: domain not in allowedDomains`,\n );\n return null;\n }\n }\n }\n\n // Determine if agent was CC'd (not in To, but in CC)\n const toAddresses = parsed.to.map((a) => a.toLowerCase());\n const ccAddresses = (parsed.cc ?? []).map((a) => a.toLowerCase());\n const isCC =\n !toAddresses.includes(agentAddress) &&\n ccAddresses.includes(agentAddress);\n\n // Build thread ID from References chain (Gmail-style: oldest Message-ID is thread root).\n // Scope the thread root by sender so an attacker who can forge a `References:`\n // header pointing at someone else's thread root can't graft into that thread.\n // Without this scoping, a third party could craft an inbound email whose\n // References chain matches a known victim's Message-ID and inject messages into\n // the victim's existing conversation — leaking prior content via the agent's\n // reply (M1 in the webhooks security audit).\n const threadRootId = scopeThreadIdToSender(\n getThreadRootId(parsed.messageId, parsed.references),\n senderEmail,\n );\n\n // Build body text\n let bodyText = parsed.text || stripHtmlForPlainText(parsed.html || \"\");\n\n // Truncate if needed\n if (bodyText.length > EMAIL_MAX_BODY_LENGTH) {\n bodyText =\n bodyText.slice(0, EMAIL_MAX_BODY_LENGTH) + \"\\n[Message truncated]\";\n }\n\n // Prefix CC'd emails with context\n if (isCC) {\n const otherRecipients = toAddresses\n .filter((a) => a !== agentAddress)\n .join(\", \");\n bodyText =\n `[CC'd on email between ${senderEmail} and ${otherRecipients || \"others\"}]\\n` +\n `Subject: ${parsed.subject}\\n\\n` +\n bodyText;\n }\n\n return {\n platform: \"email\",\n externalThreadId: threadRootId,\n text: bodyText,\n senderName: parsed.from.name,\n senderId: senderEmail,\n // Carry the message-authentication verdict downstream. Owner\n // resolution (dispatch) must NOT grant a real user's identity /\n // credentials unless the sender is verified — an unverified or\n // spoofed `From:` falls back to a synthetic, credential-less owner.\n senderVerified: parsed.senderVerified,\n platformContext: {\n messageId: parsed.messageId,\n subject: parsed.subject,\n from: senderEmail,\n to: parsed.to,\n cc: parsed.cc,\n inReplyTo: parsed.inReplyTo,\n references: parsed.references,\n isCC,\n senderVerified: parsed.senderVerified,\n },\n timestamp: parsed.date ? new Date(parsed.date).getTime() : Date.now(),\n };\n },\n\n async sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n // EMAIL_FROM overrides the from-address — required when the receiving\n // address is on a sub-domain that can't be a verified sender (e.g.\n // *.resend.app). Inbound and outbound addresses can differ.\n const fromAddress = process.env.EMAIL_FROM\n ? process.env.EMAIL_FROM\n : `${displayName} <${agentAddress}>`;\n\n const subject = context.platformContext.subject as string;\n const reSubject = subject.startsWith(\"Re: \") ? subject : `Re: ${subject}`;\n\n try {\n await sendEmail({\n to: context.senderId!,\n from: fromAddress,\n subject: reSubject,\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n inReplyTo: context.platformContext.messageId as string,\n references: buildReferencesHeader(context.platformContext),\n cc: context.platformContext.isCC\n ? buildReplyAllCc(context)\n : undefined,\n });\n } catch (err) {\n console.error(\"[email] Failed to send response:\", err);\n }\n },\n\n async sendMessageToTarget(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void> {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS;\n if (!agentAddress) {\n console.error(\"[email] EMAIL_AGENT_ADDRESS not configured\");\n return;\n }\n\n const config = await getIntegrationConfig(\"email\");\n const displayName =\n (config?.configData?.displayName as string) || \"Dispatch Agent\";\n\n try {\n await sendEmail({\n to: target.destination,\n from: `${displayName} <${agentAddress}>`,\n subject: target.label || \"Message from Dispatch Agent\",\n html: message.text,\n text: stripHtmlForPlainText(message.text),\n ...(target.threadRef\n ? {\n inReplyTo: target.threadRef,\n references: target.threadRef,\n }\n : {}),\n });\n } catch (err) {\n console.error(\"[email] Failed to send proactive message:\", err);\n throw err;\n }\n },\n\n formatAgentResponse(text: string): OutgoingMessage {\n const bodyHtml = markdownToHtml(text);\n const html = wrapInEmailTemplate(bodyHtml);\n return { text: html, platformContext: {} };\n },\n\n async getStatus(_baseUrl?: string): Promise<IntegrationStatus> {\n const hasAgentAddress = !!process.env.EMAIL_AGENT_ADDRESS;\n const hasEmailProvider = isEmailConfigured();\n const hasWebhookSecret = !!process.env.EMAIL_INBOUND_WEBHOOK_SECRET;\n const configured = hasAgentAddress && hasEmailProvider;\n\n return {\n platform: \"email\",\n label: \"Email\",\n enabled: false, // overridden by plugin\n configured,\n details: {\n hasAgentAddress,\n hasEmailProvider,\n hasWebhookSecret,\n provider: getEmailProvider(),\n },\n error: !configured\n ? \"Set EMAIL_AGENT_ADDRESS and either RESEND_API_KEY or SENDGRID_API_KEY\"\n : undefined,\n };\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Parsed email shape\n// ---------------------------------------------------------------------------\n\ninterface ParsedEmail {\n messageId: string;\n subject: string;\n from: { name?: string; email: string };\n to: string[];\n cc?: string[];\n text?: string;\n html?: string;\n inReplyTo?: string;\n references?: string[];\n date?: string;\n /**\n * True when the provider's message-authentication results show that the\n * mail genuinely originated from the From domain: DKIM `pass` aligned with\n * the From domain, or an aligned SPF `pass`. False when results are absent\n * or fail — we fail closed so a spoofed `From:` can never be treated as\n * verified. See FINDING 3 (inbound-email impersonation) in the webhook\n * security audit.\n */\n senderVerified: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Webhook verification\n// ---------------------------------------------------------------------------\n\nasync function verifyResendWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing Resend webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_resendUnverifiedWarned) {\n _resendUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting Resend webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n const svixId = getHeader(event, \"svix-id\");\n const svixTimestamp = getHeader(event, \"svix-timestamp\");\n const svixSignature = getHeader(event, \"svix-signature\");\n\n if (!svixId || !svixTimestamp || !svixSignature) {\n console.warn(\"[email] Missing Svix signature headers\");\n return false;\n }\n\n // Reject requests older than 5 minutes (replay protection)\n const ts = parseInt(svixTimestamp, 10);\n if (Math.abs(Date.now() / 1000 - ts) > 300) {\n console.warn(\"[email] Svix timestamp too old, rejecting\");\n return false;\n }\n\n const body = await readRawBody(event);\n const crypto = await import(\"node:crypto\");\n\n // Svix signing secret may be prefixed with \"whsec_\"\n const rawSecret = secret.startsWith(\"whsec_\") ? secret.slice(6) : secret;\n const secretBytes = Buffer.from(rawSecret, \"base64\");\n\n const signedContent = `${svixId}.${svixTimestamp}.${body}`;\n const expectedSignature = crypto\n .createHmac(\"sha256\", secretBytes)\n .update(signedContent)\n .digest(\"base64\");\n\n // Svix sends multiple signatures separated by spaces, each prefixed with \"v1,\"\n const signatures = svixSignature.split(\" \");\n for (const sig of signatures) {\n const sigValue = sig.startsWith(\"v1,\") ? sig.slice(3) : sig;\n try {\n if (\n crypto.timingSafeEqual(\n Buffer.from(expectedSignature),\n Buffer.from(sigValue),\n )\n ) {\n return true;\n }\n } catch {\n // Length mismatch — try next signature\n }\n }\n\n console.warn(\"[email] Svix signature verification failed\");\n return false;\n}\n\nfunction safeEq(a: string, b: string): boolean {\n const aBuf = Buffer.from(a);\n const bBuf = Buffer.from(b);\n if (aBuf.length !== bBuf.length) return false;\n return timingSafeEqual(aBuf, bBuf);\n}\n\nasync function verifySendGridWebhook(\n event: H3Event,\n secret?: string,\n): Promise<boolean> {\n if (!secret) {\n if (shouldRefuseWhenSecretMissing()) {\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.error(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — refusing SendGrid webhook in production. \" +\n \"Set EMAIL_INBOUND_WEBHOOK_SECRET, or set AGENT_NATIVE_ALLOW_UNVERIFIED_WEBHOOKS=1 for local testing only.\",\n );\n }\n return false;\n }\n if (!_sendgridUnverifiedWarned) {\n _sendgridUnverifiedWarned = true;\n console.warn(\n \"[email] EMAIL_INBOUND_WEBHOOK_SECRET not set — accepting SendGrid webhook without verification (dev mode)\",\n );\n }\n return true;\n }\n\n // Check for the secret in a custom header or basic auth\n const authHeader = getHeader(event, \"authorization\");\n if (authHeader) {\n // Basic auth: \"Basic base64(user:pass)\" — secret is the password\n if (authHeader.startsWith(\"Basic \")) {\n const decoded = Buffer.from(authHeader.slice(6), \"base64\").toString();\n const password = decoded.split(\":\")[1];\n if (password !== undefined && safeEq(password, secret)) return true;\n }\n }\n\n // Also check a custom header (common SendGrid Inbound Parse pattern)\n const customSecret = getHeader(event, \"x-webhook-secret\");\n if (customSecret !== undefined && safeEq(customSecret, secret)) return true;\n\n console.warn(\"[email] SendGrid webhook secret verification failed\");\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Inbound email parsing\n// ---------------------------------------------------------------------------\n\nasync function parseResendWebhook(event: H3Event): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body || body.type !== \"email.received\") return null;\n\n const data = body.data;\n if (!data) return null;\n\n // Resend webhook payload provides email metadata directly in data\n // Fields: from, to, cc, subject, text, html, headers, created_at\n const fromRaw = data.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = data.to as string | string[] | undefined;\n const to = normalizeAddressList(toRaw);\n const ccRaw = data.cc as string | string[] | undefined;\n const cc = normalizeAddressList(ccRaw);\n\n // Parse headers for Message-ID, In-Reply-To, References\n const headers = parseHeadersObject(data.headers);\n const messageId =\n headers[\"message-id\"] || data.email_id || `resend-${Date.now()}`;\n\n // Resend forwards the raw `Authentication-Results` header (and may also\n // surface explicit `dkim`/`spf` fields). Derive a verified verdict from\n // whichever is present; absent results fail closed (unverified).\n const senderVerified = computeSenderVerified({\n fromEmail: from.email,\n authResults: headers[\"authentication-results\"],\n dkim: typeof data.dkim === \"string\" ? data.dkim : undefined,\n spf: typeof data.spf === \"string\" ? data.spf : undefined,\n });\n\n return {\n messageId,\n subject: (data.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: data.text as string | undefined,\n html: data.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: (data.created_at as string) || undefined,\n senderVerified,\n };\n}\n\nasync function parseSendGridWebhook(\n event: H3Event,\n): Promise<ParsedEmail | null> {\n const raw = await readRawBody(event);\n const body = JSON.parse(raw);\n if (!body) return null;\n\n // SendGrid Inbound Parse sends form data with fields:\n // from, to, cc, subject, text, html, headers, envelope\n const fromRaw = body.from as string | undefined;\n const from = fromRaw ? parseEmailAddress(fromRaw) : null;\n if (!from) return null;\n\n const toRaw = body.to as string | undefined;\n const to = toRaw ? toRaw.split(\",\").map((a: string) => a.trim()) : [];\n const ccRaw = body.cc as string | undefined;\n const cc = ccRaw ? ccRaw.split(\",\").map((a: string) => a.trim()) : [];\n\n // Parse raw headers string\n const headersStr = body.headers as string | undefined;\n const headers = parseHeadersString(headersStr);\n const messageId = headers[\"message-id\"] || `sendgrid-${Date.now()}`;\n\n // SendGrid Inbound Parse posts explicit `dkim` (e.g. `{@example.com : pass}`)\n // and `SPF` (e.g. `pass`) form fields, and also carries\n // `Authentication-Results` inside the raw headers blob. Use all available\n // signals; absent results fail closed (unverified).\n const senderVerified = computeSenderVerified({\n fromEmail: from.email,\n authResults: headers[\"authentication-results\"],\n dkim: typeof body.dkim === \"string\" ? body.dkim : undefined,\n spf: typeof body.SPF === \"string\" ? body.SPF : undefined,\n });\n\n return {\n messageId,\n subject: (body.subject as string) || \"(no subject)\",\n from,\n to,\n cc: cc.length > 0 ? cc : undefined,\n text: body.text as string | undefined,\n html: body.html as string | undefined,\n inReplyTo: headers[\"in-reply-to\"] || undefined,\n references: parseReferencesHeader(headers[\"references\"]),\n date: headers[\"date\"] || undefined,\n senderVerified,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — sender authentication (DKIM / SPF)\n// ---------------------------------------------------------------------------\n\n/**\n * Extract the registrable-ish domain from an email address (lowercased).\n * We keep the full host rather than collapsing to an eTLD+1 — exact-domain\n * alignment is the conservative choice here, and avoids bundling a public\n * suffix list. Subdomain senders that legitimately DKIM-sign with the parent\n * domain are handled by the suffix check in `domainsAlign`.\n */\nfunction emailDomain(email: string): string {\n const at = email.lastIndexOf(\"@\");\n return at >= 0\n ? email\n .slice(at + 1)\n .trim()\n .toLowerCase()\n : \"\";\n}\n\n/**\n * True when `signingDomain` is the From domain or a parent of it (e.g.\n * From `user@mail.example.com` aligned with a `d=example.com` signature).\n * Both directions of subdomain nesting are accepted because senders sign\n * with either the exact From host or the organizational parent.\n */\nfunction domainsAlign(fromDomain: string, signingDomain: string): boolean {\n if (!fromDomain || !signingDomain) return false;\n if (fromDomain === signingDomain) return true;\n return (\n fromDomain.endsWith(`.${signingDomain}`) ||\n signingDomain.endsWith(`.${fromDomain}`)\n );\n}\n\n/**\n * Compute whether an inbound email is authenticated as genuinely coming from\n * its `From:` domain. Returns true only when DKIM passes for an aligned\n * domain, or SPF passes for an aligned domain. Anything else — missing\n * results, `fail`, `softfail`, `none`, `neutral`, `temperror`, `permerror`\n * — returns false (fail closed).\n *\n * Inputs may come from provider-specific fields (`dkim`, `spf`) and/or the\n * RFC 8601 `Authentication-Results` header, in any combination. We treat the\n * union: if ANY source shows an aligned pass, the sender is verified.\n */\nfunction computeSenderVerified(input: {\n fromEmail: string;\n authResults?: string;\n dkim?: string;\n spf?: string;\n}): boolean {\n const fromDomain = emailDomain(input.fromEmail);\n if (!fromDomain) return false;\n\n // 1. Provider DKIM field, e.g. SendGrid `{@example.com : pass}` or\n // `{@example.com : pass; @other.com : fail}`.\n if (input.dkim) {\n const dkimEntries = input.dkim.matchAll(\n /@([a-z0-9.-]+)\\s*:\\s*(pass|fail|none|neutral|softfail|temperror|permerror)/gi,\n );\n for (const m of dkimEntries) {\n const domain = m[1].toLowerCase();\n const verdict = m[2].toLowerCase();\n if (verdict === \"pass\" && domainsAlign(fromDomain, domain)) return true;\n }\n }\n\n // 2. Provider SPF field. SendGrid posts a bare verdict (e.g. `pass`); since\n // SPF authenticates the envelope/MailFrom rather than the header From,\n // a bare `pass` with no domain only counts when we can't tell it's\n // misaligned. We accept a bare `pass` as an aligned SPF pass — this is\n // the same trust level Gmail-style routing assigns to a plain SPF pass.\n if (input.spf) {\n const spfVerdict = input.spf.trim().toLowerCase();\n if (spfVerdict === \"pass\") return true;\n }\n\n // 3. RFC 8601 `Authentication-Results` header (may list multiple methods).\n if (input.authResults) {\n const ar = input.authResults.toLowerCase();\n // DKIM with an aligned domain.\n const dkimRe = /dkim=pass[^;]*?(?:header\\.(?:d|i)=|@)([a-z0-9.-]+)/g;\n for (const m of ar.matchAll(dkimRe)) {\n const domain = m[1].replace(/^@/, \"\");\n if (domainsAlign(fromDomain, domain)) return true;\n }\n // SPF pass (envelope auth) — accept as an aligned pass.\n if (/spf=pass\\b/.test(ar)) return true;\n }\n\n return false;\n}\n\n// ---------------------------------------------------------------------------\n// Rate limiting\n// ---------------------------------------------------------------------------\n\n/**\n * Rate-limit heuristic backed by the `integration_pending_tasks` queue.\n *\n * Counts how many tasks this sender has produced in the last hour. The count\n * INCLUDES tasks already processed (status = completed/failed) because the\n * rows aren't deleted on completion — that's enough signal to throttle a\n * single noisy/abusive sender without needing a dedicated counter table.\n *\n * Two trade-offs worth knowing:\n * - This is a coarse heuristic, not exact metering. Within one hour the\n * count is correct; rows produced more than an hour ago naturally drop\n * off. We don't try to be precise, only to raise the bar past the\n * \"send 10K emails through one Lambda burst\" failure mode.\n * - The query relies on the `idx_pending_tasks_status_created` index plus\n * a sender substring match. A targeted attacker could amortise the cost\n * by reusing one sender address — that's fine, the goal here is to bound\n * the attack within a single attacker identity, not to detect spoofing.\n *\n * If the table doesn't yet exist on this deployment (no inbound webhook has\n * been processed before), we silently allow the message — the schema is\n * provisioned on first task insert. See H4 in the webhook security audit.\n */\nasync function isRateLimited(senderEmail: string): Promise<boolean> {\n const cutoff = Date.now() - RATE_LIMIT_WINDOW_MS;\n try {\n const client = getDbExec();\n const { rows } = await client.execute({\n sql: `\n SELECT COUNT(*) AS c\n FROM integration_pending_tasks\n WHERE platform = ?\n AND created_at >= ?\n AND payload LIKE ?\n `,\n args: [\"email\", cutoff, `%\"senderId\":\"${senderEmail}\"%`],\n });\n const count = Number(\n (rows[0] as Record<string, unknown> | undefined)?.c ?? 0,\n );\n return count >= RATE_LIMIT_MAX;\n } catch {\n // Table doesn't exist yet (first webhook on a fresh deployment) — allow.\n return false;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — email address parsing\n// ---------------------------------------------------------------------------\n\n/** Parse \"Name <addr@example.com>\" or plain \"addr@example.com\" */\nfunction parseEmailAddress(raw: string): { name?: string; email: string } {\n const match = raw.match(/^\\s*(.*?)\\s*<([^>]+)>\\s*$/);\n if (match && match[2]) {\n return {\n name: match[1].replace(/^[\"']|[\"']$/g, \"\").trim() || undefined,\n email: match[2].trim(),\n };\n }\n return { email: raw.trim() };\n}\n\n/** Normalize a to/cc field that may be a string, array, or undefined into a string[] of addresses */\nfunction normalizeAddressList(raw: string | string[] | undefined): string[] {\n if (!raw) return [];\n if (Array.isArray(raw)) return raw.map((a) => a.trim());\n return raw.split(\",\").map((a) => a.trim());\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — header parsing\n// ---------------------------------------------------------------------------\n\n/** Parse a headers object (Resend format: array of {name, value} or Record) */\nfunction parseHeadersObject(headers: unknown): Record<string, string> {\n const result: Record<string, string> = {};\n if (!headers) return result;\n\n if (Array.isArray(headers)) {\n for (const h of headers) {\n if (h && typeof h === \"object\" && \"name\" in h && \"value\" in h) {\n result[(h.name as string).toLowerCase()] = h.value as string;\n }\n }\n } else if (typeof headers === \"object\") {\n for (const [key, value] of Object.entries(\n headers as Record<string, unknown>,\n )) {\n result[key.toLowerCase()] = String(value);\n }\n }\n return result;\n}\n\n/** Parse a raw headers string (SendGrid format: \"Key: Value\\nKey: Value\\n...\") */\nfunction parseHeadersString(raw: string | undefined): Record<string, string> {\n const result: Record<string, string> = {};\n if (!raw) return result;\n\n const lines = raw.split(/\\r?\\n/);\n let currentKey = \"\";\n let currentValue = \"\";\n\n for (const line of lines) {\n // Continuation line (starts with whitespace)\n if (/^\\s/.test(line) && currentKey) {\n currentValue += \" \" + line.trim();\n continue;\n }\n // Save previous header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n const colonIdx = line.indexOf(\":\");\n if (colonIdx > 0) {\n currentKey = line.slice(0, colonIdx).trim();\n currentValue = line.slice(colonIdx + 1).trim();\n } else {\n currentKey = \"\";\n currentValue = \"\";\n }\n }\n // Save last header\n if (currentKey) {\n result[currentKey.toLowerCase()] = currentValue;\n }\n return result;\n}\n\n/** Parse a References header value into an array of Message-IDs */\nfunction parseReferencesHeader(\n references: string | undefined,\n): string[] | undefined {\n if (!references) return undefined;\n const ids = references.match(/<[^>]+>/g);\n return ids && ids.length > 0 ? ids : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — threading\n// ---------------------------------------------------------------------------\n\n/**\n * Get the thread root ID using a Gmail-style approach:\n * the oldest Message-ID from the References chain is the thread root.\n * If no References, use the current Message-ID.\n */\nfunction getThreadRootId(messageId: string, references?: string[]): string {\n if (references && references.length > 0) {\n return references[0];\n }\n return messageId;\n}\n\n/**\n * Scope a raw thread root id by the sender's email address. Two different\n * senders crafting the same `References:` header value should NOT collide\n * onto the same internal thread mapping — that's the email-side fix for the\n * thread-injection finding (M1 in the webhook security audit).\n *\n * The returned id is opaque to callers and stays stable across messages\n * from the same sender on the same conversation thread, so reply behaviour\n * is unchanged.\n */\nfunction scopeThreadIdToSender(\n rawThreadId: string,\n senderEmail: string,\n): string {\n return `${senderEmail.toLowerCase()}::${rawThreadId}`;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — reply building\n// ---------------------------------------------------------------------------\n\n/** Build a References header from the platform context */\nfunction buildReferencesHeader(ctx: Record<string, unknown>): string {\n const parts: string[] = [];\n\n // Include existing references\n const refs = ctx.references as string[] | undefined;\n if (refs) {\n parts.push(...refs);\n }\n\n // Append the current message ID\n const messageId = ctx.messageId as string | undefined;\n if (messageId) {\n // Avoid duplicates\n if (!parts.includes(messageId)) {\n parts.push(messageId);\n }\n }\n\n return parts.join(\" \");\n}\n\n/**\n * Build CC list for reply-all when agent was CC'd.\n * Include original To addresses and other CC addresses, excluding the agent and the original sender.\n */\nfunction buildReplyAllCc(context: IncomingMessage): string[] | undefined {\n const agentAddress = process.env.EMAIL_AGENT_ADDRESS?.toLowerCase();\n const senderEmail = context.senderId?.toLowerCase();\n const toAddresses = (context.platformContext.to as string[]) || [];\n const ccAddresses = (context.platformContext.cc as string[]) || [];\n\n const allRecipients = new Set<string>();\n for (const addr of [...toAddresses, ...ccAddresses]) {\n const normalized = addr.toLowerCase().trim();\n // Exclude agent address and original sender (sender goes in To)\n if (normalized !== agentAddress && normalized !== senderEmail) {\n allRecipients.add(normalized);\n }\n }\n\n return allRecipients.size > 0 ? Array.from(allRecipients) : undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Helpers — text conversion\n// ---------------------------------------------------------------------------\n\n/** Strip HTML tags for a plain-text version of the email */\nfunction stripHtmlForPlainText(html: string): string {\n return html\n .replace(/<br\\s*\\/?>/gi, \"\\n\")\n .replace(/<\\/p>/gi, \"\\n\\n\")\n .replace(/<\\/div>/gi, \"\\n\")\n .replace(/<\\/li>/gi, \"\\n\")\n .replace(/<li[^>]*>/gi, \"- \")\n .replace(/<\\/h[1-6]>/gi, \"\\n\\n\")\n .replace(/<[^>]+>/g, \"\")\n .replace(/ /g, \" \")\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\")\n .replace(/\\n{3,}/g, \"\\n\\n\")\n .trim();\n}\n\nfunction escapeHtml(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\");\n}\n\nfunction decodeBasicHtmlEntities(s: string): string {\n return s\n .replace(/&/g, \"&\")\n .replace(/</g, \"<\")\n .replace(/>/g, \">\")\n .replace(/"/g, '\"')\n .replace(/'/g, \"'\");\n}\n\nfunction splitTrailingUrlPunctuation(raw: string): {\n url: string;\n trailing: string;\n} {\n let url = raw;\n let trailing = \"\";\n const trailingEntities = [\""\", \"'\"];\n\n for (;;) {\n const entity = trailingEntities.find((candidate) =>\n url.endsWith(candidate),\n );\n if (!entity) break;\n url = url.slice(0, -entity.length);\n trailing = entity + trailing;\n }\n\n while (/[.,!?;:]$/.test(url)) {\n trailing = url.slice(-1) + trailing;\n url = url.slice(0, -1);\n }\n\n while (url.endsWith(\")\") && !url.includes(\"(\")) {\n trailing = \")\" + trailing;\n url = url.slice(0, -1);\n }\n\n return { url, trailing };\n}\n\nfunction labelForUrl(rawUrl: string): string {\n try {\n const parsed = new URL(decodeBasicHtmlEntities(rawUrl));\n const host = parsed.hostname.replace(/^www\\./, \"\");\n return host ? `Open ${host}` : \"Open link\";\n } catch {\n return \"Open link\";\n }\n}\n\nfunction linkifyTextSegment(segment: string): string {\n return segment.replace(/\\bhttps?:\\/\\/[^\\s<>\"']+/gi, (raw) => {\n const { url, trailing } = splitTrailingUrlPunctuation(raw);\n const href = decodeBasicHtmlEntities(url);\n return `<a href=\"${escapeHtml(href)}\" style=\"color:#2563eb;text-decoration:underline;\">${escapeHtml(\n labelForUrl(url),\n )}</a>${trailing}`;\n });\n}\n\nfunction linkifyBareUrlsInHtml(html: string): string {\n const parts = html.split(/(<\\/?[^>]+>)/g);\n let skipDepth = 0;\n\n return parts\n .map((part) => {\n if (part.startsWith(\"<\") && part.endsWith(\">\")) {\n if (/^<\\/\\s*(a|code)\\b/i.test(part)) {\n skipDepth = Math.max(0, skipDepth - 1);\n } else if (/^<\\s*(a|code)\\b/i.test(part)) {\n skipDepth += 1;\n }\n return part;\n }\n return skipDepth > 0 ? part : linkifyTextSegment(part);\n })\n .join(\"\");\n}\n\n/** Convert basic markdown to HTML for email rendering */\nfunction markdownToHtml(md: string): string {\n let html = md;\n\n // Escape HTML entities in the source (but not our generated tags)\n html = escapeHtml(html);\n\n // Bold: **text** or __text__\n html = html.replace(/\\*\\*(.+?)\\*\\*/g, \"<strong>$1</strong>\");\n html = html.replace(/__(.+?)__/g, \"<strong>$1</strong>\");\n\n // Italic: *text* or _text_ (but not inside words with underscores)\n html = html.replace(/(?<!\\w)\\*([^*]+?)\\*(?!\\w)/g, \"<em>$1</em>\");\n html = html.replace(/(?<!\\w)_([^_]+?)_(?!\\w)/g, \"<em>$1</em>\");\n\n // Links: [text](url)\n html = html.replace(/\\[([^\\]]+)\\]\\(([^)]+)\\)/g, (_match, label, url) => {\n const visibleLabel = /^https?:\\/\\//i.test(decodeBasicHtmlEntities(label))\n ? escapeHtml(labelForUrl(label))\n : label;\n return `<a href=\"${escapeHtml(\n decodeBasicHtmlEntities(url),\n )}\" style=\"color:#2563eb;text-decoration:underline;\">${visibleLabel}</a>`;\n });\n\n // Inline code: `code`\n html = html.replace(\n /`([^`]+)`/g,\n '<code style=\"background:#f1f5f9;padding:1px 4px;border-radius:3px;font-size:0.9em;\">$1</code>',\n );\n\n // Bare URLs: keep the destination in href but avoid spelling long URLs out.\n html = linkifyBareUrlsInHtml(html);\n\n // Unordered lists: lines starting with \"- \" or \"* \"\n html = html.replace(/^([*-]) (.+)$/gm, \"<li>$2</li>\");\n // Wrap consecutive <li> in <ul>\n html = html.replace(\n /(<li>.*?<\\/li>\\n?)+/g,\n '<ul style=\"margin:8px 0;padding-left:20px;\">$&</ul>',\n );\n\n // Ordered lists: lines starting with \"1. \", \"2. \" etc.\n html = html.replace(/^\\d+\\. (.+)$/gm, \"<li>$1</li>\");\n // Wrap consecutive <li> that aren't in <ul> in <ol>\n html = html.replace(/(?<!<\\/ul>)(<li>.*?<\\/li>\\n?)+/g, (match) => {\n if (match.includes(\"<ul\")) return match;\n return `<ol style=\"margin:8px 0;padding-left:20px;\">${match}</ol>`;\n });\n\n // Headings: # through ###\n html = html.replace(\n /^### (.+)$/gm,\n '<h3 style=\"margin:16px 0 8px;font-size:1.1em;\">$1</h3>',\n );\n html = html.replace(\n /^## (.+)$/gm,\n '<h2 style=\"margin:16px 0 8px;font-size:1.25em;\">$1</h2>',\n );\n html = html.replace(\n /^# (.+)$/gm,\n '<h1 style=\"margin:16px 0 8px;font-size:1.4em;\">$1</h1>',\n );\n\n // Horizontal rules: --- or ***\n html = html.replace(\n /^(-{3,}|\\*{3,})$/gm,\n '<hr style=\"border:none;border-top:1px solid #e2e8f0;margin:16px 0;\">',\n );\n\n // Paragraphs: double newlines\n html = html.replace(/\\n\\n/g, \"</p><p>\");\n // Single newlines → <br>\n html = html.replace(/\\n/g, \"<br>\");\n\n // Wrap in paragraph tags\n html = `<p>${html}</p>`;\n // Clean up empty paragraphs\n html = html.replace(/<p>\\s*<\\/p>/g, \"\");\n\n return html;\n}\n\n/** Wrap body HTML in a minimal email template with inline styles */\nfunction wrapInEmailTemplate(bodyHtml: string): string {\n return `<!DOCTYPE html>\n<html>\n<head>\n<meta charset=\"utf-8\">\n<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n</head>\n<body style=\"margin:0;padding:0;background-color:#ffffff;\">\n<div style=\"max-width:600px;margin:0 auto;padding:20px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Helvetica,Arial,sans-serif;font-size:14px;line-height:1.6;color:#1a1a1a;\">\n${bodyHtml}\n</div>\n</body>\n</html>`;\n}\n\n// ---------------------------------------------------------------------------\n// Raw body reader (matches Slack adapter pattern)\n// ---------------------------------------------------------------------------\n\n/**\n * Read the raw request body as a string and cache on the event context.\n * Reads raw bytes from the request stream — never re-stringifies a parsed\n * body, since the Resend / Svix HMAC is computed over the exact bytes sent\n * (M2 in the webhook security audit).\n */\nasync function readRawBody(event: H3Event): Promise<string> {\n const cached = event.context.__rawBody;\n if (typeof cached === \"string\") return cached;\n const raw = (await h3ReadRawBody(event)) ?? \"\";\n event.context.__rawBody = raw;\n return raw;\n}\n"]}
|
|
@@ -16,6 +16,17 @@ export interface IncomingMessage {
|
|
|
16
16
|
senderEmail?: string;
|
|
17
17
|
/** Platform-specific sender ID */
|
|
18
18
|
senderId?: string;
|
|
19
|
+
/**
|
|
20
|
+
* Whether the platform cryptographically authenticated that the message
|
|
21
|
+
* genuinely came from the claimed sender (e.g. inbound email that passed
|
|
22
|
+
* DKIM, or an aligned SPF pass, for the From domain). Defaults to
|
|
23
|
+
* undefined/false for platforms that don't provide sender authentication.
|
|
24
|
+
*
|
|
25
|
+
* Owner-resolution paths that grant a real user's identity/credentials
|
|
26
|
+
* MUST treat a missing/false value as "unverified" and fail closed —
|
|
27
|
+
* never derive a privileged acting identity from an unverified sender.
|
|
28
|
+
*/
|
|
29
|
+
senderVerified?: boolean;
|
|
19
30
|
/** Raw platform-specific context needed for routing responses */
|
|
20
31
|
platformContext: Record<string, unknown>;
|
|
21
32
|
/** Message timestamp (epoch ms) */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { H3Event } from \"h3\";\nimport type { EnvKeyConfig } from \"../server/create-server.js\";\n\n/**\n * Normalized incoming message from any messaging platform.\n */\nexport interface IncomingMessage {\n /** Platform identifier (e.g., \"slack\", \"telegram\", \"whatsapp\") */\n platform: string;\n /** Platform-specific thread/conversation identifier */\n externalThreadId: string;\n /** Message text content */\n text: string;\n /** Display name of the sender */\n senderName?: string;\n /** Verified sender email, when the platform can provide one */\n senderEmail?: string;\n /** Platform-specific sender ID */\n senderId?: string;\n /** Raw platform-specific context needed for routing responses */\n platformContext: Record<string, unknown>;\n /** Message timestamp (epoch ms) */\n timestamp: number;\n}\n\n/**\n * Outgoing message to send back to a messaging platform.\n */\nexport interface OutgoingMessage {\n /** Text content of the response */\n text: string;\n /** Platform-specific payload (e.g., Slack blocks, Telegram parse_mode) */\n platformContext: Record<string, unknown>;\n}\n\n/**\n * Proactive outbound message target for a platform.\n * Used when the agent needs to send to a saved destination instead of replying\n * to the current inbound thread.\n */\nexport interface OutboundTarget {\n /** Canonical platform-specific destination id (channel, chat, thread, etc.) */\n destination: string;\n /** Optional thread reference when the destination supports threading */\n threadRef?: string | null;\n /** Optional fallback display label */\n label?: string;\n}\n\n/**\n * Connection status for a platform integration.\n */\nexport interface IntegrationStatus {\n platform: string;\n /** Human-readable label (e.g., \"Slack\", \"Telegram\") */\n label: string;\n /** Whether the integration is explicitly enabled */\n enabled: boolean;\n /** Whether all required credentials are configured */\n configured: boolean;\n /** Platform-specific details (workspace name, bot username, etc.) */\n details?: Record<string, unknown>;\n /** Error message if something is wrong */\n error?: string;\n /** The webhook URL that should be configured in the platform */\n webhookUrl?: string;\n /** The full list of env keys (required + optional) the adapter recognizes,\n * including UI hints. Surfaced on the integrations status endpoint so the\n * frontend can render fields without hard-coding them per platform. */\n requiredEnvKeys?: import(\"../server/create-server.js\").EnvKeyConfig[];\n}\n\n/**\n * Platform adapter interface — implement this for each messaging platform.\n *\n * Each adapter handles the platform-specific concerns:\n * - Webhook verification (HMAC signatures, challenge responses)\n * - Message parsing (platform events → normalized IncomingMessage)\n * - Response formatting (agent text → platform-specific format)\n * - Response delivery (POST back to platform API)\n */\nexport interface PlatformAdapter {\n /** Unique platform identifier */\n readonly platform: string;\n /** Human-readable label */\n readonly label: string;\n\n /** Env keys this adapter needs (tokens, secrets, etc.) */\n getRequiredEnvKeys(): EnvKeyConfig[];\n\n /**\n * Handle platform-specific verification challenges.\n * For example, Slack sends a `url_verification` event when setting up.\n * Return `{ handled: true, response }` to short-circuit the webhook handler.\n */\n handleVerification(event: H3Event): Promise<{\n handled: boolean;\n response?: unknown;\n }>;\n\n /**\n * Validate the webhook request signature.\n * Returns true if the request is authentic.\n */\n verifyWebhook(event: H3Event): Promise<boolean>;\n\n /**\n * Parse the webhook payload into a normalized IncomingMessage.\n * Return null to silently ignore the event (bot messages, edits, etc.).\n */\n parseIncomingMessage(event: H3Event): Promise<IncomingMessage | null>;\n\n /**\n * Send the agent's response back to the messaging platform.\n *\n * If `opts.placeholderRef` is provided (returned earlier by\n * `postProcessingPlaceholder`), adapters that support in-place edits should\n * update that placeholder message rather than posting a new one. Adapters\n * without an \"update message\" API can ignore the ref and post fresh.\n */\n sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n opts?: { placeholderRef?: string },\n ): Promise<void>;\n\n /**\n * Optionally post a \"working on it…\" placeholder message immediately when a\n * webhook arrives, before the agent loop runs. Adapters that support\n * in-place message edits (Slack via `chat.update`, etc.) return an opaque\n * `placeholderRef` that the webhook flow threads through to `sendResponse`\n * so the same message is updated with the final answer once ready.\n *\n * Adapters without edit support should leave this undefined; the webhook\n * handler will skip the placeholder step entirely.\n */\n postProcessingPlaceholder?(\n incoming: IncomingMessage,\n ): Promise<{ placeholderRef: string } | null>;\n\n /**\n * Send a proactive outbound message to a platform destination. Adapters that\n * only support direct replies can omit this.\n */\n sendMessageToTarget?(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void>;\n\n /**\n * Format plain agent response text into a platform-appropriate message.\n * Handles markdown conversion, message splitting for length limits, etc.\n *\n * `opts.threadDeepLinkUrl`, when present, is a URL back to the originating\n * thread in the dispatch UI. Adapters that support rich blocks should\n * render this as a button (Slack); adapters that don't may inline it as a\n * link or simply omit it.\n */\n formatAgentResponse(\n text: string,\n opts?: { threadDeepLinkUrl?: string },\n ): OutgoingMessage;\n\n /** Return current connection/configuration status for the settings UI. */\n getStatus(baseUrl?: string): Promise<IntegrationStatus>;\n}\n\n/**\n * Options for the integrations plugin.\n */\nexport interface IntegrationsPluginOptions {\n /** App identifier used by call-agent to prevent self-calls (e.g. \"dispatch\"). */\n appId?: string;\n /** Platform adapters to enable. Default: all built-in adapters with configured env keys. */\n adapters?: PlatformAdapter[];\n /** System prompt for the agent (same as agent-chat). Inherited from agent-chat plugin if not set. */\n systemPrompt?: string;\n /** Actions registry (same as agent-chat). */\n actions?: Record<string, import(\"../agent/production-agent.js\").ActionEntry>;\n /** Model to use. Defaults to the resolved engine's default model. */\n model?: string;\n /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var. */\n apiKey?: string;\n /** Agent engine to use. Defaults to the same engine resolver as web chat. */\n engine?:\n | import(\"../agent/engine/types.js\").AgentEngine\n | string\n | {\n name: string;\n config: Record<string, unknown>;\n };\n /**\n * Resolve which owner should receive personal resource context and own the\n * created chat thread for an incoming platform message.\n */\n resolveOwner?: (incoming: IncomingMessage) => string | Promise<string>;\n /**\n * Optional preprocessor for inbound platform messages. Can intercept special\n * commands (such as `/link`) before the agent loop runs.\n */\n beforeProcess?: (\n incoming: IncomingMessage,\n adapter: PlatformAdapter,\n ) => Promise<\n | {\n handled: true;\n responseText?: string;\n }\n | { handled: false }\n >;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/integrations/types.ts"],"names":[],"mappings":"","sourcesContent":["import type { H3Event } from \"h3\";\nimport type { EnvKeyConfig } from \"../server/create-server.js\";\n\n/**\n * Normalized incoming message from any messaging platform.\n */\nexport interface IncomingMessage {\n /** Platform identifier (e.g., \"slack\", \"telegram\", \"whatsapp\") */\n platform: string;\n /** Platform-specific thread/conversation identifier */\n externalThreadId: string;\n /** Message text content */\n text: string;\n /** Display name of the sender */\n senderName?: string;\n /** Verified sender email, when the platform can provide one */\n senderEmail?: string;\n /** Platform-specific sender ID */\n senderId?: string;\n /**\n * Whether the platform cryptographically authenticated that the message\n * genuinely came from the claimed sender (e.g. inbound email that passed\n * DKIM, or an aligned SPF pass, for the From domain). Defaults to\n * undefined/false for platforms that don't provide sender authentication.\n *\n * Owner-resolution paths that grant a real user's identity/credentials\n * MUST treat a missing/false value as \"unverified\" and fail closed —\n * never derive a privileged acting identity from an unverified sender.\n */\n senderVerified?: boolean;\n /** Raw platform-specific context needed for routing responses */\n platformContext: Record<string, unknown>;\n /** Message timestamp (epoch ms) */\n timestamp: number;\n}\n\n/**\n * Outgoing message to send back to a messaging platform.\n */\nexport interface OutgoingMessage {\n /** Text content of the response */\n text: string;\n /** Platform-specific payload (e.g., Slack blocks, Telegram parse_mode) */\n platformContext: Record<string, unknown>;\n}\n\n/**\n * Proactive outbound message target for a platform.\n * Used when the agent needs to send to a saved destination instead of replying\n * to the current inbound thread.\n */\nexport interface OutboundTarget {\n /** Canonical platform-specific destination id (channel, chat, thread, etc.) */\n destination: string;\n /** Optional thread reference when the destination supports threading */\n threadRef?: string | null;\n /** Optional fallback display label */\n label?: string;\n}\n\n/**\n * Connection status for a platform integration.\n */\nexport interface IntegrationStatus {\n platform: string;\n /** Human-readable label (e.g., \"Slack\", \"Telegram\") */\n label: string;\n /** Whether the integration is explicitly enabled */\n enabled: boolean;\n /** Whether all required credentials are configured */\n configured: boolean;\n /** Platform-specific details (workspace name, bot username, etc.) */\n details?: Record<string, unknown>;\n /** Error message if something is wrong */\n error?: string;\n /** The webhook URL that should be configured in the platform */\n webhookUrl?: string;\n /** The full list of env keys (required + optional) the adapter recognizes,\n * including UI hints. Surfaced on the integrations status endpoint so the\n * frontend can render fields without hard-coding them per platform. */\n requiredEnvKeys?: import(\"../server/create-server.js\").EnvKeyConfig[];\n}\n\n/**\n * Platform adapter interface — implement this for each messaging platform.\n *\n * Each adapter handles the platform-specific concerns:\n * - Webhook verification (HMAC signatures, challenge responses)\n * - Message parsing (platform events → normalized IncomingMessage)\n * - Response formatting (agent text → platform-specific format)\n * - Response delivery (POST back to platform API)\n */\nexport interface PlatformAdapter {\n /** Unique platform identifier */\n readonly platform: string;\n /** Human-readable label */\n readonly label: string;\n\n /** Env keys this adapter needs (tokens, secrets, etc.) */\n getRequiredEnvKeys(): EnvKeyConfig[];\n\n /**\n * Handle platform-specific verification challenges.\n * For example, Slack sends a `url_verification` event when setting up.\n * Return `{ handled: true, response }` to short-circuit the webhook handler.\n */\n handleVerification(event: H3Event): Promise<{\n handled: boolean;\n response?: unknown;\n }>;\n\n /**\n * Validate the webhook request signature.\n * Returns true if the request is authentic.\n */\n verifyWebhook(event: H3Event): Promise<boolean>;\n\n /**\n * Parse the webhook payload into a normalized IncomingMessage.\n * Return null to silently ignore the event (bot messages, edits, etc.).\n */\n parseIncomingMessage(event: H3Event): Promise<IncomingMessage | null>;\n\n /**\n * Send the agent's response back to the messaging platform.\n *\n * If `opts.placeholderRef` is provided (returned earlier by\n * `postProcessingPlaceholder`), adapters that support in-place edits should\n * update that placeholder message rather than posting a new one. Adapters\n * without an \"update message\" API can ignore the ref and post fresh.\n */\n sendResponse(\n message: OutgoingMessage,\n context: IncomingMessage,\n opts?: { placeholderRef?: string },\n ): Promise<void>;\n\n /**\n * Optionally post a \"working on it…\" placeholder message immediately when a\n * webhook arrives, before the agent loop runs. Adapters that support\n * in-place message edits (Slack via `chat.update`, etc.) return an opaque\n * `placeholderRef` that the webhook flow threads through to `sendResponse`\n * so the same message is updated with the final answer once ready.\n *\n * Adapters without edit support should leave this undefined; the webhook\n * handler will skip the placeholder step entirely.\n */\n postProcessingPlaceholder?(\n incoming: IncomingMessage,\n ): Promise<{ placeholderRef: string } | null>;\n\n /**\n * Send a proactive outbound message to a platform destination. Adapters that\n * only support direct replies can omit this.\n */\n sendMessageToTarget?(\n message: OutgoingMessage,\n target: OutboundTarget,\n ): Promise<void>;\n\n /**\n * Format plain agent response text into a platform-appropriate message.\n * Handles markdown conversion, message splitting for length limits, etc.\n *\n * `opts.threadDeepLinkUrl`, when present, is a URL back to the originating\n * thread in the dispatch UI. Adapters that support rich blocks should\n * render this as a button (Slack); adapters that don't may inline it as a\n * link or simply omit it.\n */\n formatAgentResponse(\n text: string,\n opts?: { threadDeepLinkUrl?: string },\n ): OutgoingMessage;\n\n /** Return current connection/configuration status for the settings UI. */\n getStatus(baseUrl?: string): Promise<IntegrationStatus>;\n}\n\n/**\n * Options for the integrations plugin.\n */\nexport interface IntegrationsPluginOptions {\n /** App identifier used by call-agent to prevent self-calls (e.g. \"dispatch\"). */\n appId?: string;\n /** Platform adapters to enable. Default: all built-in adapters with configured env keys. */\n adapters?: PlatformAdapter[];\n /** System prompt for the agent (same as agent-chat). Inherited from agent-chat plugin if not set. */\n systemPrompt?: string;\n /** Actions registry (same as agent-chat). */\n actions?: Record<string, import(\"../agent/production-agent.js\").ActionEntry>;\n /** Model to use. Defaults to the resolved engine's default model. */\n model?: string;\n /** Anthropic API key. Falls back to ANTHROPIC_API_KEY env var. */\n apiKey?: string;\n /** Agent engine to use. Defaults to the same engine resolver as web chat. */\n engine?:\n | import(\"../agent/engine/types.js\").AgentEngine\n | string\n | {\n name: string;\n config: Record<string, unknown>;\n };\n /**\n * Resolve which owner should receive personal resource context and own the\n * created chat thread for an incoming platform message.\n */\n resolveOwner?: (incoming: IncomingMessage) => string | Promise<string>;\n /**\n * Optional preprocessor for inbound platform messages. Can intercept special\n * commands (such as `/link`) before the agent loop runs.\n */\n beforeProcess?: (\n incoming: IncomingMessage,\n adapter: PlatformAdapter,\n ) => Promise<\n | {\n handled: true;\n responseText?: string;\n }\n | { handled: false }\n >;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../../src/scripts/db/exec.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAylBH,wBAA8B,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAyJlE"}
|
package/dist/scripts/db/exec.js
CHANGED
|
@@ -17,7 +17,7 @@ import path from "path";
|
|
|
17
17
|
import { getDatabaseUrl } from "../../db/client.js";
|
|
18
18
|
import { parseArgs, fail } from "../utils.js";
|
|
19
19
|
import { buildScopingPostgres, buildScopingSqlite, } from "./scoping.js";
|
|
20
|
-
import { assertNoRawDbAccessControlWrite, assertNoSensitiveFrameworkTables, } from "./safety.js";
|
|
20
|
+
import { assertNoRawDbAccessControlWrite, assertNoSchemaQualifiedTables, assertNoSensitiveFrameworkTables, } from "./safety.js";
|
|
21
21
|
import { createSqliteScriptClient } from "./sqlite-client.js";
|
|
22
22
|
function isPostgresUrl(url) {
|
|
23
23
|
return url.startsWith("postgres://") || url.startsWith("postgresql://");
|
|
@@ -161,6 +161,7 @@ function validateWriteSql(sql, index) {
|
|
|
161
161
|
}
|
|
162
162
|
assertNoSensitiveFrameworkTables(normalized, "write");
|
|
163
163
|
assertNoRawDbAccessControlWrite(normalized);
|
|
164
|
+
assertNoSchemaQualifiedTables(normalized, "write");
|
|
164
165
|
return normalized;
|
|
165
166
|
}
|
|
166
167
|
function convertQuestionMarksToPostgresParams(sql) {
|