@agentisend/sdk-node 0.1.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.
Files changed (50) hide show
  1. package/README.md +97 -0
  2. package/dist/cli/args.d.ts +24 -0
  3. package/dist/cli/args.js +71 -0
  4. package/dist/cli/args.js.map +1 -0
  5. package/dist/cli/commands.d.ts +29 -0
  6. package/dist/cli/commands.js +147 -0
  7. package/dist/cli/commands.js.map +1 -0
  8. package/dist/cli/config.d.ts +31 -0
  9. package/dist/cli/config.js +73 -0
  10. package/dist/cli/config.js.map +1 -0
  11. package/dist/cli/doctor.d.ts +36 -0
  12. package/dist/cli/doctor.js +161 -0
  13. package/dist/cli/doctor.js.map +1 -0
  14. package/dist/cli/listen.d.ts +28 -0
  15. package/dist/cli/listen.js +140 -0
  16. package/dist/cli/listen.js.map +1 -0
  17. package/dist/cli/main.d.ts +14 -0
  18. package/dist/cli/main.js +369 -0
  19. package/dist/cli/main.js.map +1 -0
  20. package/dist/cli/output.d.ts +40 -0
  21. package/dist/cli/output.js +35 -0
  22. package/dist/cli/output.js.map +1 -0
  23. package/dist/cli/scheduled-at.d.ts +19 -0
  24. package/dist/cli/scheduled-at.js +108 -0
  25. package/dist/cli/scheduled-at.js.map +1 -0
  26. package/dist/cli.d.ts +2 -0
  27. package/dist/cli.js +17 -0
  28. package/dist/cli.js.map +1 -0
  29. package/dist/client.d.ts +426 -0
  30. package/dist/client.js +542 -0
  31. package/dist/client.js.map +1 -0
  32. package/dist/compat-resend.d.ts +194 -0
  33. package/dist/compat-resend.js +233 -0
  34. package/dist/compat-resend.js.map +1 -0
  35. package/dist/errors.d.ts +82 -0
  36. package/dist/errors.js +92 -0
  37. package/dist/errors.js.map +1 -0
  38. package/dist/index.d.ts +10 -0
  39. package/dist/index.js +9 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/types.d.ts +499 -0
  42. package/dist/types.js +9 -0
  43. package/dist/types.js.map +1 -0
  44. package/dist/version.d.ts +8 -0
  45. package/dist/version.js +9 -0
  46. package/dist/version.js.map +1 -0
  47. package/dist/webhook-signing.d.ts +64 -0
  48. package/dist/webhook-signing.js +125 -0
  49. package/dist/webhook-signing.js.map +1 -0
  50. package/package.json +65 -0
