@easybits.cloud/mailmask 0.4.8 → 0.4.9

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.
@@ -0,0 +1,802 @@
1
+ export interface MailMaskConfig {
2
+ apiKey: string;
3
+ baseUrl?: string;
4
+ /**
5
+ * `fetch` alterno. Sirve para poner un timeout por llamada
6
+ * (`AbortSignal.timeout`), reintentos o un proxy, y para probar el SDK
7
+ * contra el servidor en proceso sin levantar un puerto.
8
+ */
9
+ fetch?: typeof fetch;
10
+ }
11
+ export interface Domain {
12
+ id: string;
13
+ domain: string;
14
+ /** Último valor medido. Si `verifiedStatus` es "unknown", no lo afirmes: confírmalo con `domains.health`. */
15
+ verified: boolean;
16
+ /** Último valor medido. Si `mxStatus` es "unknown", no lo afirmes: confírmalo con `domains.health`. */
17
+ mxConfigured: boolean;
18
+ registeredViaMailmask: boolean;
19
+ createdAt: string;
20
+ /** Cuándo se midieron `verified` y `mxConfigured` en vivo (health, verify o el servidor). null = nunca. */
21
+ checkedAt?: string | null;
22
+ /** "unknown" si la revisión tiene más de 24 h o nunca se hizo. */
23
+ mxStatus?: "ok" | "missing" | "unknown";
24
+ /** "unknown" si la revisión tiene más de 24 h o nunca se hizo. */
25
+ verifiedStatus?: "ok" | "missing" | "unknown";
26
+ /** Presente cuando algún estado es "unknown": qué hacer para confirmarlo. */
27
+ statusNote?: string;
28
+ /** Sólo en `domains.list`: reenvíos del mes en curso. */
29
+ monthlyForwards?: number;
30
+ /** Sólo en `domains.list`: tope de reenvíos por hora del plan. */
31
+ forwardPerHour?: number;
32
+ }
33
+ export interface DnsRecord {
34
+ type: "MX" | "TXT" | "CNAME";
35
+ name: string;
36
+ value: string;
37
+ priority?: number;
38
+ }
39
+ /** Respuesta de `domains.create`: el dominio y los registros DNS que hay que poner. */
40
+ export interface DomainCreated {
41
+ domain: Domain;
42
+ /** true si es el 2.º dominio sin activar: se guarda pero no reenvía hasta activarlo ($99/mes). */
43
+ requiereActivacion: boolean;
44
+ dnsRecords: {
45
+ mx: DnsRecord;
46
+ verification: DnsRecord;
47
+ dkim: DnsRecord[];
48
+ spf: DnsRecord;
49
+ };
50
+ }
51
+ /** Respuesta de `domains.verify`. */
52
+ export interface DomainVerification {
53
+ domain: string;
54
+ verified: boolean;
55
+ dkimVerified: boolean;
56
+ /** Si el MX apunta al inbound de SES, medido en la misma llamada; null si el DNS no respondió. */
57
+ mxConfigured?: boolean | null;
58
+ /** true cuando no se pudo consultar a SES: los campos son el último estado conocido. */
59
+ stale?: boolean;
60
+ error?: string;
61
+ }
62
+ /** Nombre público de `Alias` desde la 0.4.5. */
63
+ export type Address = Alias;
64
+ /** Nombre público de `AliasCreated` desde la 0.4.5. */
65
+ export type AddressCreated = AliasCreated;
66
+ /** Nombre público de `CreateAliasInput` desde la 0.4.5. */
67
+ export type CreateAddressInput = CreateAliasInput;
68
+ /** Nombre público de `UpdateAliasInput` desde la 0.4.5. */
69
+ export type UpdateAddressInput = UpdateAliasInput;
70
+ export interface Alias {
71
+ alias: string;
72
+ domainId: string;
73
+ destinations: string[];
74
+ enabled: boolean;
75
+ forwardCount: number;
76
+ lastFrom?: string | null;
77
+ lastAt?: string | null;
78
+ createdAt: string;
79
+ /** true si la máscara guarda el correo en un buzón IMAP. */
80
+ mailboxEnabled?: boolean;
81
+ }
82
+ /** Credenciales de un buzón IMAP recién creado. La contraseña se muestra una sola vez. */
83
+ export interface MailboxCreated {
84
+ email: string;
85
+ password: string;
86
+ quotaBytes: number;
87
+ imap: {
88
+ host: string;
89
+ port: number;
90
+ security: string;
91
+ };
92
+ smtp: {
93
+ host: string;
94
+ port: number;
95
+ security: string;
96
+ };
97
+ }
98
+ /** `aliases.create`: el alias, y si pediste buzón, sus credenciales o por qué no se creó. */
99
+ export interface AliasCreated extends Alias {
100
+ buzon?: MailboxCreated | null;
101
+ errorBuzon?: string | null;
102
+ }
103
+ export interface CreateAliasInput {
104
+ /** Parte local, sin el dominio: "hola" para hola@tudominio.com. `*` para catch-all. */
105
+ alias: string;
106
+ /** Adónde reenviar. Puede ir vacío sólo si `mailbox` es true. */
107
+ destinations?: string[];
108
+ /** Crear también un buzón IMAP (requiere dominio activado). */
109
+ mailbox?: boolean;
110
+ }
111
+ export interface UpdateAliasInput {
112
+ enabled?: boolean;
113
+ destinations?: string[];
114
+ }
115
+ export type RuleField = "to" | "from" | "subject";
116
+ export type RuleMatch = "contains" | "equals" | "regex";
117
+ /** `forward` y `webhook` requieren `target`; `discard` no. */
118
+ export type RuleAction = "forward" | "webhook" | "discard";
119
+ export interface Rule {
120
+ id: string;
121
+ domainId: string;
122
+ field: RuleField;
123
+ match: RuleMatch;
124
+ value: string;
125
+ action: RuleAction;
126
+ target: string;
127
+ priority: number;
128
+ enabled: boolean;
129
+ createdAt: string;
130
+ }
131
+ export interface CreateRuleInput {
132
+ field: RuleField;
133
+ /** Los patrones `regex` se validan al guardar: uno peligroso responde 400. */
134
+ match: RuleMatch;
135
+ value: string;
136
+ action: RuleAction;
137
+ /** Destino del `forward` o URL del `webhook`. Se ignora con `discard`. */
138
+ target?: string;
139
+ priority?: number;
140
+ enabled?: boolean;
141
+ }
142
+ export interface UpdateRuleInput {
143
+ field?: RuleField;
144
+ match?: RuleMatch;
145
+ value?: string;
146
+ action?: RuleAction;
147
+ target?: string;
148
+ priority?: number;
149
+ enabled?: boolean;
150
+ }
151
+ export interface EmailLog {
152
+ id: string;
153
+ domainId: string;
154
+ timestamp: string;
155
+ from: string;
156
+ to: string;
157
+ subject: string;
158
+ /** Entrantes: forwarded, discarded, failed, rule_matched. Salientes: sent → delivered | bounced | complained. */
159
+ status: "forwarded" | "discarded" | "failed" | "rule_matched" | "sent" | "delivered" | "bounced" | "complained";
160
+ forwardedTo: string;
161
+ sizeBytes: number;
162
+ error?: string;
163
+ /** Id interno de SES; cruza el log con los eventos de entrega. Sólo en salientes. */
164
+ sesMessageId?: string;
165
+ }
166
+ export interface SendEmailInput {
167
+ to: string;
168
+ subject: string;
169
+ /** Al menos uno de `html`, `body` o `markdown`. Con html y body se manda multipart. HTML máx. 100 KB. */
170
+ html?: string;
171
+ body?: string;
172
+ markdown?: string;
173
+ replyTo?: string;
174
+ /**
175
+ * Parte local de un alias **activo** del dominio. Sin esto el correo sale
176
+ * desde `noreply@tudominio.com`.
177
+ */
178
+ from?: string;
179
+ /** Nombre visible del remitente: `Libretas <hola@tudominio.com>`. */
180
+ fromName?: string;
181
+ /** Copias visibles. Máx. 20; también pasan por la lista de supresión. */
182
+ cc?: string[];
183
+ /** Copias ocultas. Máx. 20. */
184
+ bcc?: string[];
185
+ /** `Message-ID` del correo al que se responde, para que el cliente lo enhebre. */
186
+ inReplyTo?: string;
187
+ /** Cadena `References` del hilo. */
188
+ references?: string;
189
+ /** Archivos subidos antes con `attachments.upload`. Se borran de S3 al enviarse. */
190
+ attachments?: AttachmentRef[];
191
+ }
192
+ /** Lo que devuelve `attachments.upload`; se pasa tal cual en `SendEmailInput.attachments`. */
193
+ export interface AttachmentRef {
194
+ key: string;
195
+ filename: string;
196
+ contentType?: string;
197
+ }
198
+ export interface UploadAttachmentInput {
199
+ filename: string;
200
+ contentType: string;
201
+ data: Uint8Array | Blob;
202
+ }
203
+ export interface UploadedAttachment {
204
+ ok: boolean;
205
+ key: string;
206
+ filename: string;
207
+ size: number;
208
+ }
209
+ export interface SendOptions {
210
+ /**
211
+ * Reintentar con la misma clave (máx. 128 caracteres) devuelve la respuesta
212
+ * original sin volver a enviar ni consumir cuota, durante 24 h.
213
+ */
214
+ idempotencyKey?: string;
215
+ }
216
+ export interface Suppression {
217
+ email: string;
218
+ /** `bounce:Permanent`, `complaint` o `manual`. */
219
+ reason: string;
220
+ createdAt: string;
221
+ }
222
+ export type WebhookEvent = "email.received" | "email.sent" | "email.delivered" | "email.bounced" | "email.complained";
223
+ export interface Webhook {
224
+ id: string;
225
+ domainId: string;
226
+ url: string;
227
+ events: WebhookEvent[];
228
+ enabled: boolean;
229
+ createdAt: string;
230
+ }
231
+ /** Lo que devuelve `webhooks.create`. El `secret` se muestra una sola vez. */
232
+ export interface WebhookCreated extends Webhook {
233
+ secret: string;
234
+ }
235
+ export interface CreateWebhookInput {
236
+ /** Debe ser https y pública. */
237
+ url: string;
238
+ events: WebhookEvent[];
239
+ }
240
+ export interface UpdateWebhookInput {
241
+ url?: string;
242
+ events?: WebhookEvent[];
243
+ enabled?: boolean;
244
+ }
245
+ export interface WebhookDelivery {
246
+ id: string;
247
+ webhookId: string;
248
+ event: WebhookEvent | "ping";
249
+ attempts: number;
250
+ status: "pending" | "delivered" | "failed";
251
+ nextAt: string;
252
+ lastError: string | null;
253
+ lastStatusCode: number | null;
254
+ createdAt: string;
255
+ }
256
+ /** Cuerpo que recibe tu endpoint. `data` depende del evento. */
257
+ export interface WebhookPayload<T = Record<string, unknown>> {
258
+ event: WebhookEvent | "ping";
259
+ domainId: string;
260
+ timestamp: string;
261
+ data: T;
262
+ }
263
+ export interface BulkSendInput {
264
+ recipients: string[];
265
+ subject: string;
266
+ html: string;
267
+ /** Alias activo del dominio; por omisión `noreply`. */
268
+ from?: string;
269
+ }
270
+ /** Lo que devuelve `bulkSend`: el job se encola, todavía no hay estado que leer. */
271
+ export interface BulkJobCreated {
272
+ ok: boolean;
273
+ jobId: string;
274
+ }
275
+ export interface BulkJob {
276
+ id: string;
277
+ domainId: string;
278
+ recipients: string[];
279
+ subject: string;
280
+ html: string;
281
+ from: string;
282
+ status: string;
283
+ totalRecipients: number;
284
+ sent: number;
285
+ failed: number;
286
+ /** Destinatarios saltados por bounce o queja previa: total = sent + failed + skippedSuppressed. */
287
+ skippedSuppressed: number;
288
+ lastError?: string | null;
289
+ createdAt: string;
290
+ completedAt?: string | null;
291
+ expiresAt: string;
292
+ }
293
+ export interface SmtpCredential {
294
+ id: string;
295
+ domainId: string;
296
+ label: string;
297
+ iamUsername: string;
298
+ createdAt: string;
299
+ }
300
+ /**
301
+ * Lo que devuelve `smtp.create`. La contraseña se muestra **una sola vez**: no
302
+ * se puede volver a consultar, sólo revocar la credencial y crear otra.
303
+ */
304
+ export interface SmtpCredentialCreated {
305
+ id: string;
306
+ label: string;
307
+ server: string;
308
+ port: number;
309
+ encryption: string;
310
+ username: string;
311
+ password: string;
312
+ createdAt: string;
313
+ }
314
+ export interface ApiKey {
315
+ id: string;
316
+ name: string;
317
+ /** Primeros caracteres de la llave, para identificarla en listados. */
318
+ keyPrefix: string;
319
+ lastUsedAt?: string;
320
+ createdAt: string;
321
+ }
322
+ export type DnsRecordType = "A" | "AAAA" | "CNAME" | "TXT" | "MX" | "NS" | "CAA" | "SRV";
323
+ /**
324
+ * Un conjunto de registros con el mismo nombre y tipo. El DNS trabaja así, no con registros
325
+ * sueltos: `values` es la lista completa y al escribirla reemplaza lo que hubiera.
326
+ */
327
+ export interface DnsRRSet {
328
+ name: string;
329
+ type: DnsRecordType;
330
+ ttl: number;
331
+ values: string[];
332
+ }
333
+ export interface DnsRRSetAnotado extends DnsRRSet {
334
+ /** Lo pone MailMask para que el correo funcione. */
335
+ managed: boolean;
336
+ editable: boolean;
337
+ managedReason?: string;
338
+ /** Valores que hay que conservar aunque el registro sea editable (el SPF). */
339
+ protectedValues?: string[];
340
+ }
341
+ export interface DnsZoneState {
342
+ status: "none" | "pending_delegation" | "active";
343
+ hostedZoneId?: string;
344
+ nameservers?: string[];
345
+ delegated?: boolean;
346
+ }
347
+ export interface DnsListResponse {
348
+ zone: DnsZoneState;
349
+ records: DnsRRSetAnotado[];
350
+ /** Presente cuando todavía no hay zona: dice qué hacer. */
351
+ hint?: string;
352
+ }
353
+ export interface DnsZoneCreated {
354
+ hostedZoneId: string;
355
+ nameservers: string[];
356
+ /** Lo que copiamos de tu proveedor anterior. Revísalo: puede faltar algo. */
357
+ imported: DnsRRSet[];
358
+ importWarning: string;
359
+ }
360
+ export interface DnsDelegation {
361
+ delegated: boolean;
362
+ observed: string[];
363
+ expected: string[];
364
+ }
365
+ export interface DnsImportResult {
366
+ found: DnsRRSet[];
367
+ nameservers: string[];
368
+ warning: string;
369
+ }
370
+ export interface DnsChangeResult {
371
+ record?: DnsRRSet;
372
+ records?: DnsRRSet[];
373
+ changeId: string;
374
+ propagacion: string;
375
+ }
376
+ export type DnsPreset = "vercel" | "netlify" | "github-pages" | "cloudflare-pages" | "render" | "fly" | "easybits" | "redirect-a-www" | "dmarc";
377
+ export interface DnsPresetPreview {
378
+ dryRun: true;
379
+ records: DnsRRSet[];
380
+ /** Lo que hay hoy en cada (nombre, tipo) de `records`, en el mismo orden; null = nada. */
381
+ current: (DnsRRSet | null)[];
382
+ }
383
+ export interface WebsiteHost {
384
+ name: string;
385
+ /** '@' para la raíz o el subdominio ('www', 'app'). */
386
+ label: string;
387
+ records: {
388
+ type: "A" | "AAAA" | "CNAME";
389
+ values: string[];
390
+ }[];
391
+ platform: {
392
+ id: string;
393
+ label: string;
394
+ } | null;
395
+ issues: string[];
396
+ https: {
397
+ ok: boolean;
398
+ status?: number;
399
+ location?: string;
400
+ certValidTo?: string;
401
+ error?: string;
402
+ } | null;
403
+ }
404
+ export interface WebsiteStatus {
405
+ domain: string;
406
+ /** true si la zona es de MailMask y se puede editar desde aquí. */
407
+ editable: boolean;
408
+ hosts: WebsiteHost[];
409
+ }
410
+ export interface DnsSetupRecord {
411
+ id: string;
412
+ type: "MX" | "TXT" | "CNAME";
413
+ /** Relativo al dominio, como lo piden casi todos los paneles ('@', '_amazonses'). */
414
+ name: string;
415
+ fqdn: string;
416
+ value: string;
417
+ /** Sólo MX, para paneles con campo de prioridad aparte (entonces el valor es `host`). */
418
+ priority?: number;
419
+ host?: string;
420
+ level: "requerido" | "recomendado" | "opcional";
421
+ purpose: string;
422
+ benefit?: string;
423
+ /** Ayuda en texto con **negritas** estilo markdown. */
424
+ hints: string[];
425
+ /** Sólo con `live`: si el DNS público ya lo tiene; null = no se pudo consultar. */
426
+ ok?: boolean | null;
427
+ observed?: string[];
428
+ /** SPF: valor fusionado cuando ya existe otro SPF (se edita ése, no se crea otro). */
429
+ suggestedValue?: string;
430
+ }
431
+ export interface DnsSetup {
432
+ domain: string;
433
+ records: DnsSetupRecord[];
434
+ live: boolean;
435
+ nameservers?: string[];
436
+ /** Panel donde se pegan, deducido de los nameservers. */
437
+ registrarHint?: {
438
+ provider: string;
439
+ label: string;
440
+ note: string;
441
+ } | null;
442
+ summary?: string;
443
+ }
444
+ export interface BillingStatus {
445
+ subscription: {
446
+ plan: string;
447
+ status: string;
448
+ currentPeriodEnd?: string;
449
+ [k: string]: unknown;
450
+ };
451
+ }
452
+ export interface Addon {
453
+ id: string;
454
+ kind: string;
455
+ /** Dominio al que aplica; sin él es un add-on legado de toda la cuenta. */
456
+ domainId?: string;
457
+ status: "pending" | "active" | "cancelled" | "expired";
458
+ priceCents: number;
459
+ currentPeriodEnd?: string;
460
+ createdAt: string;
461
+ cancelledAt?: string;
462
+ source: "purchase" | "courtesy" | "migration";
463
+ }
464
+ export interface AddonsResponse {
465
+ catalog: Record<string, {
466
+ price: number;
467
+ label: string;
468
+ }>;
469
+ forSale: string[];
470
+ mine: Addon[];
471
+ }
472
+ /** Liga de pago de MercadoPago. Nada cambia hasta que el usuario la abre y paga. */
473
+ export interface CheckoutLink {
474
+ init_point: string;
475
+ addonId: string;
476
+ }
477
+ export interface DomainSearchResult {
478
+ available: boolean;
479
+ domain: string;
480
+ tld: string;
481
+ /** Centavos MXN por año. */
482
+ price: number;
483
+ currency: "MXN";
484
+ }
485
+ export interface TldPrice {
486
+ tld: string;
487
+ /** Centavos MXN. */
488
+ price: number;
489
+ renewPrice: number;
490
+ transferPrice: number;
491
+ popular: boolean;
492
+ }
493
+ export interface DomainRegistrationCreated {
494
+ /** Liga de pago de MercadoPago; el registro arranca al pagar. */
495
+ initPoint: string;
496
+ registrationId: string;
497
+ }
498
+ export interface DomainRegistration {
499
+ id: string;
500
+ domainId: string | null;
501
+ domainName: string;
502
+ kind: "register" | "transfer";
503
+ status: string;
504
+ expiresAt: string | null;
505
+ priceCents: number;
506
+ renewalStatus: string;
507
+ renewalPriceCents: number | null;
508
+ nextChargeAt: string | null;
509
+ dnsImportStatus: string;
510
+ transferAuthCodeHint: string | null;
511
+ /** Candado de transferencia (`clientTransferProhibited`); null si aún no se ha leído de AWS. */
512
+ transferLock: boolean | null;
513
+ /** Mientras está quitado: cuándo se vuelve a poner solo. */
514
+ transferUnlockedUntil: string | null;
515
+ /** Desde cuándo puede cambiar de registrador (regla de 60 días de ICANN). */
516
+ transferEligibleAt: string;
517
+ lastError: string | null;
518
+ createdAt: string;
519
+ [k: string]: unknown;
520
+ }
521
+ export interface TransferRequirement {
522
+ texto: string;
523
+ ok: boolean | null;
524
+ ayuda?: string;
525
+ }
526
+ export interface TransferCheck {
527
+ domain: string;
528
+ /** Centavos MXN; incluye un año de renovación. */
529
+ price: number;
530
+ currency: "MXN";
531
+ requisitos: TransferRequirement[];
532
+ dns: {
533
+ found: unknown[];
534
+ nameservers?: string[];
535
+ warning?: string;
536
+ truncado?: boolean;
537
+ };
538
+ [k: string]: unknown;
539
+ }
540
+ export interface TransferDnsInventory {
541
+ records: unknown[];
542
+ status: string;
543
+ takenAt: string | null;
544
+ }
545
+ export interface RenewalLink {
546
+ init_point: string;
547
+ nextChargeAt: string;
548
+ }
549
+ export interface DomainMember {
550
+ id: string;
551
+ domainId: string;
552
+ email: string;
553
+ name: string;
554
+ role: "admin" | "agent";
555
+ createdAt: string;
556
+ /** Del perfil de su cuenta de MailMask, si lo llenó. */
557
+ displayName?: string | null;
558
+ avatarUrl?: string | null;
559
+ }
560
+ export interface DomainInvite {
561
+ token: string;
562
+ email: string;
563
+ name: string;
564
+ role: "admin" | "agent";
565
+ expiresAt: string;
566
+ inviteUrl: string;
567
+ }
568
+ export interface CannedReply {
569
+ id: string;
570
+ domainId: string;
571
+ title: string;
572
+ /** Markdown. */
573
+ body: string;
574
+ createdAt: string;
575
+ }
576
+ /** Perfil de la cuenta de MailMask (el usuario, no una máscara). */
577
+ export interface AccountProfile {
578
+ email: string;
579
+ displayName: string | null;
580
+ /** Ruta relativa al host de MailMask (`/api/avatar/...`), o null sin foto. */
581
+ avatarUrl: string | null;
582
+ }
583
+ /** Derechos y uso de UN dominio, dentro de `AccountMe.porDominio`. */
584
+ export interface AccountMeDomainUsage {
585
+ id: string;
586
+ domain: string;
587
+ /** Límites del dominio (sends, aliases, dominios, etc.), por plan y add-ons. */
588
+ derechos: Record<string, unknown>;
589
+ addons: Addon[];
590
+ uso: {
591
+ aliases: {
592
+ current: number;
593
+ limit: number;
594
+ };
595
+ rules: {
596
+ current: number;
597
+ limit: number;
598
+ };
599
+ sends: {
600
+ current: number;
601
+ limit: number;
602
+ };
603
+ forwards: {
604
+ current: number;
605
+ limit: number;
606
+ };
607
+ mailboxBytes: {
608
+ current: number;
609
+ limit: number;
610
+ };
611
+ };
612
+ }
613
+ /** Respuesta de `account.me()`: identidad de la cuenta y su uso, por dominio y total. */
614
+ export interface AccountMe extends AccountProfile {
615
+ isAdmin: boolean;
616
+ assistant: boolean;
617
+ domainsCount: number;
618
+ emailVerified: boolean;
619
+ forwards: {
620
+ current: number;
621
+ limit: number;
622
+ };
623
+ subscription: {
624
+ plan: string;
625
+ status: string;
626
+ currentPeriodEnd: string | null;
627
+ planLabel: string;
628
+ [k: string]: unknown;
629
+ };
630
+ porDominio: AccountMeDomainUsage[];
631
+ addons: Addon[];
632
+ planPriceCents: number | null;
633
+ addonCatalog: Record<string, {
634
+ price: number;
635
+ label: string;
636
+ }>;
637
+ addonsForSale: string[];
638
+ lastOrder: Order | null;
639
+ usage: {
640
+ domains: {
641
+ current: number;
642
+ limit: number | null;
643
+ };
644
+ aliasesPerDomain: unknown[];
645
+ rulesPerDomain: unknown[];
646
+ sendsPerDomain: unknown[];
647
+ };
648
+ referralSlug?: string | null;
649
+ referralStats: ReferralStats;
650
+ }
651
+ /** Respuesta de `account.export()`: todo el dato del usuario, listo para descargar. */
652
+ export interface AccountExport {
653
+ email: string;
654
+ exportedAt: string;
655
+ domains: {
656
+ domain: string;
657
+ domainId: string;
658
+ verified: boolean;
659
+ aliases: Alias[];
660
+ rules: Rule[];
661
+ logs: EmailLog[];
662
+ }[];
663
+ }
664
+ /** Respuesta de `domains.uploadImage()`. */
665
+ export interface UploadedEmailImage {
666
+ ok: boolean;
667
+ /** Efímera: se borra tras enviarse (o la barre el aseo diario si nunca se usó). */
668
+ url: string;
669
+ }
670
+ export type InboxStatus = "open" | "snoozed" | "closed";
671
+ export interface InboxConversation {
672
+ id: string;
673
+ domainId: string;
674
+ /** El contacto externo (en un hilo que inició el dominio, el destinatario). */
675
+ from: string;
676
+ /** La máscara del dominio por la que va el hilo (`ventas@tudominio.com`). */
677
+ to: string;
678
+ subject: string;
679
+ status: InboxStatus;
680
+ assignedTo?: string;
681
+ priority: "normal" | "urgent";
682
+ lastMessageAt: string;
683
+ messageCount: number;
684
+ tags: string[];
685
+ deletedAt?: string;
686
+ snoozedUntil?: string;
687
+ /** Para quien pregunta: hay mensajes que no ha visto. */
688
+ unread?: boolean;
689
+ /** Sólo en búsqueda: fragmento con la coincidencia. */
690
+ snippet?: string;
691
+ [k: string]: unknown;
692
+ }
693
+ export interface InboxListOptions {
694
+ /** `open`, `snoozed`, `closed`, `unread` (de quien pregunta) o `deleted` (papelera). */
695
+ status?: InboxStatus | "unread" | "deleted";
696
+ /** Dirección completa de la máscara (`ventas@tudominio.com`). */
697
+ to?: string;
698
+ assignedTo?: string;
699
+ /** Búsqueda en asunto, remitente y cuerpo. Con `q` no hay paginación (tope 50). */
700
+ q?: string;
701
+ /** Máx. 100. */
702
+ limit?: number;
703
+ cursor?: string;
704
+ }
705
+ export interface InboxPage {
706
+ items: InboxConversation[];
707
+ nextCursor: string | null;
708
+ /** Máscaras con conversaciones (sólo en la primera página). */
709
+ aliases?: string[];
710
+ mode: "list" | "search" | "search-degraded";
711
+ unreadCount?: number;
712
+ [k: string]: unknown;
713
+ }
714
+ export interface InboxAttachment {
715
+ index: number;
716
+ filename: string;
717
+ contentType: string;
718
+ size: number;
719
+ }
720
+ export interface InboxMessage {
721
+ id: string;
722
+ conversationId: string;
723
+ from: string;
724
+ /** Texto plano. */
725
+ body?: string;
726
+ html?: string;
727
+ direction: "inbound" | "outbound";
728
+ createdAt: string;
729
+ messageId?: string;
730
+ deliveryStatus?: "sent" | "delivered" | "bounced" | "complained";
731
+ attachments?: InboxAttachment[];
732
+ /** El original ya no está (retención de 90 días o pérdida): `body` puede venir del índice. */
733
+ bodyDegraded?: string;
734
+ }
735
+ export interface InboxNote {
736
+ id: string;
737
+ conversationId: string;
738
+ author: string;
739
+ body: string;
740
+ createdAt: string;
741
+ }
742
+ export interface InboxConversationDetail extends InboxConversation {
743
+ messages: InboxMessage[];
744
+ notes: InboxNote[];
745
+ totalMessages: number;
746
+ hasMore: boolean;
747
+ }
748
+ export interface InboxComposeInput {
749
+ /** Parte local (o dirección completa) de una máscara activa del dominio. */
750
+ fromAlias: string;
751
+ to: string;
752
+ subject: string;
753
+ markdown?: string;
754
+ html?: string;
755
+ body?: string;
756
+ cc?: string[];
757
+ bcc?: string[];
758
+ attachments?: AttachmentRef[];
759
+ }
760
+ export interface InboxReplyInput {
761
+ markdown?: string;
762
+ html?: string;
763
+ body?: string;
764
+ cc?: string[];
765
+ bcc?: string[];
766
+ /** Cita el último mensaje recibido (por omisión true; sólo con markdown). */
767
+ quote?: boolean;
768
+ attachments?: AttachmentRef[];
769
+ }
770
+ export interface InboxUpdateInput {
771
+ status?: InboxStatus;
772
+ /** ISO, futura y a menos de 90 días. Obligatoria con `status: "snoozed"`. */
773
+ snoozedUntil?: string;
774
+ tags?: string[];
775
+ priority?: "normal" | "urgent";
776
+ }
777
+ export interface Order {
778
+ id: string;
779
+ number: string;
780
+ date: string;
781
+ kind: string;
782
+ concept: string;
783
+ subject: string | null;
784
+ amountCents: number;
785
+ listPriceCents: number | null;
786
+ currency: string;
787
+ periodStart: string | null;
788
+ periodEnd: string | null;
789
+ failureReason: string | null;
790
+ note: string | null;
791
+ reference: string | null;
792
+ }
793
+ export interface OrdersPage {
794
+ orders: Order[];
795
+ nextCursor: string | null;
796
+ invoiceNote: string;
797
+ }
798
+ export interface ReferralStats {
799
+ slug?: string | null;
800
+ referrals: unknown[];
801
+ [k: string]: unknown;
802
+ }