@molecule/api-emails-inbound-agentmail 1.0.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/LICENSE +115 -0
- package/README.md +1159 -0
- package/dist/api.d.ts +141 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +244 -0
- package/dist/api.js.map +1 -0
- package/dist/browser-guard.d.ts +2 -0
- package/dist/browser-guard.d.ts.map +1 -0
- package/dist/browser-guard.js +19 -0
- package/dist/browser-guard.js.map +1 -0
- package/dist/index.d.ts +71 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +71 -0
- package/dist/index.js.map +1 -0
- package/dist/provider.d.ts +117 -0
- package/dist/provider.d.ts.map +1 -0
- package/dist/provider.js +417 -0
- package/dist/provider.js.map +1 -0
- package/dist/secrets.d.ts +17 -0
- package/dist/secrets.d.ts.map +1 -0
- package/dist/secrets.js +52 -0
- package/dist/secrets.js.map +1 -0
- package/dist/types.d.ts +229 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +14 -0
- package/dist/types.js.map +1 -0
- package/dist/utilities.d.ts +148 -0
- package/dist/utilities.d.ts.map +1 -0
- package/dist/utilities.js +257 -0
- package/dist/utilities.js.map +1 -0
- package/package.json +53 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the AgentMail inbound-emails provider.
|
|
3
|
+
*
|
|
4
|
+
* Only the fields this bond reads are typed; AgentMail emits a superset.
|
|
5
|
+
* Every optional field is read defensively — a payload that omits or
|
|
6
|
+
* mistypes one degrades to "absent", never to a crash.
|
|
7
|
+
*
|
|
8
|
+
* @see https://docs.agentmail.to/api-reference/webhooks/events/message-received
|
|
9
|
+
* @see https://docs.agentmail.to/api-reference/inboxes/messages/get
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
export type { InboundEmail, InboundEmailAttachment, InboundEmailProvider, InboundEmailReply, InboundEmailReplyResult, } from '@molecule/api-emails-inbound';
|
|
14
|
+
/**
|
|
15
|
+
* Attachment METADATA as carried by a webhook payload or a `GET message`
|
|
16
|
+
* response. The bytes are never inline — see
|
|
17
|
+
* {@link AgentMailAttachmentDownload}.
|
|
18
|
+
*/
|
|
19
|
+
export interface AgentMailAttachmentMeta {
|
|
20
|
+
/** AgentMail's identifier for the attachment. */
|
|
21
|
+
attachment_id: string;
|
|
22
|
+
/** Size of the attachment in bytes. */
|
|
23
|
+
size: number;
|
|
24
|
+
/** Original filename, when the sender supplied one. */
|
|
25
|
+
filename?: string;
|
|
26
|
+
/** MIME type, when known. */
|
|
27
|
+
content_type?: string;
|
|
28
|
+
/** `inline` for `cid:`-referenced parts, `attachment` otherwise. */
|
|
29
|
+
content_disposition?: 'inline' | 'attachment';
|
|
30
|
+
/** Content-ID for inline parts referenced from the HTML body. */
|
|
31
|
+
content_id?: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Response of `GET /v0/inboxes/{inbox_id}/messages/{message_id}/attachments/{attachment_id}`:
|
|
35
|
+
* the attachment's metadata plus a presigned, time-limited `download_url`
|
|
36
|
+
* from which the raw bytes are fetched.
|
|
37
|
+
*
|
|
38
|
+
* @see https://docs.agentmail.to/api-reference/inboxes/messages/get-attachment
|
|
39
|
+
*/
|
|
40
|
+
export interface AgentMailAttachmentDownload extends AgentMailAttachmentMeta {
|
|
41
|
+
/** Presigned URL serving the raw attachment bytes (no auth header needed). */
|
|
42
|
+
download_url: string;
|
|
43
|
+
/** When `download_url` stops working. */
|
|
44
|
+
expires_at?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* An AgentMail message as it appears in a `message.received` webhook payload
|
|
48
|
+
* and in the `GET message` response (same schema).
|
|
49
|
+
*
|
|
50
|
+
* `message_id` is the RFC 5322 `Message-ID`, INCLUDING its angle brackets
|
|
51
|
+
* (`<abc@agentmail.to>`); AgentMail uses that exact string as the path
|
|
52
|
+
* parameter of every per-message endpoint.
|
|
53
|
+
*/
|
|
54
|
+
export interface AgentMailMessage {
|
|
55
|
+
/** Opaque id of the inbox that received the message (NOT its address). */
|
|
56
|
+
inbox_id: string;
|
|
57
|
+
/** Opaque id of the conversation thread. */
|
|
58
|
+
thread_id?: string;
|
|
59
|
+
/** RFC 5322 Message-ID, with angle brackets. */
|
|
60
|
+
message_id: string;
|
|
61
|
+
/** AgentMail labels, e.g. `['received']`. */
|
|
62
|
+
labels?: string[];
|
|
63
|
+
/** ISO 8601 time AgentMail received the message. */
|
|
64
|
+
timestamp?: string;
|
|
65
|
+
/**
|
|
66
|
+
* Sender mailbox (`Alice <alice@example.com>`). The API reference spells
|
|
67
|
+
* this `from`; the webhooks guide's example spells it `from_` — both are
|
|
68
|
+
* documented, so both are read.
|
|
69
|
+
*/
|
|
70
|
+
from?: string;
|
|
71
|
+
/** Alternate documented spelling of {@link AgentMailMessage.from}. */
|
|
72
|
+
from_?: string;
|
|
73
|
+
/** `To:` recipients. */
|
|
74
|
+
to?: string[];
|
|
75
|
+
/** `Cc:` recipients. */
|
|
76
|
+
cc?: string[];
|
|
77
|
+
/** `Bcc:` recipients. */
|
|
78
|
+
bcc?: string[];
|
|
79
|
+
/** `Reply-To:` addresses. */
|
|
80
|
+
reply_to?: string[];
|
|
81
|
+
/** Subject line. */
|
|
82
|
+
subject?: string;
|
|
83
|
+
/** Short body preview. */
|
|
84
|
+
preview?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Plain-text body. Omitted (together with `html`) when the webhook payload
|
|
87
|
+
* would exceed AgentMail's 1 MB cap — fetch the message via the API then.
|
|
88
|
+
*/
|
|
89
|
+
text?: string;
|
|
90
|
+
/** HTML body. Omitted under the same 1 MB rule as `text`. */
|
|
91
|
+
html?: string;
|
|
92
|
+
/** Attachment metadata only — bytes come from the attachment endpoint. */
|
|
93
|
+
attachments?: AgentMailAttachmentMeta[];
|
|
94
|
+
/** `In-Reply-To` header value, with angle brackets. */
|
|
95
|
+
in_reply_to?: string;
|
|
96
|
+
/** `References` header values, with angle brackets. */
|
|
97
|
+
references?: string[];
|
|
98
|
+
/** Raw message headers as a name → value map. */
|
|
99
|
+
headers?: Record<string, string>;
|
|
100
|
+
/** Message size in bytes. */
|
|
101
|
+
size?: number;
|
|
102
|
+
/** ISO 8601 creation time. */
|
|
103
|
+
created_at?: string;
|
|
104
|
+
/** ISO 8601 last-update time. */
|
|
105
|
+
updated_at?: string;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Top-level shape of an AgentMail webhook delivery for the
|
|
109
|
+
* `message.received*` event family.
|
|
110
|
+
*
|
|
111
|
+
* @see https://docs.agentmail.to/api-reference/webhooks/events/message-received
|
|
112
|
+
*/
|
|
113
|
+
export interface AgentMailWebhookEvent {
|
|
114
|
+
/** Always `event`. */
|
|
115
|
+
type?: string;
|
|
116
|
+
/**
|
|
117
|
+
* `message.received`, `message.received.spam`,
|
|
118
|
+
* `message.received.blocked`, or `message.received.unauthenticated`.
|
|
119
|
+
*/
|
|
120
|
+
event_type: string;
|
|
121
|
+
/** Unique id of this event. */
|
|
122
|
+
event_id?: string;
|
|
123
|
+
/** The received message. */
|
|
124
|
+
message: AgentMailMessage;
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Request body of `POST /v0/inboxes/{inbox_id}/messages/{message_id}/reply`.
|
|
128
|
+
* Every field is optional on the wire; AgentMail threads the reply itself
|
|
129
|
+
* (there is no `subject` — the original's is reused).
|
|
130
|
+
*
|
|
131
|
+
* @see https://docs.agentmail.to/api-reference/inboxes/messages/reply
|
|
132
|
+
*/
|
|
133
|
+
export interface AgentMailReplyRequest {
|
|
134
|
+
/** Recipient(s). */
|
|
135
|
+
to?: string | string[];
|
|
136
|
+
/** CC recipient(s). */
|
|
137
|
+
cc?: string | string[];
|
|
138
|
+
/** BCC recipient(s). */
|
|
139
|
+
bcc?: string | string[];
|
|
140
|
+
/** Reply-To address(es). */
|
|
141
|
+
reply_to?: string | string[];
|
|
142
|
+
/** Plain-text body. */
|
|
143
|
+
text?: string;
|
|
144
|
+
/** HTML body. */
|
|
145
|
+
html?: string;
|
|
146
|
+
/** Attachments; `content` is the base64-encoded payload. */
|
|
147
|
+
attachments?: AgentMailReplyAttachment[];
|
|
148
|
+
/** Custom message headers. */
|
|
149
|
+
headers?: Record<string, string>;
|
|
150
|
+
/** Message labels. */
|
|
151
|
+
labels?: string[];
|
|
152
|
+
}
|
|
153
|
+
/** One attachment in an {@link AgentMailReplyRequest}. */
|
|
154
|
+
export interface AgentMailReplyAttachment {
|
|
155
|
+
/** Filename shown to the recipient. */
|
|
156
|
+
filename?: string;
|
|
157
|
+
/** MIME type. */
|
|
158
|
+
content_type?: string;
|
|
159
|
+
/** `inline` for `cid:`-referenced parts. */
|
|
160
|
+
content_disposition?: 'inline' | 'attachment';
|
|
161
|
+
/** Content-ID for inline parts. */
|
|
162
|
+
content_id?: string;
|
|
163
|
+
/** Base64-encoded attachment bytes. */
|
|
164
|
+
content?: string;
|
|
165
|
+
}
|
|
166
|
+
/** Response of the reply endpoint. */
|
|
167
|
+
export interface AgentMailReplyResponse {
|
|
168
|
+
/** Message-ID of the created reply. */
|
|
169
|
+
message_id: string;
|
|
170
|
+
/** Thread the reply belongs to. */
|
|
171
|
+
thread_id?: string;
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* AgentMail's error envelope.
|
|
175
|
+
*
|
|
176
|
+
* @see https://docs.agentmail.to/errors
|
|
177
|
+
*/
|
|
178
|
+
export interface AgentMailErrorBody {
|
|
179
|
+
/** Legacy error type name (e.g. `NotFoundError`). */
|
|
180
|
+
name?: string;
|
|
181
|
+
/** Machine-readable error code (e.g. `unknown_api_key`, `rate_limit_exceeded`). */
|
|
182
|
+
code?: string;
|
|
183
|
+
/** Human-readable description. */
|
|
184
|
+
message?: string;
|
|
185
|
+
/** Concrete remediation steps, when AgentMail supplied them. */
|
|
186
|
+
fix?: string;
|
|
187
|
+
/** Link to the error's documentation. */
|
|
188
|
+
docs?: string;
|
|
189
|
+
}
|
|
190
|
+
declare global {
|
|
191
|
+
namespace NodeJS {
|
|
192
|
+
/**
|
|
193
|
+
* Process Env interface — AgentMail credentials for the inbound bond.
|
|
194
|
+
* Webhooks are verified with the per-webhook signing secret; the API key
|
|
195
|
+
* is used for message/attachment hydration and for reply dispatch.
|
|
196
|
+
*/
|
|
197
|
+
interface ProcessEnv {
|
|
198
|
+
/**
|
|
199
|
+
* AgentMail API key (`am_…`). Sent as `Authorization: Bearer` on every
|
|
200
|
+
* API call: body hydration, attachment download, reply dispatch.
|
|
201
|
+
*/
|
|
202
|
+
AGENTMAIL_API_KEY?: string;
|
|
203
|
+
/**
|
|
204
|
+
* Webhook signing secret (`whsec_…`) returned when the webhook was
|
|
205
|
+
* created. Used to verify the `svix-signature` of inbound webhooks.
|
|
206
|
+
*/
|
|
207
|
+
AGENTMAIL_WEBHOOK_SECRET?: string;
|
|
208
|
+
/**
|
|
209
|
+
* Optional `inbox_id` this app owns. When set, webhooks for any other
|
|
210
|
+
* inbox are rejected by `parseWebhookPayload`, and replies are sent
|
|
211
|
+
* from this inbox even when the original parse happened in another
|
|
212
|
+
* process.
|
|
213
|
+
*/
|
|
214
|
+
AGENTMAIL_INBOX_ID?: string;
|
|
215
|
+
/**
|
|
216
|
+
* Optional API base URL. Defaults to `https://api.agentmail.to`; set
|
|
217
|
+
* `https://api.agentmail.eu` for the EU region.
|
|
218
|
+
*/
|
|
219
|
+
AGENTMAIL_BASE_URL?: string;
|
|
220
|
+
/**
|
|
221
|
+
* Maximum age in seconds for an inbound webhook timestamp before the
|
|
222
|
+
* provider rejects it as a replay. Defaults to `300` (5 minutes) when
|
|
223
|
+
* unset.
|
|
224
|
+
*/
|
|
225
|
+
AGENTMAIL_INBOUND_REPLAY_WINDOW_SECONDS?: string;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for the AgentMail inbound-emails provider.
|
|
3
|
+
*
|
|
4
|
+
* Only the fields this bond reads are typed; AgentMail emits a superset.
|
|
5
|
+
* Every optional field is read defensively — a payload that omits or
|
|
6
|
+
* mistypes one degrades to "absent", never to a crash.
|
|
7
|
+
*
|
|
8
|
+
* @see https://docs.agentmail.to/api-reference/webhooks/events/message-received
|
|
9
|
+
* @see https://docs.agentmail.to/api-reference/inboxes/messages/get
|
|
10
|
+
*
|
|
11
|
+
* @module
|
|
12
|
+
*/
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal utilities for the AgentMail inbound-emails provider.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of `provider.ts` so the signing/parsing helpers can be
|
|
5
|
+
* unit-tested in isolation without touching the bond singleton or the
|
|
6
|
+
* network.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { Buffer } from 'node:buffer';
|
|
11
|
+
/**
|
|
12
|
+
* Default replay window for inbound webhook timestamps, in seconds.
|
|
13
|
+
*
|
|
14
|
+
* AgentMail delivers webhooks through Svix, whose documented default
|
|
15
|
+
* tolerance for `svix-timestamp` is five minutes.
|
|
16
|
+
*/
|
|
17
|
+
export declare const DEFAULT_REPLAY_WINDOW_SECONDS = 300;
|
|
18
|
+
/** Default AgentMail API base URL (production). */
|
|
19
|
+
export declare const DEFAULT_BASE_URL = "https://api.agentmail.to";
|
|
20
|
+
/** Prefix Svix puts on webhook signing secrets before the base64 key. */
|
|
21
|
+
export declare const WEBHOOK_SECRET_PREFIX = "whsec_";
|
|
22
|
+
/** The only signature-scheme version this bond understands. */
|
|
23
|
+
export declare const SIGNATURE_VERSION = "v1";
|
|
24
|
+
/**
|
|
25
|
+
* Coerces an HTTP header value (which may be `string`, `string[]`, or
|
|
26
|
+
* `undefined`) to a single string. Multi-value headers are joined with
|
|
27
|
+
* `, ` per RFC 9110 §5.2.
|
|
28
|
+
*
|
|
29
|
+
* @param value - The header value to coerce.
|
|
30
|
+
* @returns The header value as a single string, or `undefined` when the
|
|
31
|
+
* header was not present.
|
|
32
|
+
*/
|
|
33
|
+
export declare const headerToString: (value: string | string[] | undefined) => string | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Returns the value of `headers[name]` (case-insensitive) coerced to a
|
|
36
|
+
* single string.
|
|
37
|
+
*
|
|
38
|
+
* @param headers - The headers object.
|
|
39
|
+
* @param name - The header name (case-insensitive).
|
|
40
|
+
* @returns The header value as a single string, or `undefined` if absent.
|
|
41
|
+
*/
|
|
42
|
+
export declare const getHeader: (headers: Record<string, string | string[] | undefined>, name: string) => string | undefined;
|
|
43
|
+
/**
|
|
44
|
+
* Coerces the request body into a UTF-8 string. Buffers are decoded as
|
|
45
|
+
* UTF-8 (AgentMail POSTs `application/json`), strings are returned as-is.
|
|
46
|
+
*
|
|
47
|
+
* @param body - The raw body.
|
|
48
|
+
* @returns The body as a UTF-8 string.
|
|
49
|
+
*/
|
|
50
|
+
export declare const bodyToString: (body: Buffer | string) => string;
|
|
51
|
+
/**
|
|
52
|
+
* Narrowing guard for a plain JSON object.
|
|
53
|
+
*
|
|
54
|
+
* @param value - Any value.
|
|
55
|
+
* @returns `true` when `value` is a non-null, non-array object.
|
|
56
|
+
*/
|
|
57
|
+
export declare const isRecord: (value: unknown) => value is Record<string, unknown>;
|
|
58
|
+
/**
|
|
59
|
+
* Parses a JSON request body. Accepts the raw bytes/string of the request
|
|
60
|
+
* or an already-parsed object (Express's JSON middleware gives us the
|
|
61
|
+
* latter when a JSON route captures the webhook).
|
|
62
|
+
*
|
|
63
|
+
* @param body - Raw body or pre-parsed object.
|
|
64
|
+
* @returns The parsed JSON value.
|
|
65
|
+
* @throws {SyntaxError} When a string/Buffer body is not valid JSON.
|
|
66
|
+
*/
|
|
67
|
+
export declare const parseJsonBody: (body: Buffer | string | Record<string, unknown>) => unknown;
|
|
68
|
+
/**
|
|
69
|
+
* Decodes a Svix-style signing secret into raw key bytes: strip the
|
|
70
|
+
* `whsec_` prefix, then base64-decode the remainder. A secret without the
|
|
71
|
+
* prefix is base64-decoded as-is (the Svix libraries do the same).
|
|
72
|
+
*
|
|
73
|
+
* @param secret - The signing secret as configured.
|
|
74
|
+
* @returns The HMAC key bytes (empty when the secret decodes to nothing).
|
|
75
|
+
*/
|
|
76
|
+
export declare const decodeWebhookSecret: (secret: string) => Buffer;
|
|
77
|
+
/**
|
|
78
|
+
* Builds the exact bytes Svix signs: `${id}.${timestamp}.` followed by the
|
|
79
|
+
* raw request body, unchanged. Returned as a Buffer so a body that is not
|
|
80
|
+
* valid UTF-8 still signs byte-for-byte.
|
|
81
|
+
*
|
|
82
|
+
* @param id - The `svix-id` header value.
|
|
83
|
+
* @param timestamp - The `svix-timestamp` header value (as received).
|
|
84
|
+
* @param body - The raw request body.
|
|
85
|
+
* @returns The signed content.
|
|
86
|
+
*/
|
|
87
|
+
export declare const buildSignedContent: (id: string, timestamp: string, body: Buffer | string) => Buffer;
|
|
88
|
+
/**
|
|
89
|
+
* Splits a `svix-signature` header — a space-delimited list of
|
|
90
|
+
* `<version>,<base64>` entries (e.g. `v1,abc v1,def`) — into the `v1`
|
|
91
|
+
* signatures. Entries of any other version are ignored, not rejected: Svix
|
|
92
|
+
* may add versions and a receiver is expected to match on any one it
|
|
93
|
+
* understands.
|
|
94
|
+
*
|
|
95
|
+
* @param value - The raw header value.
|
|
96
|
+
* @returns The base64 `v1` signatures (empty when none are present).
|
|
97
|
+
*/
|
|
98
|
+
export declare const parseSignatureHeader: (value: string | undefined) => string[];
|
|
99
|
+
/**
|
|
100
|
+
* Constant-time comparison of two base64-encoded digests.
|
|
101
|
+
*
|
|
102
|
+
* @param a - The first digest.
|
|
103
|
+
* @param b - The second digest.
|
|
104
|
+
* @returns `true` when the decoded bytes are equal.
|
|
105
|
+
*/
|
|
106
|
+
export declare const safeEqualBase64: (a: string, b: string) => boolean;
|
|
107
|
+
/**
|
|
108
|
+
* Normalizes an address field that AgentMail types as `string` in one
|
|
109
|
+
* place and `string[]` in another into a trimmed, non-empty string array.
|
|
110
|
+
*
|
|
111
|
+
* @param value - The raw field value.
|
|
112
|
+
* @returns The addresses (empty when the field is absent or malformed).
|
|
113
|
+
*/
|
|
114
|
+
export declare const normalizeAddressList: (value: unknown) => string[];
|
|
115
|
+
/**
|
|
116
|
+
* Recovers the core's normalized headers map (lowercased names,
|
|
117
|
+
* multi-value headers as arrays) from AgentMail's `headers` object. Any
|
|
118
|
+
* non-string value is skipped; a missing or malformed map yields `{}`.
|
|
119
|
+
*
|
|
120
|
+
* @param value - The raw `headers` field.
|
|
121
|
+
* @returns Normalized headers map.
|
|
122
|
+
*/
|
|
123
|
+
export declare const lowercaseHeaderMap: (value: unknown) => Record<string, string | string[]>;
|
|
124
|
+
/**
|
|
125
|
+
* Strips surrounding angle brackets from a `Message-ID` value.
|
|
126
|
+
*
|
|
127
|
+
* @param value - The raw value (with or without angle brackets).
|
|
128
|
+
* @returns The value without angle brackets, or `undefined` if input was
|
|
129
|
+
* empty or not a string.
|
|
130
|
+
*/
|
|
131
|
+
export declare const unwrapMessageId: (value: unknown) => string | undefined;
|
|
132
|
+
/**
|
|
133
|
+
* Parses an ISO 8601 timestamp into a `Date`.
|
|
134
|
+
*
|
|
135
|
+
* @param value - The raw field value.
|
|
136
|
+
* @returns The date, or `undefined` when absent or unparseable.
|
|
137
|
+
*/
|
|
138
|
+
export declare const parseTimestamp: (value: unknown) => Date | undefined;
|
|
139
|
+
/**
|
|
140
|
+
* Parses a `Retry-After` header, which is equally valid as delta-seconds
|
|
141
|
+
* (`'30'`) or an HTTP-date, into whole seconds from now.
|
|
142
|
+
*
|
|
143
|
+
* @param value - The raw header value.
|
|
144
|
+
* @returns Seconds to wait (never negative), or `undefined` when absent or
|
|
145
|
+
* unparseable.
|
|
146
|
+
*/
|
|
147
|
+
export declare const parseRetryAfterSeconds: (value: string | null | undefined) => number | undefined;
|
|
148
|
+
//# sourceMappingURL=utilities.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utilities.d.ts","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAGpC;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,MAAM,CAAA;AAEhD,mDAAmD;AACnD,eAAO,MAAM,gBAAgB,6BAA6B,CAAA;AAE1D,yEAAyE;AACzE,eAAO,MAAM,qBAAqB,WAAW,CAAA;AAE7C,+DAA+D;AAC/D,eAAO,MAAM,iBAAiB,OAAO,CAAA;AAErC;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAG,MAAM,GAAG,SAG9E,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,SAAS,GACpB,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,EACtD,MAAM,MAAM,KACX,MAAM,GAAG,SAQX,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY,GAAI,MAAM,MAAM,GAAG,MAAM,KAAG,MAEpD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,GAAI,OAAO,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAExE,CAAA;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,OAK/E,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,mBAAmB,GAAI,QAAQ,MAAM,KAAG,MAMpD,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,GAC7B,IAAI,MAAM,EACV,WAAW,MAAM,EACjB,MAAM,MAAM,GAAG,MAAM,KACpB,MAGF,CAAA;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,MAAM,GAAG,SAAS,KAAG,MAAM,EAWtE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,GAAG,MAAM,EAAE,GAAG,MAAM,KAAG,OAKtD,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,GAAI,OAAO,OAAO,KAAG,MAAM,EAS3D,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,kBAAkB,GAAI,OAAO,OAAO,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAsBnF,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,OAAO,KAAG,MAAM,GAAG,SAKzD,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,OAAO,OAAO,KAAG,IAAI,GAAG,SAItD,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,GAAI,OAAO,MAAM,GAAG,IAAI,GAAG,SAAS,KAAG,MAAM,GAAG,SAOlF,CAAA"}
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal utilities for the AgentMail inbound-emails provider.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of `provider.ts` so the signing/parsing helpers can be
|
|
5
|
+
* unit-tested in isolation without touching the bond singleton or the
|
|
6
|
+
* network.
|
|
7
|
+
*
|
|
8
|
+
* @module
|
|
9
|
+
*/
|
|
10
|
+
import { Buffer } from 'node:buffer';
|
|
11
|
+
import { timingSafeEqual } from 'node:crypto';
|
|
12
|
+
/**
|
|
13
|
+
* Default replay window for inbound webhook timestamps, in seconds.
|
|
14
|
+
*
|
|
15
|
+
* AgentMail delivers webhooks through Svix, whose documented default
|
|
16
|
+
* tolerance for `svix-timestamp` is five minutes.
|
|
17
|
+
*/
|
|
18
|
+
export const DEFAULT_REPLAY_WINDOW_SECONDS = 300;
|
|
19
|
+
/** Default AgentMail API base URL (production). */
|
|
20
|
+
export const DEFAULT_BASE_URL = 'https://api.agentmail.to';
|
|
21
|
+
/** Prefix Svix puts on webhook signing secrets before the base64 key. */
|
|
22
|
+
export const WEBHOOK_SECRET_PREFIX = 'whsec_';
|
|
23
|
+
/** The only signature-scheme version this bond understands. */
|
|
24
|
+
export const SIGNATURE_VERSION = 'v1';
|
|
25
|
+
/**
|
|
26
|
+
* Coerces an HTTP header value (which may be `string`, `string[]`, or
|
|
27
|
+
* `undefined`) to a single string. Multi-value headers are joined with
|
|
28
|
+
* `, ` per RFC 9110 §5.2.
|
|
29
|
+
*
|
|
30
|
+
* @param value - The header value to coerce.
|
|
31
|
+
* @returns The header value as a single string, or `undefined` when the
|
|
32
|
+
* header was not present.
|
|
33
|
+
*/
|
|
34
|
+
export const headerToString = (value) => {
|
|
35
|
+
if (value === undefined)
|
|
36
|
+
return undefined;
|
|
37
|
+
return Array.isArray(value) ? value.join(', ') : value;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Returns the value of `headers[name]` (case-insensitive) coerced to a
|
|
41
|
+
* single string.
|
|
42
|
+
*
|
|
43
|
+
* @param headers - The headers object.
|
|
44
|
+
* @param name - The header name (case-insensitive).
|
|
45
|
+
* @returns The header value as a single string, or `undefined` if absent.
|
|
46
|
+
*/
|
|
47
|
+
export const getHeader = (headers, name) => {
|
|
48
|
+
const target = name.toLowerCase();
|
|
49
|
+
for (const key of Object.keys(headers)) {
|
|
50
|
+
if (key.toLowerCase() === target) {
|
|
51
|
+
return headerToString(headers[key]);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Coerces the request body into a UTF-8 string. Buffers are decoded as
|
|
58
|
+
* UTF-8 (AgentMail POSTs `application/json`), strings are returned as-is.
|
|
59
|
+
*
|
|
60
|
+
* @param body - The raw body.
|
|
61
|
+
* @returns The body as a UTF-8 string.
|
|
62
|
+
*/
|
|
63
|
+
export const bodyToString = (body) => {
|
|
64
|
+
return Buffer.isBuffer(body) ? body.toString('utf8') : body;
|
|
65
|
+
};
|
|
66
|
+
/**
|
|
67
|
+
* Narrowing guard for a plain JSON object.
|
|
68
|
+
*
|
|
69
|
+
* @param value - Any value.
|
|
70
|
+
* @returns `true` when `value` is a non-null, non-array object.
|
|
71
|
+
*/
|
|
72
|
+
export const isRecord = (value) => {
|
|
73
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
74
|
+
};
|
|
75
|
+
/**
|
|
76
|
+
* Parses a JSON request body. Accepts the raw bytes/string of the request
|
|
77
|
+
* or an already-parsed object (Express's JSON middleware gives us the
|
|
78
|
+
* latter when a JSON route captures the webhook).
|
|
79
|
+
*
|
|
80
|
+
* @param body - Raw body or pre-parsed object.
|
|
81
|
+
* @returns The parsed JSON value.
|
|
82
|
+
* @throws {SyntaxError} When a string/Buffer body is not valid JSON.
|
|
83
|
+
*/
|
|
84
|
+
export const parseJsonBody = (body) => {
|
|
85
|
+
if (typeof body === 'string' || Buffer.isBuffer(body)) {
|
|
86
|
+
return JSON.parse(bodyToString(body));
|
|
87
|
+
}
|
|
88
|
+
return body;
|
|
89
|
+
};
|
|
90
|
+
/**
|
|
91
|
+
* Decodes a Svix-style signing secret into raw key bytes: strip the
|
|
92
|
+
* `whsec_` prefix, then base64-decode the remainder. A secret without the
|
|
93
|
+
* prefix is base64-decoded as-is (the Svix libraries do the same).
|
|
94
|
+
*
|
|
95
|
+
* @param secret - The signing secret as configured.
|
|
96
|
+
* @returns The HMAC key bytes (empty when the secret decodes to nothing).
|
|
97
|
+
*/
|
|
98
|
+
export const decodeWebhookSecret = (secret) => {
|
|
99
|
+
const trimmed = secret.trim();
|
|
100
|
+
const encoded = trimmed.startsWith(WEBHOOK_SECRET_PREFIX)
|
|
101
|
+
? trimmed.slice(WEBHOOK_SECRET_PREFIX.length)
|
|
102
|
+
: trimmed;
|
|
103
|
+
return Buffer.from(encoded, 'base64');
|
|
104
|
+
};
|
|
105
|
+
/**
|
|
106
|
+
* Builds the exact bytes Svix signs: `${id}.${timestamp}.` followed by the
|
|
107
|
+
* raw request body, unchanged. Returned as a Buffer so a body that is not
|
|
108
|
+
* valid UTF-8 still signs byte-for-byte.
|
|
109
|
+
*
|
|
110
|
+
* @param id - The `svix-id` header value.
|
|
111
|
+
* @param timestamp - The `svix-timestamp` header value (as received).
|
|
112
|
+
* @param body - The raw request body.
|
|
113
|
+
* @returns The signed content.
|
|
114
|
+
*/
|
|
115
|
+
export const buildSignedContent = (id, timestamp, body) => {
|
|
116
|
+
const bodyBytes = Buffer.isBuffer(body) ? body : Buffer.from(body, 'utf8');
|
|
117
|
+
return Buffer.concat([Buffer.from(`${id}.${timestamp}.`, 'utf8'), bodyBytes]);
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Splits a `svix-signature` header — a space-delimited list of
|
|
121
|
+
* `<version>,<base64>` entries (e.g. `v1,abc v1,def`) — into the `v1`
|
|
122
|
+
* signatures. Entries of any other version are ignored, not rejected: Svix
|
|
123
|
+
* may add versions and a receiver is expected to match on any one it
|
|
124
|
+
* understands.
|
|
125
|
+
*
|
|
126
|
+
* @param value - The raw header value.
|
|
127
|
+
* @returns The base64 `v1` signatures (empty when none are present).
|
|
128
|
+
*/
|
|
129
|
+
export const parseSignatureHeader = (value) => {
|
|
130
|
+
if (!value)
|
|
131
|
+
return [];
|
|
132
|
+
const out = [];
|
|
133
|
+
for (const entry of value.split(/\s+/u)) {
|
|
134
|
+
const separator = entry.indexOf(',');
|
|
135
|
+
if (separator <= 0)
|
|
136
|
+
continue;
|
|
137
|
+
const version = entry.slice(0, separator);
|
|
138
|
+
const signature = entry.slice(separator + 1);
|
|
139
|
+
if (version === SIGNATURE_VERSION && signature.length > 0)
|
|
140
|
+
out.push(signature);
|
|
141
|
+
}
|
|
142
|
+
return out;
|
|
143
|
+
};
|
|
144
|
+
/**
|
|
145
|
+
* Constant-time comparison of two base64-encoded digests.
|
|
146
|
+
*
|
|
147
|
+
* @param a - The first digest.
|
|
148
|
+
* @param b - The second digest.
|
|
149
|
+
* @returns `true` when the decoded bytes are equal.
|
|
150
|
+
*/
|
|
151
|
+
export const safeEqualBase64 = (a, b) => {
|
|
152
|
+
const left = Buffer.from(a, 'base64');
|
|
153
|
+
const right = Buffer.from(b, 'base64');
|
|
154
|
+
if (left.length === 0 || left.length !== right.length)
|
|
155
|
+
return false;
|
|
156
|
+
return timingSafeEqual(left, right);
|
|
157
|
+
};
|
|
158
|
+
/**
|
|
159
|
+
* Normalizes an address field that AgentMail types as `string` in one
|
|
160
|
+
* place and `string[]` in another into a trimmed, non-empty string array.
|
|
161
|
+
*
|
|
162
|
+
* @param value - The raw field value.
|
|
163
|
+
* @returns The addresses (empty when the field is absent or malformed).
|
|
164
|
+
*/
|
|
165
|
+
export const normalizeAddressList = (value) => {
|
|
166
|
+
const raw = Array.isArray(value) ? value : [value];
|
|
167
|
+
const out = [];
|
|
168
|
+
for (const entry of raw) {
|
|
169
|
+
if (typeof entry !== 'string')
|
|
170
|
+
continue;
|
|
171
|
+
const trimmed = entry.trim();
|
|
172
|
+
if (trimmed.length > 0)
|
|
173
|
+
out.push(trimmed);
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
};
|
|
177
|
+
/**
|
|
178
|
+
* Recovers the core's normalized headers map (lowercased names,
|
|
179
|
+
* multi-value headers as arrays) from AgentMail's `headers` object. Any
|
|
180
|
+
* non-string value is skipped; a missing or malformed map yields `{}`.
|
|
181
|
+
*
|
|
182
|
+
* @param value - The raw `headers` field.
|
|
183
|
+
* @returns Normalized headers map.
|
|
184
|
+
*/
|
|
185
|
+
export const lowercaseHeaderMap = (value) => {
|
|
186
|
+
const out = {};
|
|
187
|
+
if (!isRecord(value))
|
|
188
|
+
return out;
|
|
189
|
+
for (const [nameRaw, valueRaw] of Object.entries(value)) {
|
|
190
|
+
const values = Array.isArray(valueRaw)
|
|
191
|
+
? valueRaw.filter((v) => typeof v === 'string')
|
|
192
|
+
: typeof valueRaw === 'string'
|
|
193
|
+
? [valueRaw]
|
|
194
|
+
: [];
|
|
195
|
+
const name = nameRaw.toLowerCase();
|
|
196
|
+
for (const entry of values) {
|
|
197
|
+
const existing = out[name];
|
|
198
|
+
if (existing === undefined) {
|
|
199
|
+
out[name] = entry;
|
|
200
|
+
}
|
|
201
|
+
else if (Array.isArray(existing)) {
|
|
202
|
+
existing.push(entry);
|
|
203
|
+
}
|
|
204
|
+
else {
|
|
205
|
+
out[name] = [existing, entry];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return out;
|
|
210
|
+
};
|
|
211
|
+
/**
|
|
212
|
+
* Strips surrounding angle brackets from a `Message-ID` value.
|
|
213
|
+
*
|
|
214
|
+
* @param value - The raw value (with or without angle brackets).
|
|
215
|
+
* @returns The value without angle brackets, or `undefined` if input was
|
|
216
|
+
* empty or not a string.
|
|
217
|
+
*/
|
|
218
|
+
export const unwrapMessageId = (value) => {
|
|
219
|
+
if (typeof value !== 'string')
|
|
220
|
+
return undefined;
|
|
221
|
+
const trimmed = value.trim();
|
|
222
|
+
if (trimmed.length === 0)
|
|
223
|
+
return undefined;
|
|
224
|
+
return trimmed.replace(/^<|>$/gu, '');
|
|
225
|
+
};
|
|
226
|
+
/**
|
|
227
|
+
* Parses an ISO 8601 timestamp into a `Date`.
|
|
228
|
+
*
|
|
229
|
+
* @param value - The raw field value.
|
|
230
|
+
* @returns The date, or `undefined` when absent or unparseable.
|
|
231
|
+
*/
|
|
232
|
+
export const parseTimestamp = (value) => {
|
|
233
|
+
if (typeof value !== 'string' || value.length === 0)
|
|
234
|
+
return undefined;
|
|
235
|
+
const date = new Date(value);
|
|
236
|
+
return Number.isNaN(date.getTime()) ? undefined : date;
|
|
237
|
+
};
|
|
238
|
+
/**
|
|
239
|
+
* Parses a `Retry-After` header, which is equally valid as delta-seconds
|
|
240
|
+
* (`'30'`) or an HTTP-date, into whole seconds from now.
|
|
241
|
+
*
|
|
242
|
+
* @param value - The raw header value.
|
|
243
|
+
* @returns Seconds to wait (never negative), or `undefined` when absent or
|
|
244
|
+
* unparseable.
|
|
245
|
+
*/
|
|
246
|
+
export const parseRetryAfterSeconds = (value) => {
|
|
247
|
+
if (!value)
|
|
248
|
+
return undefined;
|
|
249
|
+
const trimmed = value.trim();
|
|
250
|
+
if (/^\d+$/u.test(trimmed))
|
|
251
|
+
return Number.parseInt(trimmed, 10);
|
|
252
|
+
const at = Date.parse(trimmed);
|
|
253
|
+
if (Number.isNaN(at))
|
|
254
|
+
return undefined;
|
|
255
|
+
return Math.max(0, Math.ceil((at - Date.now()) / 1000));
|
|
256
|
+
};
|
|
257
|
+
//# sourceMappingURL=utilities.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utilities.js","sourceRoot":"","sources":["../src/utilities.ts"],"names":[],"mappings":"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"}
|