@vibesdotdev/integrations-resend 0.0.0-stage → 1.0.0-rc.3
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/LICENSE +126 -0
- package/README.md +21 -2
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/runtime-client.d.ts +12 -0
- package/dist/client/runtime-client.d.ts.map +1 -0
- package/dist/client/runtime-client.js +61 -0
- package/dist/client/runtime-client.js.map +1 -0
- package/dist/config/resend.config.descriptor.d.ts +46 -0
- package/dist/config/resend.config.descriptor.d.ts.map +1 -0
- package/dist/config/resend.config.descriptor.js +50 -0
- package/dist/config/resend.config.descriptor.js.map +1 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/resend/index.d.ts +10 -0
- package/dist/resend/index.d.ts.map +1 -0
- package/dist/resend/index.js +10 -0
- package/dist/resend/index.js.map +1 -0
- package/dist/resend/resend-events.descriptors.d.ts +62 -0
- package/dist/resend/resend-events.descriptors.d.ts.map +1 -0
- package/dist/resend/resend-events.descriptors.js +55 -0
- package/dist/resend/resend-events.descriptors.js.map +1 -0
- package/dist/resend/resend-events.impls.d.ts +35 -0
- package/dist/resend/resend-events.impls.d.ts.map +1 -0
- package/dist/resend/resend-events.impls.js +115 -0
- package/dist/resend/resend-events.impls.js.map +1 -0
- package/dist/resend/resend-message-source.descriptor.d.ts +30 -0
- package/dist/resend/resend-message-source.descriptor.d.ts.map +1 -0
- package/dist/resend/resend-message-source.descriptor.js +24 -0
- package/dist/resend/resend-message-source.descriptor.js.map +1 -0
- package/dist/resend/resend-normalize.d.ts +24 -0
- package/dist/resend/resend-normalize.d.ts.map +1 -0
- package/dist/resend/resend-normalize.js +22 -0
- package/dist/resend/resend-normalize.js.map +1 -0
- package/dist/resend/resend-received.d.ts +26 -0
- package/dist/resend/resend-received.d.ts.map +1 -0
- package/dist/resend/resend-received.js +26 -0
- package/dist/resend/resend-received.js.map +1 -0
- package/dist/resend/resend-response.d.ts +3 -0
- package/dist/resend/resend-response.d.ts.map +1 -0
- package/dist/resend/resend-response.js +14 -0
- package/dist/resend/resend-response.js.map +1 -0
- package/dist/resend/resend-signature-verifier.descriptor.d.ts +20 -0
- package/dist/resend/resend-signature-verifier.descriptor.d.ts.map +1 -0
- package/dist/resend/resend-signature-verifier.descriptor.js +20 -0
- package/dist/resend/resend-signature-verifier.descriptor.js.map +1 -0
- package/dist/resend/resend-signature-verifier.impl.d.ts +16 -0
- package/dist/resend/resend-signature-verifier.impl.d.ts.map +1 -0
- package/dist/resend/resend-signature-verifier.impl.js +19 -0
- package/dist/resend/resend-signature-verifier.impl.js.map +1 -0
- package/dist/resend/resend-signature.d.ts +32 -0
- package/dist/resend/resend-signature.d.ts.map +1 -0
- package/dist/resend/resend-signature.js +77 -0
- package/dist/resend/resend-signature.js.map +1 -0
- package/dist/resend/resend-webhook.descriptor.d.ts +39 -0
- package/dist/resend/resend-webhook.descriptor.d.ts.map +1 -0
- package/dist/resend/resend-webhook.descriptor.js +24 -0
- package/dist/resend/resend-webhook.descriptor.js.map +1 -0
- package/dist/resend/resend-webhook.impl.d.ts +19 -0
- package/dist/resend/resend-webhook.impl.d.ts.map +1 -0
- package/dist/resend/resend-webhook.impl.js +111 -0
- package/dist/resend/resend-webhook.impl.js.map +1 -0
- package/dist/resend/resend.descriptor.d.ts +37 -0
- package/dist/resend/resend.descriptor.d.ts.map +1 -0
- package/dist/resend/resend.descriptor.js +107 -0
- package/dist/resend/resend.descriptor.js.map +1 -0
- package/dist/resend/resend.impl.d.ts +24 -0
- package/dist/resend/resend.impl.d.ts.map +1 -0
- package/dist/resend/resend.impl.js +258 -0
- package/dist/resend/resend.impl.js.map +1 -0
- package/dist/resend.plugin.d.ts +19 -0
- package/dist/resend.plugin.d.ts.map +1 -0
- package/dist/resend.plugin.js +88 -0
- package/dist/resend.plugin.js.map +1 -0
- package/dist/schemas/resend.d.ts +421 -0
- package/dist/schemas/resend.d.ts.map +1 -0
- package/dist/schemas/resend.js +97 -0
- package/dist/schemas/resend.js.map +1 -0
- package/package.json +134 -4
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime implementations for the Resend `tools/webhook-event-definition`
|
|
3
|
+
* descriptors. Each impl extracts a normalized payload from Resend's raw
|
|
4
|
+
* webhook body, builds a marshal task spec, and (for `email.received`) builds
|
|
5
|
+
* the `update_lead` outbox entry.
|
|
6
|
+
*
|
|
7
|
+
* The received parser accepts both the provider envelope and an enriched
|
|
8
|
+
* received-email resource. RFC reply identity stays distinct from the API id.
|
|
9
|
+
*/
|
|
10
|
+
import { normalizeReceived } from "./resend-normalize.js";
|
|
11
|
+
import { CapabilityError } from '@vibesdotdev/kernel';
|
|
12
|
+
import { identityValueSchema, receivedPayloadSchema, receivedWebhookSchema, webhookPayloadSchema } from "../schemas/resend.js";
|
|
13
|
+
import { resendEmailBouncedDescriptor, resendEmailComplainedDescriptor, resendEmailDeliveredDescriptor, resendEmailReceivedDescriptor } from "./resend-events.descriptors.js";
|
|
14
|
+
function generateId() {
|
|
15
|
+
return crypto.randomUUID();
|
|
16
|
+
}
|
|
17
|
+
function nowIso() {
|
|
18
|
+
return new Date().toISOString();
|
|
19
|
+
}
|
|
20
|
+
class ResendEmailReceived {
|
|
21
|
+
descriptor = resendEmailReceivedDescriptor;
|
|
22
|
+
idempotencyKey(parsed) {
|
|
23
|
+
const value = identityValueSchema.safeParse(parsed.email_id);
|
|
24
|
+
const emailId = value.success ? value.data : '';
|
|
25
|
+
return emailId ? `resend:email.received:${encodeURIComponent(emailId)}` : null;
|
|
26
|
+
}
|
|
27
|
+
parse(raw) {
|
|
28
|
+
if ('data' in raw || 'type' in raw) {
|
|
29
|
+
if (!receivedWebhookSchema.safeParse(raw).success)
|
|
30
|
+
throw new CapabilityError('Invalid Resend received event.', 'INVALID_INPUT', { reason: 'resend-webhook-invalid' });
|
|
31
|
+
}
|
|
32
|
+
return normalizeReceived(raw);
|
|
33
|
+
}
|
|
34
|
+
buildTask(parsed) {
|
|
35
|
+
return {
|
|
36
|
+
title: `Inbound: ${receivedPayloadSchema.parse(parsed).subject || '(no subject)'}`,
|
|
37
|
+
lane: 'webhook',
|
|
38
|
+
description: `New email from ${parsed.from} to ${parsed.to}`,
|
|
39
|
+
priority: 'medium',
|
|
40
|
+
assigned_to: 'marshal-webhook'
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
buildOutbox(parsed) {
|
|
44
|
+
return [
|
|
45
|
+
{
|
|
46
|
+
id: generateId(),
|
|
47
|
+
source: 'resend',
|
|
48
|
+
webhook_request_id: '',
|
|
49
|
+
action: 'update_lead',
|
|
50
|
+
payload: {
|
|
51
|
+
contact_email: parsed.from,
|
|
52
|
+
subject: parsed.subject,
|
|
53
|
+
direction: 'inbound',
|
|
54
|
+
message_id: parsed.message_id
|
|
55
|
+
},
|
|
56
|
+
status: 'pending',
|
|
57
|
+
created_at: nowIso()
|
|
58
|
+
}
|
|
59
|
+
];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function deliveryPayload(raw, type) {
|
|
63
|
+
if ('data' in raw || 'type' in raw) {
|
|
64
|
+
const event = webhookPayloadSchema.safeParse(raw);
|
|
65
|
+
if (!event.success || event.data.type !== type)
|
|
66
|
+
throw new CapabilityError('Invalid Resend delivery event.', 'INVALID_INPUT', { reason: 'resend-webhook-invalid' });
|
|
67
|
+
}
|
|
68
|
+
const payload = receivedPayloadSchema.parse('data' in raw ? raw.data : raw);
|
|
69
|
+
return {
|
|
70
|
+
message_id: payload.email_id || payload.id, from: payload.from, to: payload.to[0] ?? '',
|
|
71
|
+
subject: payload.subject, bounce_reason: payload.bounce?.message || payload.reason,
|
|
72
|
+
created_at: payload.created_at || nowIso()
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
class ResendEmailBounced {
|
|
76
|
+
descriptor = resendEmailBouncedDescriptor;
|
|
77
|
+
parse(raw) { return deliveryPayload(raw, 'email.bounced'); }
|
|
78
|
+
buildTask(parsed) {
|
|
79
|
+
return {
|
|
80
|
+
title: `Bounce: ${receivedPayloadSchema.parse(parsed).subject || '(no subject)'}`,
|
|
81
|
+
lane: 'webhook',
|
|
82
|
+
description: `Email to ${parsed.to} bounced: ${parsed.bounce_reason}`,
|
|
83
|
+
priority: 'low',
|
|
84
|
+
assigned_to: 'marshal-webhook'
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
class ResendEmailDelivered {
|
|
89
|
+
descriptor = resendEmailDeliveredDescriptor;
|
|
90
|
+
parse(raw) { return deliveryPayload(raw, 'email.delivered'); }
|
|
91
|
+
buildTask(parsed) {
|
|
92
|
+
return {
|
|
93
|
+
title: `Delivered: ${receivedPayloadSchema.parse(parsed).subject || '(no subject)'}`,
|
|
94
|
+
lane: 'webhook',
|
|
95
|
+
description: `Email delivered to ${parsed.to}`,
|
|
96
|
+
priority: 'low',
|
|
97
|
+
assigned_to: 'marshal-webhook'
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
class ResendEmailComplained {
|
|
102
|
+
descriptor = resendEmailComplainedDescriptor;
|
|
103
|
+
parse(raw) { return deliveryPayload(raw, 'email.complained'); }
|
|
104
|
+
buildTask(parsed) {
|
|
105
|
+
return {
|
|
106
|
+
title: `Spam complaint: ${parsed.subject}`,
|
|
107
|
+
lane: 'webhook',
|
|
108
|
+
description: `Spam complaint from ${parsed.to}`,
|
|
109
|
+
priority: 'high',
|
|
110
|
+
assigned_to: 'marshal-webhook'
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
export { ResendEmailReceived, ResendEmailBounced, ResendEmailDelivered, ResendEmailComplained };
|
|
115
|
+
//# sourceMappingURL=resend-events.impls.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-events.impls.js","sourceRoot":"","sources":["../../src/resend/resend-events.impls.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
declare const _default: {
|
|
2
|
+
id: string;
|
|
3
|
+
kind: "agent/event-source";
|
|
4
|
+
name: string;
|
|
5
|
+
sourceType: "webhook" | "schedule" | "system" | "channel" | "integration";
|
|
6
|
+
status: "error" | "active" | "paused" | "disconnected";
|
|
7
|
+
agentIds: string[];
|
|
8
|
+
config: Record<string, unknown>;
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
description?: string | undefined;
|
|
11
|
+
filters?: {
|
|
12
|
+
eventTypes?: string[] | undefined;
|
|
13
|
+
channels?: string[] | undefined;
|
|
14
|
+
guilds?: string[] | undefined;
|
|
15
|
+
keywords?: string[] | undefined;
|
|
16
|
+
minPriority?: number | undefined;
|
|
17
|
+
} | undefined;
|
|
18
|
+
integrationId?: string | undefined;
|
|
19
|
+
schedule?: {
|
|
20
|
+
cron?: string | undefined;
|
|
21
|
+
intervalMs?: number | undefined;
|
|
22
|
+
} | undefined;
|
|
23
|
+
userId?: string | undefined;
|
|
24
|
+
projectId?: string | undefined;
|
|
25
|
+
organizationId?: string | undefined;
|
|
26
|
+
hardware?: ("consumer" | "cloud")[] | undefined;
|
|
27
|
+
tags?: string[] | undefined;
|
|
28
|
+
};
|
|
29
|
+
export default _default;
|
|
30
|
+
//# sourceMappingURL=resend-message-source.descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-message-source.descriptor.d.ts","sourceRoot":"","sources":["../../src/resend/resend-message-source.descriptor.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAGA,wBAqBG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { createRuntimeAsset } from '@vibesdotdev/kernel/factory';
|
|
2
|
+
export default createRuntimeAsset({
|
|
3
|
+
kind: 'agent/event-source',
|
|
4
|
+
id: 'message.email.resend',
|
|
5
|
+
name: 'Resend Email',
|
|
6
|
+
description: 'Inbound Resend email. Agent deployments select the connected account and receiving mailbox.',
|
|
7
|
+
sourceType: 'integration',
|
|
8
|
+
status: 'disconnected',
|
|
9
|
+
agentIds: [],
|
|
10
|
+
integrationId: 'integration.email.resend',
|
|
11
|
+
config: {
|
|
12
|
+
provider: 'resend',
|
|
13
|
+
category: 'email',
|
|
14
|
+
eventTypes: ['email.received'],
|
|
15
|
+
operations: ['send', 'check'],
|
|
16
|
+
credentialKeys: ['apiKey', 'webhookSecret'],
|
|
17
|
+
inbound: { type: 'webhook', source: 'resend' }
|
|
18
|
+
},
|
|
19
|
+
filters: { eventTypes: ['email.received'] },
|
|
20
|
+
enabled: true,
|
|
21
|
+
hardware: ['cloud', 'consumer'],
|
|
22
|
+
tags: ['messaging', 'email', 'resend', 'agent-event-source']
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=resend-message-source.descriptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-message-source.descriptor.js","sourceRoot":"","sources":["../../src/resend/resend-message-source.descriptor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAGjE,eAAe,kBAAkB,CAA6B;IAC7D,IAAI,EAAE,oBAAoB;IAC1B,EAAE,EAAE,sBAAsB;IAC1B,IAAI,EAAE,cAAc;IACpB,WAAW,EAAE,6FAA6F;IAC1G,UAAU,EAAE,aAAa;IACzB,MAAM,EAAE,cAAc;IACtB,QAAQ,EAAE,EAAE;IACZ,aAAa,EAAE,0BAA0B;IACzC,MAAM,EAAE;QACP,QAAQ,EAAE,QAAQ;QAClB,QAAQ,EAAE,OAAO;QACjB,UAAU,EAAE,CAAC,gBAAgB,CAAC;QAC9B,UAAU,EAAE,CAAC,MAAM,EAAE,OAAO,CAAC;QAC7B,cAAc,EAAE,CAAC,QAAQ,EAAE,eAAe,CAAC;QAC3C,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;KAC9C;IACD,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,gBAAgB,CAAC,EAAE;IAC3C,OAAO,EAAE,IAAI;IACb,QAAQ,EAAE,CAAC,OAAO,EAAE,UAAU,CAAC;IAC/B,IAAI,EAAE,CAAC,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,oBAAoB,CAAC;CAC5D,CAAC,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { JsonObject } from '@vibesdotdev/kernel/schemas/json';
|
|
2
|
+
/** Pure shared normalization for verified events and selected-account hydration. */
|
|
3
|
+
export declare function normalizeReceived(raw: JsonObject): {
|
|
4
|
+
message_id: string;
|
|
5
|
+
email_id: string;
|
|
6
|
+
from: string;
|
|
7
|
+
to: string;
|
|
8
|
+
to_addresses: string[];
|
|
9
|
+
cc: string[];
|
|
10
|
+
bcc: string[];
|
|
11
|
+
received_for: string[];
|
|
12
|
+
subject: string;
|
|
13
|
+
body_text: string;
|
|
14
|
+
body_html: string;
|
|
15
|
+
reply_to: string;
|
|
16
|
+
reply_to_addresses: string[];
|
|
17
|
+
in_reply_to: string;
|
|
18
|
+
references: string | string[];
|
|
19
|
+
headers: Record<string, string>;
|
|
20
|
+
thread_id: string;
|
|
21
|
+
attachments: import("@vibesdotdev/kernel/bootstrap").JsonValue[];
|
|
22
|
+
created_at: string;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=resend-normalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-normalize.d.ts","sourceRoot":"","sources":["../../src/resend/resend-normalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAGnE,oFAAoF;AACpF,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;EAkBhD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { receivedEnvelopeSchema, receivedPayloadSchema, normalizedReceivedSchema } from "../schemas/resend.js";
|
|
2
|
+
/** Pure shared normalization for verified events and selected-account hydration. */
|
|
3
|
+
export function normalizeReceived(raw) {
|
|
4
|
+
const envelope = 'data' in raw ? { success: true, data: receivedEnvelopeSchema.parse(raw) } : undefined;
|
|
5
|
+
const payload = envelope ? envelope.data.data : receivedPayloadSchema.parse(raw);
|
|
6
|
+
const headers = payload.headers;
|
|
7
|
+
const header = (name) => Object.entries(headers).find(([key]) => key.toLowerCase() === name)?.[1] ?? '';
|
|
8
|
+
const replyTo = payload.reply_to.length ? payload.reply_to : [header('reply-to')].filter(Boolean);
|
|
9
|
+
return normalizedReceivedSchema.parse({
|
|
10
|
+
message_id: header('message-id') || payload.message_id || payload.messageId || payload.id,
|
|
11
|
+
email_id: payload.email_id || payload.id, from: payload.from,
|
|
12
|
+
to: payload.to[0] ?? '', to_addresses: payload.to, cc: payload.cc, bcc: payload.bcc,
|
|
13
|
+
received_for: payload.received_for, subject: payload.subject,
|
|
14
|
+
body_text: payload.text || payload.body_text, body_html: payload.html || payload.body_html,
|
|
15
|
+
reply_to: replyTo[0] ?? '', reply_to_addresses: replyTo,
|
|
16
|
+
in_reply_to: payload.in_reply_to || header('in-reply-to'),
|
|
17
|
+
references: payload.references.length ? payload.references : header('references'),
|
|
18
|
+
headers, thread_id: payload.thread_id || payload.threadId, attachments: payload.attachments,
|
|
19
|
+
created_at: payload.created_at || (envelope ? envelope.data.created_at : '') || new Date().toISOString()
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=resend-normalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-normalize.js","sourceRoot":"","sources":["../../src/resend/resend-normalize.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAE/G,oFAAoF;AACpF,MAAM,UAAU,iBAAiB,CAAC,GAAe;IAChD,MAAM,QAAQ,GAAG,MAAM,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,sBAAsB,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC;IACxG,MAAM,OAAO,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,qBAAqB,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACjF,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAChC,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,WAAW,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAChH,MAAM,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAClG,OAAO,wBAAwB,CAAC,KAAK,CAAC;QACrC,UAAU,EAAE,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,EAAE;QACzF,QAAQ,EAAE,OAAO,CAAC,QAAQ,IAAI,OAAO,CAAC,EAAE,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI;QAC5D,EAAE,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG;QACnF,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO;QAC5D,SAAS,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,SAAS,EAAE,SAAS,EAAE,OAAO,CAAC,IAAI,IAAI,OAAO,CAAC,SAAS;QAC1F,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,EAAE,EAAE,kBAAkB,EAAE,OAAO;QACvD,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,MAAM,CAAC,aAAa,CAAC;QACzD,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC;QACjF,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,WAAW;QAC3F,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;KACxG,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type RuntimeHttpFetch } from '@vibesdotdev/kernel';
|
|
2
|
+
import { type ResendReceivedEmailInput } from '../schemas/resend.ts';
|
|
3
|
+
export type { ResendReceivedEmailInput } from '../schemas/resend.ts';
|
|
4
|
+
/** Retrieve the selected resource before normalizing complete content. */
|
|
5
|
+
export declare function retrieveResendReceivedEmail(httpFetch: RuntimeHttpFetch, input: ResendReceivedEmailInput): Promise<{
|
|
6
|
+
message_id: string;
|
|
7
|
+
email_id: string;
|
|
8
|
+
from: string;
|
|
9
|
+
to: string;
|
|
10
|
+
to_addresses: string[];
|
|
11
|
+
cc: string[];
|
|
12
|
+
bcc: string[];
|
|
13
|
+
received_for: string[];
|
|
14
|
+
subject: string;
|
|
15
|
+
body_text: string;
|
|
16
|
+
body_html: string;
|
|
17
|
+
reply_to: string;
|
|
18
|
+
reply_to_addresses: string[];
|
|
19
|
+
in_reply_to: string;
|
|
20
|
+
references: string | string[];
|
|
21
|
+
headers: Record<string, string>;
|
|
22
|
+
thread_id: string;
|
|
23
|
+
attachments: import("@vibesdotdev/kernel/bootstrap").JsonValue[];
|
|
24
|
+
created_at: string;
|
|
25
|
+
}>;
|
|
26
|
+
//# sourceMappingURL=resend-received.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-received.d.ts","sourceRoot":"","sources":["../../src/resend/resend-received.ts"],"names":[],"mappings":"AACA,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE7E,OAAO,EAAgD,KAAK,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAEnH,YAAY,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAErE,0EAA0E;AAC1E,wBAAsB,2BAA2B,CAAC,SAAS,EAAE,gBAAgB,EAAE,KAAK,EAAE,wBAAwB;;;;;;;;;;;;;;;;;;;;GAc7G"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { readResendResponse } from "./resend-response.js";
|
|
2
|
+
import { CapabilityError } from '@vibesdotdev/kernel';
|
|
3
|
+
import { JsonObjectSchema } from '@vibesdotdev/kernel/schemas/json';
|
|
4
|
+
import { receivedResourceSchema, retrievalInputSchema } from "../schemas/resend.js";
|
|
5
|
+
import { normalizeReceived } from "./resend-normalize.js";
|
|
6
|
+
/** Retrieve the selected resource before normalizing complete content. */
|
|
7
|
+
export async function retrieveResendReceivedEmail(httpFetch, input) {
|
|
8
|
+
const admittedInput = retrievalInputSchema.safeParse(input);
|
|
9
|
+
if (!admittedInput.success)
|
|
10
|
+
throw new CapabilityError('Resend received email requires emailId, selected apiKey and baseUrl.', 'INVALID_INPUT', { reason: 'resend-received-input-invalid' });
|
|
11
|
+
input = admittedInput.data;
|
|
12
|
+
const response = await httpFetch(`${input.baseUrl.replace(/\/$/, '')}/emails/receiving/${encodeURIComponent(input.emailId)}`, {
|
|
13
|
+
method: 'GET', headers: { authorization: `Bearer ${input.apiKey}`, accept: 'application/json' },
|
|
14
|
+
redirect: 'error', signal: input.signal ?? AbortSignal.timeout(15_000)
|
|
15
|
+
});
|
|
16
|
+
if (!response.ok)
|
|
17
|
+
throw new CapabilityError(`Resend received-email retrieval failed (${response.status}).`, 'UNAVAILABLE', { reason: 'resend-upstream-refused', details: { status: response.status } });
|
|
18
|
+
const body = await readResendResponse(response);
|
|
19
|
+
const admitted = receivedResourceSchema.safeParse(body);
|
|
20
|
+
if (!admitted.success)
|
|
21
|
+
throw new CapabilityError('Resend received-email response is missing full content, headers or message identity.', 'UNAVAILABLE', { reason: 'resend-received-invalid' });
|
|
22
|
+
if (admitted.data.id !== input.emailId)
|
|
23
|
+
throw new CapabilityError('Resend received-email response identity does not match the requested email.', 'UNAVAILABLE', { reason: 'resend-received-invalid' });
|
|
24
|
+
return normalizeReceived(JsonObjectSchema.parse(body));
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=resend-received.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-received.js","sourceRoot":"","sources":["../../src/resend/resend-received.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,eAAe,EAAyB,MAAM,qBAAqB,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAiC,MAAM,sBAAsB,CAAC;AACnH,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAG1D,0EAA0E;AAC1E,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAAC,SAA2B,EAAE,KAA+B;IAC7G,MAAM,aAAa,GAAG,oBAAoB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,IAAI,CAAC,aAAa,CAAC,OAAO;QAAE,MAAM,IAAI,eAAe,CAAC,sEAAsE,EAAE,eAAe,EAAE,EAAE,MAAM,EAAE,+BAA+B,EAAE,CAAC,CAAC;IAC5L,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC;IAC3B,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,qBAAqB,kBAAkB,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,EAAE;QAC7H,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,KAAK,CAAC,MAAM,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE;QAC/F,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC;KACtE,CAAC,CAAC;IACH,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,MAAM,IAAI,eAAe,CAAC,2CAA2C,QAAQ,CAAC,MAAM,IAAI,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxM,MAAM,IAAI,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,CAAC;IAChD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IACxD,IAAI,CAAC,QAAQ,CAAC,OAAO;QAAE,MAAM,IAAI,eAAe,CAAC,sFAAsF,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,CAAC;IAC/L,IAAI,QAAQ,CAAC,IAAI,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO;QAAE,MAAM,IAAI,eAAe,CAAC,6EAA6E,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,yBAAyB,EAAE,CAAC,CAAC;IACvM,OAAO,iBAAiB,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-response.d.ts","sourceRoot":"","sources":["../../src/resend/resend-response.ts"],"names":[],"mappings":"AAGA,iFAAiF;AACjF,wBAAsB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,8DAQ1D"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CapabilityError, CaughtFailureSchema, valueFreeFailure } from '@vibesdotdev/kernel';
|
|
2
|
+
import { JsonValueSchema } from '@vibesdotdev/kernel/schemas/json';
|
|
3
|
+
/** Upstream parse failures retain value-free facts, never response fragments. */
|
|
4
|
+
export async function readResendResponse(response) {
|
|
5
|
+
try {
|
|
6
|
+
return JsonValueSchema.parse(await response.json());
|
|
7
|
+
}
|
|
8
|
+
catch (cause) {
|
|
9
|
+
throw new CapabilityError('Resend returned an invalid JSON response.', 'UNAVAILABLE', {
|
|
10
|
+
reason: 'resend-result-invalid', details: { status: response.status, failure: valueFreeFailure(CaughtFailureSchema.parse(cause)) }
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=resend-response.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-response.js","sourceRoot":"","sources":["../../src/resend/resend-response.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC7F,OAAO,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAEnE,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,QAAkB;IAC1D,IAAI,CAAC;QACJ,OAAO,eAAe,CAAC,KAAK,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC;IACrD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,IAAI,eAAe,CAAC,2CAA2C,EAAE,aAAa,EAAE;YACrF,MAAM,EAAE,uBAAuB,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,EAAE,OAAO,EAAE,gBAAgB,CAAC,mBAAmB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE;SAClI,CAAC,CAAC;IACJ,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `tools/signature-verifier` descriptor for Resend (Svix) webhook signatures.
|
|
3
|
+
*
|
|
4
|
+
* Consumed by `processWebhook` in `@vibesdotdev/tools/webhooks/router` to
|
|
5
|
+
* verify incoming Resend webhook deliveries against the `RESEND_WEBHOOK_SECRET`
|
|
6
|
+
* env-resolved secret. The descriptor id is referenced by source name; the
|
|
7
|
+
* router filters `tools/signature-verifier` descriptors by `source === 'resend'`.
|
|
8
|
+
*/
|
|
9
|
+
declare const _default: {
|
|
10
|
+
id: string;
|
|
11
|
+
kind: "tools/signature-verifier";
|
|
12
|
+
name: string;
|
|
13
|
+
source: string;
|
|
14
|
+
description?: string | undefined;
|
|
15
|
+
headerName?: string | undefined;
|
|
16
|
+
signingSecretEnv?: string | undefined;
|
|
17
|
+
tags?: string[] | undefined;
|
|
18
|
+
};
|
|
19
|
+
export default _default;
|
|
20
|
+
//# sourceMappingURL=resend-signature-verifier.descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-signature-verifier.descriptor.d.ts","sourceRoot":"","sources":["../../src/resend/resend-signature-verifier.descriptor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;;;;;;;;;;;AAKH,wBASG"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `tools/signature-verifier` descriptor for Resend (Svix) webhook signatures.
|
|
3
|
+
*
|
|
4
|
+
* Consumed by `processWebhook` in `@vibesdotdev/tools/webhooks/router` to
|
|
5
|
+
* verify incoming Resend webhook deliveries against the `RESEND_WEBHOOK_SECRET`
|
|
6
|
+
* env-resolved secret. The descriptor id is referenced by source name; the
|
|
7
|
+
* router filters `tools/signature-verifier` descriptors by `source === 'resend'`.
|
|
8
|
+
*/
|
|
9
|
+
import { createRuntimeAsset } from '@vibesdotdev/kernel';
|
|
10
|
+
export default createRuntimeAsset({
|
|
11
|
+
kind: 'tools/signature-verifier',
|
|
12
|
+
id: 'signature-verifier.resend',
|
|
13
|
+
name: 'Resend Webhook Signature Verifier',
|
|
14
|
+
description: 'Verifies Svix-signed Resend webhook deliveries (HMAC-SHA256 over svix-id.svix-timestamp.rawBody).',
|
|
15
|
+
source: 'resend',
|
|
16
|
+
headerName: 'svix-signature',
|
|
17
|
+
signingSecretEnv: 'RESEND_WEBHOOK_SECRET',
|
|
18
|
+
tags: ['email', 'resend', 'svix', 'webhook']
|
|
19
|
+
});
|
|
20
|
+
//# sourceMappingURL=resend-signature-verifier.descriptor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-signature-verifier.descriptor.js","sourceRoot":"","sources":["../../src/resend/resend-signature-verifier.descriptor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAC;AAGzD,eAAe,kBAAkB,CAA8B;IAC9D,IAAI,EAAE,0BAA0B;IAChC,EAAE,EAAE,2BAA2B;IAC/B,IAAI,EAAE,mCAAmC;IACzC,WAAW,EAAE,mGAAmG;IAChH,MAAM,EAAE,QAAQ;IAChB,UAAU,EAAE,gBAAgB;IAC5B,gBAAgB,EAAE,uBAAuB;IACzC,IAAI,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,CAAC;CAC5C,CAAC,CAAC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime implementation for the Resend `tools/signature-verifier` descriptor.
|
|
3
|
+
*
|
|
4
|
+
* Returned by the plugin loader and called from
|
|
5
|
+
* `@vibesdotdev/tools/webhooks/router#processWebhook` after the router resolves
|
|
6
|
+
* the verifier for `source === 'resend'`. The router supplies the resolved
|
|
7
|
+
* secret (read from `RESEND_WEBHOOK_SECRET` per the descriptor); the impl
|
|
8
|
+
* does pure Svix HMAC verification with no I/O.
|
|
9
|
+
*/
|
|
10
|
+
import type { SignatureVerifierDescriptor, SignatureVerifierImplementation } from '@vibesdotdev/tools/webhooks/schemas';
|
|
11
|
+
export declare class ResendSignatureVerifier implements SignatureVerifierImplementation {
|
|
12
|
+
readonly descriptor: SignatureVerifierDescriptor;
|
|
13
|
+
verify(rawBody: string, headers: Record<string, string>, secret: string): Promise<boolean>;
|
|
14
|
+
}
|
|
15
|
+
export default ResendSignatureVerifier;
|
|
16
|
+
//# sourceMappingURL=resend-signature-verifier.impl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-signature-verifier.impl.d.ts","sourceRoot":"","sources":["../../src/resend/resend-signature-verifier.impl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EACX,2BAA2B,EAC3B,+BAA+B,EAC/B,MAAM,qCAAqC,CAAC;AAI7C,qBAAa,uBAAwB,YAAW,+BAA+B;IAC9E,QAAQ,CAAC,UAAU,EAAE,2BAA2B,CAAc;IAE9D,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAG1F;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Runtime implementation for the Resend `tools/signature-verifier` descriptor.
|
|
3
|
+
*
|
|
4
|
+
* Returned by the plugin loader and called from
|
|
5
|
+
* `@vibesdotdev/tools/webhooks/router#processWebhook` after the router resolves
|
|
6
|
+
* the verifier for `source === 'resend'`. The router supplies the resolved
|
|
7
|
+
* secret (read from `RESEND_WEBHOOK_SECRET` per the descriptor); the impl
|
|
8
|
+
* does pure Svix HMAC verification with no I/O.
|
|
9
|
+
*/
|
|
10
|
+
import descriptor from "./resend-signature-verifier.descriptor.js";
|
|
11
|
+
import { verifyResendSignature } from "./resend-signature.js";
|
|
12
|
+
export class ResendSignatureVerifier {
|
|
13
|
+
descriptor = descriptor;
|
|
14
|
+
verify(rawBody, headers, secret) {
|
|
15
|
+
return verifyResendSignature(rawBody, headers, secret);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export default ResendSignatureVerifier;
|
|
19
|
+
//# sourceMappingURL=resend-signature-verifier.impl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-signature-verifier.impl.js","sourceRoot":"","sources":["../../src/resend/resend-signature-verifier.impl.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,OAAO,UAAU,MAAM,2CAA2C,CAAC;AACnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AAE9D,MAAM,OAAO,uBAAuB;IAC1B,UAAU,GAAgC,UAAU,CAAC;IAE9D,MAAM,CAAC,OAAe,EAAE,OAA+B,EAAE,MAAc;QACtE,OAAO,qBAAqB,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;IACxD,CAAC;CACD;AAED,eAAe,uBAAuB,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svix-style signature verification for Resend webhooks.
|
|
3
|
+
*
|
|
4
|
+
* Resend delivers webhooks via Svix, which signs requests as
|
|
5
|
+
* `v1,base64(HMAC-SHA256(decoded_secret, "{svix-id}.{svix-timestamp}.{rawBody}"))`
|
|
6
|
+
* The `svix-signature` header may carry multiple space-separated `v1,<sig>`
|
|
7
|
+
* pairs during key rotation; any matching value counts as valid.
|
|
8
|
+
*
|
|
9
|
+
* Secrets are issued as `whsec_<base64>` — strip the prefix and base64-decode
|
|
10
|
+
* to recover the HMAC key bytes. Timestamps older than 5 minutes are rejected
|
|
11
|
+
* to prevent replay attacks.
|
|
12
|
+
*
|
|
13
|
+
* This is the one Svix implementation in the pack. It uses the Web Crypto API
|
|
14
|
+
* only (no `node:*`, no `Buffer`), so the root export stays universal; both the
|
|
15
|
+
* `tools/signature-verifier` impl and the `email/webhook-handler` build on it.
|
|
16
|
+
*/
|
|
17
|
+
/** Maximum allowed clock skew between the webhook timestamp and now (Svix default). */
|
|
18
|
+
export declare const SVIX_REPLAY_WINDOW_SEC = 300;
|
|
19
|
+
/**
|
|
20
|
+
* Decode a `whsec_<base64>` secret into HMAC key bytes. Accepts standard and
|
|
21
|
+
* URL-safe base64 and ignores characters outside the alphabet, matching how
|
|
22
|
+
* the secret has always been decoded.
|
|
23
|
+
*/
|
|
24
|
+
export declare function decodeSvixSecret(secret: string): Uint8Array<ArrayBuffer>;
|
|
25
|
+
/** `base64(HMAC-SHA256(key, "{svixId}.{svixTimestamp}.{rawBody}"))`. */
|
|
26
|
+
export declare function computeSvixSignature(secret: string, svixId: string, svixTimestamp: string, rawBody: string): Promise<string>;
|
|
27
|
+
/** The `v1` signatures carried by a `svix-signature` header value. */
|
|
28
|
+
export declare function svixSignatureCandidates(header: string): string[];
|
|
29
|
+
/** True when any `v1` candidate in `header` matches `expected`, compared in constant time. */
|
|
30
|
+
export declare function svixSignatureMatches(header: string, expected: string): boolean;
|
|
31
|
+
export declare function verifyResendSignature(rawBody: string, headers: Record<string, string>, secret: string): Promise<boolean>;
|
|
32
|
+
//# sourceMappingURL=resend-signature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-signature.d.ts","sourceRoot":"","sources":["../../src/resend/resend-signature.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,uFAAuF;AACvF,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAE1C;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,CASxE;AASD,wEAAwE;AACxE,wBAAsB,oBAAoB,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,MAAM,CAAC,CAcjB;AAED,sEAAsE;AACtE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAMhE;AAED,8FAA8F;AAC9F,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAI9E;AAED,wBAAsB,qBAAqB,CAC1C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,MAAM,EAAE,MAAM,GACZ,OAAO,CAAC,OAAO,CAAC,CAalB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Svix-style signature verification for Resend webhooks.
|
|
3
|
+
*
|
|
4
|
+
* Resend delivers webhooks via Svix, which signs requests as
|
|
5
|
+
* `v1,base64(HMAC-SHA256(decoded_secret, "{svix-id}.{svix-timestamp}.{rawBody}"))`
|
|
6
|
+
* The `svix-signature` header may carry multiple space-separated `v1,<sig>`
|
|
7
|
+
* pairs during key rotation; any matching value counts as valid.
|
|
8
|
+
*
|
|
9
|
+
* Secrets are issued as `whsec_<base64>` — strip the prefix and base64-decode
|
|
10
|
+
* to recover the HMAC key bytes. Timestamps older than 5 minutes are rejected
|
|
11
|
+
* to prevent replay attacks.
|
|
12
|
+
*
|
|
13
|
+
* This is the one Svix implementation in the pack. It uses the Web Crypto API
|
|
14
|
+
* only (no `node:*`, no `Buffer`), so the root export stays universal; both the
|
|
15
|
+
* `tools/signature-verifier` impl and the `email/webhook-handler` build on it.
|
|
16
|
+
*/
|
|
17
|
+
import { constantTimeEqual } from '@vibesdotdev/security';
|
|
18
|
+
/** Maximum allowed clock skew between the webhook timestamp and now (Svix default). */
|
|
19
|
+
export const SVIX_REPLAY_WINDOW_SEC = 300;
|
|
20
|
+
/**
|
|
21
|
+
* Decode a `whsec_<base64>` secret into HMAC key bytes. Accepts standard and
|
|
22
|
+
* URL-safe base64 and ignores characters outside the alphabet, matching how
|
|
23
|
+
* the secret has always been decoded.
|
|
24
|
+
*/
|
|
25
|
+
export function decodeSvixSecret(secret) {
|
|
26
|
+
const stripped = secret.startsWith('whsec_') ? secret.slice('whsec_'.length) : secret;
|
|
27
|
+
const alphabet = stripped.replace(/-/g, '+').replace(/_/g, '/').replace(/[^A-Za-z0-9+/]/g, '');
|
|
28
|
+
// A single dangling character carries no whole byte; lenient decoders drop it.
|
|
29
|
+
const normalized = alphabet.length % 4 === 1 ? alphabet.slice(0, -1) : alphabet;
|
|
30
|
+
const binary = atob(normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '='));
|
|
31
|
+
const bytes = new Uint8Array(binary.length);
|
|
32
|
+
for (let i = 0; i < binary.length; i++)
|
|
33
|
+
bytes[i] = binary.charCodeAt(i);
|
|
34
|
+
return bytes;
|
|
35
|
+
}
|
|
36
|
+
function base64Encode(bytes) {
|
|
37
|
+
const view = new Uint8Array(bytes);
|
|
38
|
+
let out = '';
|
|
39
|
+
for (let i = 0; i < view.byteLength; i++)
|
|
40
|
+
out += String.fromCharCode(view[i]);
|
|
41
|
+
return btoa(out);
|
|
42
|
+
}
|
|
43
|
+
/** `base64(HMAC-SHA256(key, "{svixId}.{svixTimestamp}.{rawBody}"))`. */
|
|
44
|
+
export async function computeSvixSignature(secret, svixId, svixTimestamp, rawBody) {
|
|
45
|
+
const key = await crypto.subtle.importKey('raw', decodeSvixSecret(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['sign']);
|
|
46
|
+
const signature = await crypto.subtle.sign('HMAC', key, new TextEncoder().encode(`${svixId}.${svixTimestamp}.${rawBody}`));
|
|
47
|
+
return base64Encode(signature);
|
|
48
|
+
}
|
|
49
|
+
/** The `v1` signatures carried by a `svix-signature` header value. */
|
|
50
|
+
export function svixSignatureCandidates(header) {
|
|
51
|
+
return header
|
|
52
|
+
.split(' ')
|
|
53
|
+
.map((candidate) => candidate.trim())
|
|
54
|
+
.filter((candidate) => candidate.startsWith('v1,'))
|
|
55
|
+
.map((candidate) => candidate.slice('v1,'.length));
|
|
56
|
+
}
|
|
57
|
+
/** True when any `v1` candidate in `header` matches `expected`, compared in constant time. */
|
|
58
|
+
export function svixSignatureMatches(header, expected) {
|
|
59
|
+
return svixSignatureCandidates(header).some((candidate) => candidate.length > 0 && constantTimeEqual(candidate, expected));
|
|
60
|
+
}
|
|
61
|
+
export async function verifyResendSignature(rawBody, headers, secret) {
|
|
62
|
+
if (!secret)
|
|
63
|
+
return false;
|
|
64
|
+
const svixId = headers['svix-id'] || '';
|
|
65
|
+
const svixTimestamp = headers['svix-timestamp'] || '';
|
|
66
|
+
const svixSignature = headers['svix-signature'] || '';
|
|
67
|
+
if (!svixId || !svixTimestamp || !svixSignature)
|
|
68
|
+
return false;
|
|
69
|
+
const ts = Number.parseInt(svixTimestamp, 10);
|
|
70
|
+
if (!Number.isFinite(ts))
|
|
71
|
+
return false;
|
|
72
|
+
if (Math.abs(Math.floor(Date.now() / 1000) - ts) > SVIX_REPLAY_WINDOW_SEC)
|
|
73
|
+
return false;
|
|
74
|
+
const expected = await computeSvixSignature(secret, svixId, svixTimestamp, rawBody);
|
|
75
|
+
return svixSignatureMatches(svixSignature, expected);
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=resend-signature.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-signature.js","sourceRoot":"","sources":["../../src/resend/resend-signature.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resend `email/webhook-handler` descriptor.
|
|
3
|
+
*
|
|
4
|
+
* Resend signs webhook deliveries using Svix conventions: three headers
|
|
5
|
+
* (`svix-id`, `svix-timestamp`, `svix-signature`) and an HMAC-SHA256 of
|
|
6
|
+
* `<id>.<timestamp>.<rawBody>` against the configured signing secret.
|
|
7
|
+
*
|
|
8
|
+
* The substrate's app-owned `+server.ts` adapter route looks up this
|
|
9
|
+
* descriptor by integration provider id (`'resend'`), invokes
|
|
10
|
+
* `verify({headers, rawBody})` for signature checking + normalization,
|
|
11
|
+
* then writes the resulting events through `recordInboundEmail`.
|
|
12
|
+
*/
|
|
13
|
+
declare const _default: {
|
|
14
|
+
id: string;
|
|
15
|
+
kind: "email/webhook-handler";
|
|
16
|
+
provider: string;
|
|
17
|
+
signatureHeader: string;
|
|
18
|
+
enabled: boolean;
|
|
19
|
+
name?: string | undefined;
|
|
20
|
+
description?: string | undefined;
|
|
21
|
+
hardware?: string[] | undefined;
|
|
22
|
+
priority?: number | undefined;
|
|
23
|
+
capabilityId?: string | undefined;
|
|
24
|
+
requiredContext?: string[] | undefined;
|
|
25
|
+
optionalContext?: string[] | undefined;
|
|
26
|
+
config?: unknown;
|
|
27
|
+
retention?: string | {
|
|
28
|
+
reason: string;
|
|
29
|
+
maxAgeDays?: number | undefined;
|
|
30
|
+
maxEntries?: number | undefined;
|
|
31
|
+
maxBytes?: number | undefined;
|
|
32
|
+
cascadeFrom?: string | undefined;
|
|
33
|
+
ageField?: string | undefined;
|
|
34
|
+
enforcedBy?: string | undefined;
|
|
35
|
+
} | undefined;
|
|
36
|
+
tags?: string[] | undefined;
|
|
37
|
+
};
|
|
38
|
+
export default _default;
|
|
39
|
+
//# sourceMappingURL=resend-webhook.descriptor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-webhook.descriptor.d.ts","sourceRoot":"","sources":["../../src/resend/resend-webhook.descriptor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;;;;;;;;;;;AAKH,wBAUG"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resend `email/webhook-handler` descriptor.
|
|
3
|
+
*
|
|
4
|
+
* Resend signs webhook deliveries using Svix conventions: three headers
|
|
5
|
+
* (`svix-id`, `svix-timestamp`, `svix-signature`) and an HMAC-SHA256 of
|
|
6
|
+
* `<id>.<timestamp>.<rawBody>` against the configured signing secret.
|
|
7
|
+
*
|
|
8
|
+
* The substrate's app-owned `+server.ts` adapter route looks up this
|
|
9
|
+
* descriptor by integration provider id (`'resend'`), invokes
|
|
10
|
+
* `verify({headers, rawBody})` for signature checking + normalization,
|
|
11
|
+
* then writes the resulting events through `recordInboundEmail`.
|
|
12
|
+
*/
|
|
13
|
+
import { createRuntimeAsset } from '@vibesdotdev/kernel/factory';
|
|
14
|
+
export default createRuntimeAsset({
|
|
15
|
+
kind: 'email/webhook-handler',
|
|
16
|
+
id: 'integration.email.resend',
|
|
17
|
+
name: 'Resend Webhook Handler',
|
|
18
|
+
description: 'Verifies Svix-signed Resend webhooks and normalizes them to EmailWebhookEvent[].',
|
|
19
|
+
provider: 'resend',
|
|
20
|
+
signatureHeader: 'svix-signature',
|
|
21
|
+
enabled: true,
|
|
22
|
+
tags: ['email', 'resend', 'webhook', 'svix']
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=resend-webhook.descriptor.js.map
|