@@ -0,0 +1,499 @@
1
+ /**
2
+ * Wire types, snake_case, mirroring what the API returns.
3
+ *
4
+ * Hand-written rather than imported from the server: a published client must
5
+ * not drag Fastify and Drizzle into a user's dependency tree. The guard against
6
+ * drift is the quickstart test, which runs this client against the real API.
7
+ */
8
+ export type AddressList = string | string[];
9
+ export interface Attachment {
10
+ filename?: string;
11
+ /** base64-encoded bytes. Provide this or `path`. */
12
+ content?: string;
13
+ /** Remote URL fetched at send time. Provide this or `content`. */
14
+ path?: string;
15
+ content_type?: string;
16
+ content_id?: string;
17
+ }
18
+ export interface SendEmailPayload {
19
+ from: string;
20
+ to: AddressList;
21
+ subject: string;
22
+ cc?: AddressList;
23
+ bcc?: AddressList;
24
+ reply_to?: AddressList;
25
+ html?: string;
26
+ text?: string;
27
+ headers?: Record<string, string>;
28
+ /** An object map, or Resend's `{name, value}[]` — both normalize to the map. */
29
+ tags?: Record<string, string> | {
30
+ name: string;
31
+ value: string;
32
+ }[];
33
+ /** ISO 8601, up to 30 days ahead. */
34
+ scheduled_at?: string;
35
+ attachments?: Attachment[];
36
+ }
37
+ export type MessageStatus = 'queued' | 'scheduled' | 'sent' | 'delivered' | 'delivery_delayed' | 'bounced' | 'complained' | 'opened' | 'clicked' | 'failed' | 'canceled' | 'suppressed';
38
+ export interface AttachmentView {
39
+ filename: string;
40
+ content_type: string | null;
41
+ content_id: string | null;
42
+ size_bytes: number | null;
43
+ path: string | null;
44
+ }
45
+ export interface Email {
46
+ id: string;
47
+ from: string;
48
+ to: string[];
49
+ cc: string[] | null;
50
+ bcc: string[] | null;
51
+ reply_to: string[] | null;
52
+ subject: string;
53
+ html: string | null;
54
+ text: string | null;
55
+ headers: Record<string, string> | null;
56
+ tags: Record<string, string> | null;
57
+ attachments: AttachmentView[] | null;
58
+ scheduled_at: string | null;
59
+ status: MessageStatus;
60
+ last_event: MessageStatus | null;
61
+ provider_message_id: string | null;
62
+ api_key_id: string | null;
63
+ domain: string;
64
+ created_at: string;
65
+ updated_at: string;
66
+ }
67
+ export interface ListEmailsQuery {
68
+ status?: MessageStatus;
69
+ from?: string;
70
+ to?: string;
71
+ domain?: string;
72
+ api_key_id?: string;
73
+ since?: string;
74
+ until?: string;
75
+ limit?: number;
76
+ cursor?: string;
77
+ /** Resend's name for `cursor`; the API accepts either. */
78
+ after?: string;
79
+ }
80
+ /** Paging for every list endpoint: one envelope, one query shape (M5.2). */
81
+ export interface ListQuery {
82
+ limit?: number;
83
+ cursor?: string;
84
+ /** Resend's name for `cursor`; the API accepts either. */
85
+ after?: string;
86
+ }
87
+ /** One component on the public status page, and what it reports about itself. */
88
+ export interface ServiceComponent {
89
+ name: string;
90
+ state: 'operational' | 'degraded' | 'down' | 'unknown';
91
+ detail: string;
92
+ }
93
+ export interface ServiceStatus {
94
+ status: 'operational' | 'degraded' | 'outage';
95
+ time: string;
96
+ components: ServiceComponent[];
97
+ }
98
+ /** One API call this account made, as the request log recorded it (M5.9). */
99
+ export interface RequestLogEntry {
100
+ id: string;
101
+ request_id: string;
102
+ method: string;
103
+ path: string;
104
+ /** The route template — what you group by when one id is not the question. */
105
+ route: string | null;
106
+ status: number;
107
+ duration_ms: number;
108
+ /** The catalogue code on a refusal; null when nothing refused. */
109
+ error_code: string | null;
110
+ api_key_id: string | null;
111
+ user_agent: string | null;
112
+ created_at: string;
113
+ }
114
+ /** One attachment on a message you sent (M5.10). Ids are stable positions. */
115
+ export interface SentAttachment {
116
+ id: string;
117
+ filename: string;
118
+ content_type: string | null;
119
+ size_bytes: number | null;
120
+ content_id: string | null;
121
+ /** Set when you sent a URL instead of bytes — nothing was stored here. */
122
+ path: string | null;
123
+ /** False for a URL attachment, and once retention has taken the message. */
124
+ bytes_available: boolean;
125
+ }
126
+ /** One attachment on a received message (M5.8). Ids are stable positions. */
127
+ export interface ReceivedAttachment {
128
+ id: string;
129
+ filename: string;
130
+ content_type: string;
131
+ size_bytes: number;
132
+ content_id: string | null;
133
+ }
134
+ /** A message someone sent to one of your domains. */
135
+ export interface ReceivedEmail {
136
+ id: string;
137
+ from: string;
138
+ to: string;
139
+ subject: string | null;
140
+ received_at: string;
141
+ size_bytes: number;
142
+ attachment_count: number;
143
+ /** Present on the single read. Data as it arrived — this SDK renders nothing. */
144
+ headers?: Record<string, string>;
145
+ text?: string | null;
146
+ html?: string | null;
147
+ attachments?: ReceivedAttachment[];
148
+ }
149
+ /** The types a declared event field can take (M5.7). */
150
+ export type EventFieldType = 'string' | 'number' | 'boolean' | 'date' | 'enum';
151
+ /** What an account says one of its custom events looks like. */
152
+ export interface EventDefinition {
153
+ id: string;
154
+ name: string;
155
+ description: string | null;
156
+ /** Field name → declared type. Flat, because event payloads are flat. */
157
+ schema: Record<string, EventFieldType>;
158
+ /** When false, fields the schema does not declare are allowed through. */
159
+ strict: boolean;
160
+ last_seen_at: string | null;
161
+ created_at: string;
162
+ updated_at: string;
163
+ }
164
+ /** One step of one automation run, and what it did (M5.6). */
165
+ export interface AutomationRunStep {
166
+ index: number;
167
+ kind: string;
168
+ /** `skipped` is a real outcome: a step that did nothing on purpose. */
169
+ status: 'succeeded' | 'skipped' | 'failed';
170
+ output: Record<string, unknown> | null;
171
+ error: string | null;
172
+ started_at: string;
173
+ finished_at: string | null;
174
+ }
175
+ /** One execution of one automation. `steps` is present on the single read. */
176
+ export interface AutomationRun {
177
+ id: string;
178
+ automation_id: string;
179
+ version_number: number | null;
180
+ trigger_type: string;
181
+ event_name: string | null;
182
+ contact_id: string | null;
183
+ status: 'running' | 'succeeded' | 'failed';
184
+ started_at: string;
185
+ finished_at: string | null;
186
+ steps?: AutomationRunStep[];
187
+ }
188
+ /** One item's outcome in a suppression batch (M5.5). */
189
+ export interface SuppressionBatchItem {
190
+ index: number;
191
+ email: string;
192
+ status: 'added' | 'removed' | 'not_found' | 'rejected';
193
+ id?: string;
194
+ error?: {
195
+ code: string;
196
+ message: string;
197
+ fix: string;
198
+ docs_url: string;
199
+ };
200
+ }
201
+ /** M5.4 — a subscription topic: the kind of mail a contact consented to. */
202
+ export interface Topic {
203
+ id: string;
204
+ name: string;
205
+ description: string | null;
206
+ /** Whether a contact who never answered receives this topic. */
207
+ default_subscribed: boolean;
208
+ created_at: string;
209
+ updated_at: string;
210
+ }
211
+ /** One contact's standing on one topic, and what decided it. */
212
+ export interface ContactTopic {
213
+ id: string;
214
+ name: string;
215
+ subscribed: boolean;
216
+ /** 'explicit' when the contact answered; 'default' when the topic did. */
217
+ basis: 'explicit' | 'default';
218
+ source: string | null;
219
+ updated_at: string | null;
220
+ }
221
+ export interface Page<T> {
222
+ data: T[];
223
+ has_more: boolean;
224
+ next_cursor: string | null;
225
+ }
226
+ export interface BatchItemResult {
227
+ index: number;
228
+ status: 'accepted' | 'rejected';
229
+ id?: string;
230
+ error?: {
231
+ code: string;
232
+ message: string;
233
+ fix: string;
234
+ docs_url: string;
235
+ details?: {
236
+ path: string;
237
+ message: string;
238
+ }[];
239
+ };
240
+ }
241
+ export type ApiKeyPermission = 'full_access' | 'sending_access';
242
+ export interface ApiKey {
243
+ id: string;
244
+ name: string;
245
+ permission: ApiKeyPermission;
246
+ domain_scope: string | null;
247
+ token_prefix: string;
248
+ created_at: string;
249
+ last_used_at: string | null;
250
+ }
251
+ export interface CreatedApiKey {
252
+ id: string;
253
+ /** Shown exactly once. */
254
+ token: string;
255
+ }
256
+ export type EventType = string;
257
+ export interface WebhookEndpoint {
258
+ id: string;
259
+ url: string;
260
+ events: EventType[];
261
+ disabled: boolean;
262
+ /** True when deliveries also carry svix-id / -timestamp / -signature (M5.11). */
263
+ svix_compat: boolean;
264
+ created_at: string;
265
+ updated_at: string;
266
+ }
267
+ export interface CreatedWebhookEndpoint extends WebhookEndpoint {
268
+ /** Shown exactly once. Store it — no endpoint returns it again. */
269
+ secret: string;
270
+ }
271
+ export interface DeadLetter {
272
+ id: string;
273
+ delivery_id: string | null;
274
+ event_id: string;
275
+ event_type: EventType;
276
+ occurred_at: string;
277
+ attempts: number;
278
+ last_status_code: number | null;
279
+ last_response_body: string | null;
280
+ reason: string;
281
+ payload: Record<string, unknown>;
282
+ created_at: string;
283
+ }
284
+ export interface ReplayResult {
285
+ replayed: number;
286
+ delivery_ids: string[];
287
+ truncated: boolean;
288
+ }
289
+ export type LimitPeriod = 'hourly' | 'daily' | 'monthly';
290
+ export interface Limit {
291
+ api_key_id: string;
292
+ /** null = unlimited. */
293
+ budget_per_period: number | null;
294
+ period: LimitPeriod;
295
+ consumed_in_period: number;
296
+ period_started_at: string;
297
+ /** null = unlimited. */
298
+ rate_ceiling_per_minute: number | null;
299
+ consumed_in_window: number;
300
+ rate_window_started_at: string;
301
+ paused: boolean;
302
+ paused_at: string | null;
303
+ paused_reason: string | null;
304
+ updated_at: string;
305
+ }
306
+ export type TrustState = 'ok' | 'warning' | 'throttled' | 'paused';
307
+ export interface TrustStanding {
308
+ state: TrustState;
309
+ reasons: string[];
310
+ next_review_at: string | null;
311
+ history: {
312
+ type: string;
313
+ reason: string | null;
314
+ occurred_at: string;
315
+ }[];
316
+ }
317
+ /** A tier someone can buy, or `none` — no plan in force. There is no free tier. */
318
+ export type PlanTier = 'none' | 'starter' | 'pro' | 'scale';
319
+ export type PaidTier = Exclude<PlanTier, 'none'>;
320
+ export type PlanStatus = 'none' | 'trialing' | 'active' | 'past_due' | 'canceled';
321
+ export type BillingTerm = 'month' | 'year';
322
+ export interface BillingTermPrice {
323
+ per_month_minor: number;
324
+ total_minor: number;
325
+ months: number;
326
+ discount_percent: number;
327
+ }
328
+ /** GET /billing/plan — the plan an account runs under, in a shape an agent can budget against. */
329
+ export interface BillingPlan {
330
+ /** The tier in force: `pro` during the 14-day trial, `none` without a plan. */
331
+ tier: PlanTier;
332
+ plan_status: PlanStatus;
333
+ /** True only for an owner or admin in the console whose account has no plan in force. Always false for an API key. */
334
+ needs_plan_selection: boolean;
335
+ billing_term: BillingTerm | null;
336
+ entitlements: {
337
+ tier: PlanTier;
338
+ included_emails_per_month: number;
339
+ retention_days: number;
340
+ max_domains: number | null;
341
+ max_seats: number;
342
+ overage_minor_per_1000_emails: number | null;
343
+ };
344
+ subscription: {
345
+ status: string;
346
+ price_lookup_key: string | null;
347
+ current_period_end: string | null;
348
+ cancel_at_period_end: boolean;
349
+ } | null;
350
+ billing_configured: boolean;
351
+ trial: {
352
+ eligible: boolean;
353
+ days: number;
354
+ started_at: string | null;
355
+ ends_at: string | null;
356
+ days_left: number | null;
357
+ emails_used: number | null;
358
+ email_cap: number;
359
+ };
360
+ /** The terms that can be bought right now. */
361
+ terms_on_sale: BillingTerm[];
362
+ plans: {
363
+ tier: PaidTier;
364
+ name: string;
365
+ featured: boolean;
366
+ trial_eligible: boolean;
367
+ included_emails_per_month: number;
368
+ max_domains: number | null;
369
+ max_seats: number;
370
+ retention_days: number;
371
+ prices: {
372
+ month: BillingTermPrice;
373
+ year: BillingTermPrice;
374
+ };
375
+ }[];
376
+ viewer: {
377
+ role: 'owner' | 'admin' | 'viewer' | null;
378
+ can_purchase: boolean;
379
+ can_start_trial: boolean;
380
+ };
381
+ purchasable: {
382
+ tier: PaidTier;
383
+ monthly_price_minor: number;
384
+ included_emails_per_month: number;
385
+ }[];
386
+ }
387
+ export type DomainRegion = 'us' | 'eu';
388
+ /** One-release aliases the API still accepts on input. */
389
+ export type LegacyDomainRegion = 'us-east-1' | 'eu-west-1' | 'sa-east-1' | 'ap-northeast-1';
390
+ export interface DomainRecord {
391
+ record: 'SPF' | 'DKIM' | 'DMARC' | 'RETURN_PATH' | 'TRACKING' | 'TRACKING_CAA' | 'RECEIVING';
392
+ name: string;
393
+ type: 'TXT' | 'MX' | 'CNAME' | 'CAA';
394
+ value: string;
395
+ ttl: number;
396
+ priority: number | null;
397
+ /** `recommended` is DMARC and TrackingCAA's resting state: advised, never required. */
398
+ status: 'pending' | 'verified' | 'failed' | 'recommended';
399
+ checked_at: string | null;
400
+ /** What to do about this record, the alternative accepted forms included. */
401
+ fix: string;
402
+ }
403
+ export interface Domain {
404
+ id: string;
405
+ name: string;
406
+ region: DomainRegion;
407
+ status: 'pending' | 'verified' | 'failed' | 'partially_verified' | 'partially_failed';
408
+ dkim_selector: string;
409
+ /** A8 — both off unless turned on with `domains.update`. */
410
+ click_tracking: boolean;
411
+ open_tracking: boolean;
412
+ tracking_subdomain: string;
413
+ /**
414
+ * DNS sheet. Present on create, get, verify, and update. `list()` omits it
415
+ * (research/01-resend-api-baseline.md:182); call `get(id)` for the records.
416
+ */
417
+ records?: DomainRecord[];
418
+ /** Tracking records that are not yet verified. Detail only, never on list. */
419
+ tracking_issues?: {
420
+ record: 'TRACKING' | 'TRACKING_CAA';
421
+ message: string;
422
+ fix: string;
423
+ }[];
424
+ created_at: string;
425
+ verified_at: string | null;
426
+ }
427
+ export interface Deleted {
428
+ id: string;
429
+ deleted: boolean;
430
+ }
431
+ /** M4.8 — one person on an account, and what they may do. */
432
+ export interface TeamMember {
433
+ id: string;
434
+ user_id: string;
435
+ email: string;
436
+ name: string | null;
437
+ role: 'owner' | 'admin' | 'viewer';
438
+ /** True for the member the credential is acting as. */
439
+ is_you: boolean;
440
+ created_at: string;
441
+ }
442
+ /** M4.8 — an invitation that has not been accepted, cancelled or expired. */
443
+ export interface TeamInvite {
444
+ id: string;
445
+ email: string;
446
+ role: 'owner' | 'admin' | 'viewer';
447
+ invited_by: string | null;
448
+ invited_by_email: string | null;
449
+ expires_at: string;
450
+ created_at: string;
451
+ }
452
+ /** M4.9 — one change on the account, with what it looked like before. */
453
+ export interface AuditEntry {
454
+ id: string;
455
+ account_id: string | null;
456
+ /** `user` when a person did it through the console, `api_key` for a key. */
457
+ actor_type: string;
458
+ actor_id: string | null;
459
+ actor_user_id: string | null;
460
+ actor_email: string | null;
461
+ action: string;
462
+ target_type: string | null;
463
+ target_id: string | null;
464
+ /** Shapes only: field names, counts and states — never message content. */
465
+ before: Record<string, unknown>;
466
+ after: Record<string, unknown>;
467
+ reason: string | null;
468
+ created_at: string;
469
+ }
470
+ /** M4.16 - one remediation step, ready to execute rather than to interpret. */
471
+ export interface ExplainAction {
472
+ do: string;
473
+ call?: {
474
+ method: 'GET' | 'POST' | 'PATCH' | 'DELETE';
475
+ path: string;
476
+ body?: Record<string, unknown>;
477
+ };
478
+ }
479
+ /** What happened to a message, and what to do about it. */
480
+ export interface ExplainReport {
481
+ id: string;
482
+ status: string;
483
+ verdict: string;
484
+ what_happened: string;
485
+ evidence: Record<string, unknown>;
486
+ retryable: boolean;
487
+ actions: ExplainAction[];
488
+ }
489
+ /** A send tested against every gate, with nothing sent and nothing spent. */
490
+ export interface PreflightReport {
491
+ ok: boolean;
492
+ simulated: boolean;
493
+ error: {
494
+ code: string;
495
+ message: string;
496
+ fix: string;
497
+ } | null;
498
+ checks: Record<string, unknown>;
499
+ }
package/dist/types.js ADDED
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Wire types, snake_case, mirroring what the API returns.
3
+ *
4
+ * Hand-written rather than imported from the server: a published client must
5
+ * not drag Fastify and Drizzle into a user's dependency tree. The guard against
6
+ * drift is the quickstart test, which runs this client against the real API.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,8 @@
1
+ /**
2
+ * The published version, as a literal.
3
+ *
4
+ * Read rather than imported from package.json so the shipped package needs no
5
+ * JSON import and no bundler has to resolve one. It cannot drift silently:
6
+ * `sdk_node_is_publishable_standalone` compares it to the manifest.
7
+ */
8
+ export declare const SDK_VERSION = "0.1.0";
@@ -0,0 +1,9 @@
1
+ /**
2
+ * The published version, as a literal.
3
+ *
4
+ * Read rather than imported from package.json so the shipped package needs no
5
+ * JSON import and no bundler has to resolve one. It cannot drift silently:
6
+ * `sdk_node_is_publishable_standalone` compares it to the manifest.
7
+ */
8
+ export const SDK_VERSION = '0.1.0';
9
+ //# sourceMappingURL=version.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"version.js","sourceRoot":"","sources":["../src/version.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,OAAO,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Webhook signing — Stripe-shaped HMAC-SHA256.
3
+ *
4
+ * Header value format: `t=<unix seconds>,v1=<hmac_hex>`
5
+ * where hmac = HMAC-SHA256(secret, `${t}.${raw_body}`).
6
+ *
7
+ * Ported from a proven webhook-signing.ts; branding
8
+ * renamed X-Warmy-* -> X-AgentiSend-*, timestamps are unix seconds
9
+ * per the AgentiSend wire spec (PRD F4 / B2).
10
+ */
11
+ /** 5-minute tolerance window for signature freshness. */
12
+ export declare const SIGNATURE_TOLERANCE_SECONDS: number;
13
+ export declare const SIGNATURE_HEADER = "x-agentisend-signature";
14
+ export declare const EVENT_ID_HEADER = "x-agentisend-event-id";
15
+ export declare const EVENT_TYPE_HEADER = "x-agentisend-event-type";
16
+ export declare const TIMESTAMP_HEADER = "x-agentisend-timestamp";
17
+ export declare const REPLAY_HEADER = "x-agentisend-replay";
18
+ /**
19
+ * M5.11 — Svix's header set, beside ours, opt-in per endpoint.
20
+ *
21
+ * A receiver migrating from Resend already has a verifier: the `svix` library,
22
+ * or the twenty lines it documents. Making them rewrite it to accept our
23
+ * header is a migration cost with nothing on the other side of it, so an
24
+ * endpoint can ask for both and keep the verifier it has.
25
+ *
26
+ * The scheme is Svix's, exactly: HMAC-SHA256 over `${id}.${timestamp}.${body}`
27
+ * with the key being the base64-decoded bytes after the `whsec_` prefix, and
28
+ * the value a space-separated list of `v1,<base64>` — a list because Svix
29
+ * rotates by sending old and new signatures together.
30
+ */
31
+ export declare const SVIX_ID_HEADER = "svix-id";
32
+ export declare const SVIX_TIMESTAMP_HEADER = "svix-timestamp";
33
+ export declare const SVIX_SIGNATURE_HEADER = "svix-signature";
34
+ /** `v1,<base64 hmac>` over `${messageId}.${timestampSeconds}.${body}`. */
35
+ export declare function signSvixPayload(secret: string, messageId: string, timestampSeconds: number, body: string): string;
36
+ /** The three headers a Svix-shaped verifier reads. */
37
+ export declare function generateSvixHeaders(secret: string, messageId: string, timestampSeconds: number, body: string): Record<string, string>;
38
+ /** Sign a raw body at a given unix-second timestamp. Pure. */
39
+ export declare function signWebhookPayload(secret: string, timestampSeconds: number, body: string): string;
40
+ export interface VerifyOptions {
41
+ /** Current time in unix seconds. Defaults to Date.now()/1000. Injectable for tests. */
42
+ nowSeconds?: number;
43
+ /** Tolerance window in seconds. Defaults to 5 minutes. */
44
+ toleranceSeconds?: number;
45
+ }
46
+ /**
47
+ * Verify a signature header against a raw body. Timing-safe on the
48
+ * comparison path; every malformed input returns false, never throws.
49
+ */
50
+ export declare function verifyWebhookSignature(secret: string, signatureHeader: string, body: string, options?: VerifyOptions): boolean;
51
+ /** What a delivery may carry beside our own headers (M5.11). */
52
+ export interface WebhookHeaderOptions {
53
+ /**
54
+ * Also sign this delivery the way Svix does, so a receiver migrating from
55
+ * Resend keeps the verifier it already has. Needs the secret and the body,
56
+ * because Svix signs the id and timestamp along with them.
57
+ */
58
+ svixCompat?: {
59
+ secret: string;
60
+ body: string;
61
+ };
62
+ }
63
+ /** Full delivery header set for an event payload. */
64
+ export declare function generateWebhookHeaders(eventId: string, eventType: string, timestampSeconds: number, signature: string, replay?: boolean, options?: WebhookHeaderOptions): Record<string, string>;