@easybits.cloud/mailmask 0.4.3 → 0.4.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -76,6 +76,8 @@ var MailMask = class {
76
76
  this.signature = new SignatureResource(req);
77
77
  this.canned = new CannedResource(req);
78
78
  this.account = new AccountResource(req);
79
+ this.inbox = new InboxResource(req, (path) => requestRaw(this.baseUrl, this.apiKey, path, doFetch));
80
+ this.referrals = new ReferralsResource(req);
79
81
  }
80
82
  };
81
83
  var DomainsResource = class {
@@ -104,6 +106,19 @@ var DomainsResource = class {
104
106
  dnsSetup(id, opts) {
105
107
  return this.req(`/api/domains/${id}/dns-setup${opts?.live ? "?live=1" : ""}`);
106
108
  }
109
+ /** Logo de la firma (PNG, JPG o WebP; máx. 500 KB). Se ve en todo correo en markdown. */
110
+ setLogo(id, file, filename = "logo") {
111
+ const form = new FormData();
112
+ form.append("file", file, filename);
113
+ return this.req(`/api/domains/${id}/logo`, { method: "POST", body: form });
114
+ }
115
+ /** Logo desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
116
+ setLogoFromUrl(id, url) {
117
+ return this.req(`/api/domains/${id}/logo`, { method: "POST", body: JSON.stringify({ fromUrl: url }) });
118
+ }
119
+ removeLogo(id) {
120
+ return this.req(`/api/domains/${id}/logo`, { method: "DELETE" });
121
+ }
107
122
  };
108
123
  var DnsResource = class {
109
124
  constructor(req) {
@@ -224,6 +239,10 @@ var AttachmentsResource = class {
224
239
  form.append("file", blob, input.filename);
225
240
  return this.req(`/api/domains/${domainId}/attachments`, { method: "POST", body: form });
226
241
  }
242
+ /** Desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
243
+ uploadFromUrl(domainId, url, filename) {
244
+ return this.req(`/api/domains/${domainId}/attachments`, { method: "POST", body: JSON.stringify({ fromUrl: url, filename }) });
245
+ }
227
246
  };
228
247
  var SuppressionsResource = class {
229
248
  constructor(req) {
@@ -306,7 +325,19 @@ var BillingResource = class {
306
325
  * El usuario la abre y paga; hasta entonces no cambia nada.
307
326
  */
308
327
  checkout(domainId, kind = "domain", opts) {
309
- return this.req("/api/addons/checkout", { method: "POST", body: JSON.stringify({ kind, domainId, payerEmail: opts?.payerEmail }) });
328
+ return this.req("/api/addons/checkout", { method: "POST", body: JSON.stringify({ kind, domainId, payerEmail: opts?.payerEmail, period: opts?.period }) });
329
+ }
330
+ /** Cancela la suscripción de un add-on; el cupo sigue hasta el fin del periodo pagado. */
331
+ cancelAddon(addonId) {
332
+ return this.req(`/api/addons/${addonId}/cancel`, { method: "POST" });
333
+ }
334
+ /** Historial de cobros, cortesías y cancelaciones (más reciente primero). */
335
+ orders(opts) {
336
+ const qs = new URLSearchParams();
337
+ if (opts?.limit) qs.set("limit", String(opts.limit));
338
+ if (opts?.before) qs.set("before", opts.before);
339
+ const q = qs.toString();
340
+ return this.req(`/api/billing/orders${q ? `?${q}` : ""}`);
310
341
  }
311
342
  };
312
343
  var RegistrationsResource = class {
@@ -334,6 +365,10 @@ var RegistrationsResource = class {
334
365
  renewal(regId, opts) {
335
366
  return this.req(`/api/domains/registrations/${regId}/renewal`, { method: "POST", body: JSON.stringify({ payerEmail: opts?.payerEmail }) });
336
367
  }
368
+ /** Deja de cobrar la renovación anual. El dominio sigue vigente hasta su vencimiento. */
369
+ cancelRenewal(regId) {
370
+ return this.req(`/api/domains/registrations/${regId}/renewal/cancel`, { method: "POST" });
371
+ }
337
372
  };
338
373
  var TransfersResource = class {
339
374
  constructor(req) {
@@ -426,6 +461,77 @@ var AccountResource = class {
426
461
  return this.req("/api/profile/avatar", { method: "DELETE" });
427
462
  }
428
463
  };
464
+ var InboxResource = class {
465
+ constructor(req, raw) {
466
+ this.req = req;
467
+ this.raw = raw;
468
+ }
469
+ list(domainId, opts) {
470
+ const qs = new URLSearchParams({ domainId });
471
+ for (const [k, v] of Object.entries(opts ?? {})) if (v !== void 0 && v !== "") qs.set(k, String(v));
472
+ return this.req(`/api/bandeja/conversations?${qs}`);
473
+ }
474
+ /** Conversación con sus mensajes (los 30 más recientes, o anteriores a `before`). Abrirla la marca leída. */
475
+ get(domainId, conversationId, opts) {
476
+ const qs = new URLSearchParams({ domainId });
477
+ if (opts?.before) qs.set("before", opts.before);
478
+ return this.req(`/api/bandeja/conversations/${conversationId}?${qs}`);
479
+ }
480
+ /** Un correo nuevo desde una máscara: abre un hilo. Gasta cuota de envío (dominio activado). */
481
+ compose(domainId, input) {
482
+ return this.req("/api/bandeja/conversations", { method: "POST", body: JSON.stringify({ ...input, domainId }) });
483
+ }
484
+ /** Responde en el hilo desde la máscara del hilo. No gasta cuota de envío. */
485
+ reply(domainId, conversationId, input) {
486
+ return this.req(`/api/bandeja/conversations/${conversationId}/reply`, { method: "POST", body: JSON.stringify({ ...input, domainId }) });
487
+ }
488
+ update(domainId, conversationId, input) {
489
+ return this.req(`/api/bandeja/conversations/${conversationId}`, { method: "PATCH", body: JSON.stringify({ ...input, domainId }) });
490
+ }
491
+ markRead(domainId, conversationId) {
492
+ return this.req(`/api/bandeja/conversations/${conversationId}/read`, { method: "POST", body: JSON.stringify({ domainId }) });
493
+ }
494
+ /** Sin `assignedTo` la deja sin asignar. */
495
+ assign(domainId, conversationId, assignedTo) {
496
+ return this.req(`/api/bandeja/conversations/${conversationId}/assign`, { method: "POST", body: JSON.stringify({ domainId, assignedTo }) });
497
+ }
498
+ /** Nota interna: la ve el equipo, nunca el contacto. */
499
+ addNote(domainId, conversationId, body) {
500
+ return this.req(`/api/bandeja/conversations/${conversationId}/note`, { method: "POST", body: JSON.stringify({ domainId, body }) });
501
+ }
502
+ /** A la papelera (se puede restaurar). Máx. 200 por llamada. */
503
+ delete(domainId, conversationIds) {
504
+ return this.req("/api/bandeja/conversations/bulk-delete", { method: "POST", body: JSON.stringify({ domainId, ids: conversationIds }) });
505
+ }
506
+ restore(domainId, conversationId) {
507
+ return this.req(`/api/bandeja/conversations/${conversationId}/restore`, { method: "POST", body: JSON.stringify({ domainId }) });
508
+ }
509
+ metrics(domainId, opts) {
510
+ const qs = new URLSearchParams({ domainId });
511
+ if (opts?.days) qs.set("days", String(opts.days));
512
+ return this.req(`/api/bandeja/metrics?${qs}`);
513
+ }
514
+ /** Bytes de un adjunto de un mensaje (id del mensaje e índice de `attachments`). */
515
+ attachment(domainId, conversationId, messageId, index) {
516
+ return this.raw(`/api/bandeja/conversations/${conversationId}/attachments/${messageId}/${index}?domainId=${encodeURIComponent(domainId)}`);
517
+ }
518
+ };
519
+ var ReferralsResource = class {
520
+ constructor(req) {
521
+ this.req = req;
522
+ }
523
+ get() {
524
+ return this.req("/api/referrals");
525
+ }
526
+ /** 3-30 caracteres: minúsculas, números y guiones. */
527
+ setSlug(slug) {
528
+ return this.req("/api/referrals/slug", { method: "PUT", body: JSON.stringify({ slug }) });
529
+ }
530
+ /** Nombre que ven los invitados (2-40 caracteres). */
531
+ setName(name) {
532
+ return this.req("/api/referrals/name", { method: "PUT", body: JSON.stringify({ name }) });
533
+ }
534
+ };
429
535
 
430
536
  // src/verify.ts
431
537
  function hex(buf) {
package/dist/index.d.cts CHANGED
@@ -521,6 +521,139 @@ interface AccountProfile {
521
521
  /** Ruta relativa al host de MailMask (`/api/avatar/...`), o null sin foto. */
522
522
  avatarUrl: string | null;
523
523
  }
524
+ type InboxStatus = "open" | "snoozed" | "closed";
525
+ interface InboxConversation {
526
+ id: string;
527
+ domainId: string;
528
+ /** El contacto externo (en un hilo que inició el dominio, el destinatario). */
529
+ from: string;
530
+ /** La máscara del dominio por la que va el hilo (`ventas@tudominio.com`). */
531
+ to: string;
532
+ subject: string;
533
+ status: InboxStatus;
534
+ assignedTo?: string;
535
+ priority: "normal" | "urgent";
536
+ lastMessageAt: string;
537
+ messageCount: number;
538
+ tags: string[];
539
+ deletedAt?: string;
540
+ snoozedUntil?: string;
541
+ /** Para quien pregunta: hay mensajes que no ha visto. */
542
+ unread?: boolean;
543
+ /** Sólo en búsqueda: fragmento con la coincidencia. */
544
+ snippet?: string;
545
+ [k: string]: unknown;
546
+ }
547
+ interface InboxListOptions {
548
+ /** `open`, `snoozed`, `closed`, `unread` (de quien pregunta) o `deleted` (papelera). */
549
+ status?: InboxStatus | "unread" | "deleted";
550
+ /** Dirección completa de la máscara (`ventas@tudominio.com`). */
551
+ to?: string;
552
+ assignedTo?: string;
553
+ /** Búsqueda en asunto, remitente y cuerpo. Con `q` no hay paginación (tope 50). */
554
+ q?: string;
555
+ /** Máx. 100. */
556
+ limit?: number;
557
+ cursor?: string;
558
+ }
559
+ interface InboxPage {
560
+ items: InboxConversation[];
561
+ nextCursor: string | null;
562
+ /** Máscaras con conversaciones (sólo en la primera página). */
563
+ aliases?: string[];
564
+ mode: "list" | "search" | "search-degraded";
565
+ unreadCount?: number;
566
+ [k: string]: unknown;
567
+ }
568
+ interface InboxAttachment {
569
+ index: number;
570
+ filename: string;
571
+ contentType: string;
572
+ size: number;
573
+ }
574
+ interface InboxMessage {
575
+ id: string;
576
+ conversationId: string;
577
+ from: string;
578
+ /** Texto plano. */
579
+ body?: string;
580
+ html?: string;
581
+ direction: "inbound" | "outbound";
582
+ createdAt: string;
583
+ messageId?: string;
584
+ deliveryStatus?: "sent" | "delivered" | "bounced" | "complained";
585
+ attachments?: InboxAttachment[];
586
+ /** El original ya no está (retención de 90 días o pérdida): `body` puede venir del índice. */
587
+ bodyDegraded?: string;
588
+ }
589
+ interface InboxNote {
590
+ id: string;
591
+ conversationId: string;
592
+ author: string;
593
+ body: string;
594
+ createdAt: string;
595
+ }
596
+ interface InboxConversationDetail extends InboxConversation {
597
+ messages: InboxMessage[];
598
+ notes: InboxNote[];
599
+ totalMessages: number;
600
+ hasMore: boolean;
601
+ }
602
+ interface InboxComposeInput {
603
+ /** Parte local (o dirección completa) de una máscara activa del dominio. */
604
+ fromAlias: string;
605
+ to: string;
606
+ subject: string;
607
+ markdown?: string;
608
+ html?: string;
609
+ body?: string;
610
+ cc?: string[];
611
+ bcc?: string[];
612
+ attachments?: AttachmentRef[];
613
+ }
614
+ interface InboxReplyInput {
615
+ markdown?: string;
616
+ html?: string;
617
+ body?: string;
618
+ cc?: string[];
619
+ bcc?: string[];
620
+ /** Cita el último mensaje recibido (por omisión true; sólo con markdown). */
621
+ quote?: boolean;
622
+ attachments?: AttachmentRef[];
623
+ }
624
+ interface InboxUpdateInput {
625
+ status?: InboxStatus;
626
+ /** ISO, futura y a menos de 90 días. Obligatoria con `status: "snoozed"`. */
627
+ snoozedUntil?: string;
628
+ tags?: string[];
629
+ priority?: "normal" | "urgent";
630
+ }
631
+ interface Order {
632
+ id: string;
633
+ number: string;
634
+ date: string;
635
+ kind: string;
636
+ concept: string;
637
+ subject: string | null;
638
+ amountCents: number;
639
+ listPriceCents: number | null;
640
+ currency: string;
641
+ periodStart: string | null;
642
+ periodEnd: string | null;
643
+ failureReason: string | null;
644
+ note: string | null;
645
+ reference: string | null;
646
+ }
647
+ interface OrdersPage {
648
+ orders: Order[];
649
+ nextCursor: string | null;
650
+ invoiceNote: string;
651
+ }
652
+ interface ReferralStats {
653
+ slug?: string | null;
654
+ referrals: unknown[];
655
+ [k: string]: unknown;
656
+ }
524
657
 
525
658
  declare class MailMaskError extends Error {
526
659
  status: number;
@@ -547,6 +680,8 @@ declare class MailMask {
547
680
  signature: SignatureResource;
548
681
  canned: CannedResource;
549
682
  account: AccountResource;
683
+ inbox: InboxResource;
684
+ referrals: ReferralsResource;
550
685
  constructor(config: MailMaskConfig);
551
686
  }
552
687
  type Req = <T>(path: string, opts?: RequestInit) => Promise<T>;
@@ -565,6 +700,19 @@ declare class DomainsResource {
565
700
  dnsSetup(id: string, opts?: {
566
701
  live?: boolean;
567
702
  }): Promise<DnsSetup>;
703
+ /** Logo de la firma (PNG, JPG o WebP; máx. 500 KB). Se ve en todo correo en markdown. */
704
+ setLogo(id: string, file: Blob, filename?: string): Promise<{
705
+ ok: boolean;
706
+ logoUrl: string;
707
+ }>;
708
+ /** Logo desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
709
+ setLogoFromUrl(id: string, url: string): Promise<{
710
+ ok: boolean;
711
+ logoUrl: string;
712
+ }>;
713
+ removeLogo(id: string): Promise<{
714
+ ok: boolean;
715
+ }>;
568
716
  }
569
717
  declare class DnsResource {
570
718
  private req;
@@ -645,6 +793,8 @@ declare class AttachmentsResource {
645
793
  constructor(req: Req);
646
794
  /** Máx. 5 MB. Ejecutables bloqueados (415). La llave vale hasta que se envía. */
647
795
  upload(domainId: string, input: UploadAttachmentInput): Promise<UploadedAttachment>;
796
+ /** Desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
797
+ uploadFromUrl(domainId: string, url: string, filename?: string): Promise<UploadedAttachment>;
648
798
  }
649
799
  declare class SuppressionsResource {
650
800
  private req;
@@ -702,7 +852,18 @@ declare class BillingResource {
702
852
  */
703
853
  checkout(domainId: string, kind?: "domain" | "storage50" | "sends100", opts?: {
704
854
  payerEmail?: string;
855
+ period?: "monthly" | "annual";
705
856
  }): Promise<CheckoutLink>;
857
+ /** Cancela la suscripción de un add-on; el cupo sigue hasta el fin del periodo pagado. */
858
+ cancelAddon(addonId: string): Promise<{
859
+ ok: boolean;
860
+ activeUntil: string | null;
861
+ }>;
862
+ /** Historial de cobros, cortesías y cancelaciones (más reciente primero). */
863
+ orders(opts?: {
864
+ limit?: number;
865
+ before?: string;
866
+ }): Promise<OrdersPage>;
706
867
  }
707
868
  declare class RegistrationsResource {
708
869
  private req;
@@ -721,6 +882,11 @@ declare class RegistrationsResource {
721
882
  renewal(regId: string, opts?: {
722
883
  payerEmail?: string;
723
884
  }): Promise<RenewalLink>;
885
+ /** Deja de cobrar la renovación anual. El dominio sigue vigente hasta su vencimiento. */
886
+ cancelRenewal(regId: string): Promise<{
887
+ ok: boolean;
888
+ aviso: string;
889
+ }>;
724
890
  }
725
891
  declare class TransfersResource {
726
892
  private req;
@@ -810,6 +976,67 @@ declare class AccountResource {
810
976
  ok: boolean;
811
977
  }>;
812
978
  }
979
+ /**
980
+ * La Bandeja: conversaciones del dominio. Todo pasa por los mismos permisos que la app
981
+ * (dueño, admin o agente invitado) y los mismos topes de envío.
982
+ */
983
+ declare class InboxResource {
984
+ private req;
985
+ private raw;
986
+ constructor(req: Req, raw: (path: string) => Promise<Response>);
987
+ list(domainId: string, opts?: InboxListOptions): Promise<InboxPage>;
988
+ /** Conversación con sus mensajes (los 30 más recientes, o anteriores a `before`). Abrirla la marca leída. */
989
+ get(domainId: string, conversationId: string, opts?: {
990
+ before?: string;
991
+ }): Promise<InboxConversationDetail>;
992
+ /** Un correo nuevo desde una máscara: abre un hilo. Gasta cuota de envío (dominio activado). */
993
+ compose(domainId: string, input: InboxComposeInput): Promise<{
994
+ ok: boolean;
995
+ conversationId: string;
996
+ messageId: string;
997
+ }>;
998
+ /** Responde en el hilo desde la máscara del hilo. No gasta cuota de envío. */
999
+ reply(domainId: string, conversationId: string, input: InboxReplyInput): Promise<{
1000
+ ok: boolean;
1001
+ messageId: string;
1002
+ }>;
1003
+ update(domainId: string, conversationId: string, input: InboxUpdateInput): Promise<InboxConversation>;
1004
+ markRead(domainId: string, conversationId: string): Promise<{
1005
+ ok: boolean;
1006
+ unreadCount: number;
1007
+ }>;
1008
+ /** Sin `assignedTo` la deja sin asignar. */
1009
+ assign(domainId: string, conversationId: string, assignedTo?: string): Promise<InboxConversation>;
1010
+ /** Nota interna: la ve el equipo, nunca el contacto. */
1011
+ addNote(domainId: string, conversationId: string, body: string): Promise<InboxNote>;
1012
+ /** A la papelera (se puede restaurar). Máx. 200 por llamada. */
1013
+ delete(domainId: string, conversationIds: string[]): Promise<{
1014
+ ok: boolean;
1015
+ deleted: number;
1016
+ }>;
1017
+ restore(domainId: string, conversationId: string): Promise<{
1018
+ ok: boolean;
1019
+ }>;
1020
+ metrics(domainId: string, opts?: {
1021
+ days?: number;
1022
+ }): Promise<Record<string, unknown>>;
1023
+ /** Bytes de un adjunto de un mensaje (id del mensaje e índice de `attachments`). */
1024
+ attachment(domainId: string, conversationId: string, messageId: string, index: number): Promise<Response>;
1025
+ }
1026
+ declare class ReferralsResource {
1027
+ private req;
1028
+ constructor(req: Req);
1029
+ get(): Promise<ReferralStats>;
1030
+ /** 3-30 caracteres: minúsculas, números y guiones. */
1031
+ setSlug(slug: string): Promise<{
1032
+ ok: boolean;
1033
+ slug: string;
1034
+ }>;
1035
+ /** Nombre que ven los invitados (2-40 caracteres). */
1036
+ setName(name: string): Promise<{
1037
+ ok: boolean;
1038
+ }>;
1039
+ }
813
1040
 
814
1041
  interface WebhookSignatureHeaders {
815
1042
  /** Header `X-MailMask-Signature`, con forma `sha256=<hex>`. */
@@ -824,4 +1051,4 @@ interface WebhookSignatureHeaders {
824
1051
  */
825
1052
  declare function verifyWebhookSignature(secret: string, headers: WebhookSignatureHeaders, rawBody: string, toleranceMs?: number): Promise<boolean>;
826
1053
 
827
- export { type AccountProfile, type Addon, type AddonsResponse, type Alias, type AliasCreated, type ApiKey, type AttachmentRef, type BillingStatus, type BulkJob, type BulkJobCreated, type BulkSendInput, type CannedReply, type CheckoutLink, type CreateAliasInput, type CreateRuleInput, type CreateWebhookInput, type DnsChangeResult, type DnsDelegation, type DnsImportResult, type DnsListResponse, type DnsPreset, type DnsRRSet, type DnsRRSetAnotado, type DnsRecord, type DnsRecordType, type DnsSetup, type DnsSetupRecord, type DnsZoneCreated, type DnsZoneState, type Domain, type DomainCreated, type DomainInvite, type DomainMember, type DomainRegistration, type DomainRegistrationCreated, type DomainSearchResult, type DomainVerification, type EmailLog, MailMask, type MailMaskConfig, MailMaskError, type MailboxCreated, type RenewalLink, type Rule, type RuleAction, type RuleField, type RuleMatch, type SendEmailInput, type SendOptions, type SmtpCredential, type SmtpCredentialCreated, type Suppression, type TldPrice, type TransferCheck, type TransferDnsInventory, type TransferRequirement, type UpdateAliasInput, type UpdateRuleInput, type UpdateWebhookInput, type UploadAttachmentInput, type UploadedAttachment, type Webhook, type WebhookCreated, type WebhookDelivery, type WebhookEvent, type WebhookPayload, type WebhookSignatureHeaders, verifyWebhookSignature };
1054
+ export { type AccountProfile, type Addon, type AddonsResponse, type Alias, type AliasCreated, type ApiKey, type AttachmentRef, type BillingStatus, type BulkJob, type BulkJobCreated, type BulkSendInput, type CannedReply, type CheckoutLink, type CreateAliasInput, type CreateRuleInput, type CreateWebhookInput, type DnsChangeResult, type DnsDelegation, type DnsImportResult, type DnsListResponse, type DnsPreset, type DnsRRSet, type DnsRRSetAnotado, type DnsRecord, type DnsRecordType, type DnsSetup, type DnsSetupRecord, type DnsZoneCreated, type DnsZoneState, type Domain, type DomainCreated, type DomainInvite, type DomainMember, type DomainRegistration, type DomainRegistrationCreated, type DomainSearchResult, type DomainVerification, type EmailLog, type InboxAttachment, type InboxComposeInput, type InboxConversation, type InboxConversationDetail, type InboxListOptions, type InboxMessage, type InboxNote, type InboxPage, type InboxReplyInput, type InboxStatus, type InboxUpdateInput, MailMask, type MailMaskConfig, MailMaskError, type MailboxCreated, type Order, type OrdersPage, type ReferralStats, type RenewalLink, type Rule, type RuleAction, type RuleField, type RuleMatch, type SendEmailInput, type SendOptions, type SmtpCredential, type SmtpCredentialCreated, type Suppression, type TldPrice, type TransferCheck, type TransferDnsInventory, type TransferRequirement, type UpdateAliasInput, type UpdateRuleInput, type UpdateWebhookInput, type UploadAttachmentInput, type UploadedAttachment, type Webhook, type WebhookCreated, type WebhookDelivery, type WebhookEvent, type WebhookPayload, type WebhookSignatureHeaders, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -521,6 +521,139 @@ interface AccountProfile {
521
521
  /** Ruta relativa al host de MailMask (`/api/avatar/...`), o null sin foto. */
522
522
  avatarUrl: string | null;
523
523
  }
524
+ type InboxStatus = "open" | "snoozed" | "closed";
525
+ interface InboxConversation {
526
+ id: string;
527
+ domainId: string;
528
+ /** El contacto externo (en un hilo que inició el dominio, el destinatario). */
529
+ from: string;
530
+ /** La máscara del dominio por la que va el hilo (`ventas@tudominio.com`). */
531
+ to: string;
532
+ subject: string;
533
+ status: InboxStatus;
534
+ assignedTo?: string;
535
+ priority: "normal" | "urgent";
536
+ lastMessageAt: string;
537
+ messageCount: number;
538
+ tags: string[];
539
+ deletedAt?: string;
540
+ snoozedUntil?: string;
541
+ /** Para quien pregunta: hay mensajes que no ha visto. */
542
+ unread?: boolean;
543
+ /** Sólo en búsqueda: fragmento con la coincidencia. */
544
+ snippet?: string;
545
+ [k: string]: unknown;
546
+ }
547
+ interface InboxListOptions {
548
+ /** `open`, `snoozed`, `closed`, `unread` (de quien pregunta) o `deleted` (papelera). */
549
+ status?: InboxStatus | "unread" | "deleted";
550
+ /** Dirección completa de la máscara (`ventas@tudominio.com`). */
551
+ to?: string;
552
+ assignedTo?: string;
553
+ /** Búsqueda en asunto, remitente y cuerpo. Con `q` no hay paginación (tope 50). */
554
+ q?: string;
555
+ /** Máx. 100. */
556
+ limit?: number;
557
+ cursor?: string;
558
+ }
559
+ interface InboxPage {
560
+ items: InboxConversation[];
561
+ nextCursor: string | null;
562
+ /** Máscaras con conversaciones (sólo en la primera página). */
563
+ aliases?: string[];
564
+ mode: "list" | "search" | "search-degraded";
565
+ unreadCount?: number;
566
+ [k: string]: unknown;
567
+ }
568
+ interface InboxAttachment {
569
+ index: number;
570
+ filename: string;
571
+ contentType: string;
572
+ size: number;
573
+ }
574
+ interface InboxMessage {
575
+ id: string;
576
+ conversationId: string;
577
+ from: string;
578
+ /** Texto plano. */
579
+ body?: string;
580
+ html?: string;
581
+ direction: "inbound" | "outbound";
582
+ createdAt: string;
583
+ messageId?: string;
584
+ deliveryStatus?: "sent" | "delivered" | "bounced" | "complained";
585
+ attachments?: InboxAttachment[];
586
+ /** El original ya no está (retención de 90 días o pérdida): `body` puede venir del índice. */
587
+ bodyDegraded?: string;
588
+ }
589
+ interface InboxNote {
590
+ id: string;
591
+ conversationId: string;
592
+ author: string;
593
+ body: string;
594
+ createdAt: string;
595
+ }
596
+ interface InboxConversationDetail extends InboxConversation {
597
+ messages: InboxMessage[];
598
+ notes: InboxNote[];
599
+ totalMessages: number;
600
+ hasMore: boolean;
601
+ }
602
+ interface InboxComposeInput {
603
+ /** Parte local (o dirección completa) de una máscara activa del dominio. */
604
+ fromAlias: string;
605
+ to: string;
606
+ subject: string;
607
+ markdown?: string;
608
+ html?: string;
609
+ body?: string;
610
+ cc?: string[];
611
+ bcc?: string[];
612
+ attachments?: AttachmentRef[];
613
+ }
614
+ interface InboxReplyInput {
615
+ markdown?: string;
616
+ html?: string;
617
+ body?: string;
618
+ cc?: string[];
619
+ bcc?: string[];
620
+ /** Cita el último mensaje recibido (por omisión true; sólo con markdown). */
621
+ quote?: boolean;
622
+ attachments?: AttachmentRef[];
623
+ }
624
+ interface InboxUpdateInput {
625
+ status?: InboxStatus;
626
+ /** ISO, futura y a menos de 90 días. Obligatoria con `status: "snoozed"`. */
627
+ snoozedUntil?: string;
628
+ tags?: string[];
629
+ priority?: "normal" | "urgent";
630
+ }
631
+ interface Order {
632
+ id: string;
633
+ number: string;
634
+ date: string;
635
+ kind: string;
636
+ concept: string;
637
+ subject: string | null;
638
+ amountCents: number;
639
+ listPriceCents: number | null;
640
+ currency: string;
641
+ periodStart: string | null;
642
+ periodEnd: string | null;
643
+ failureReason: string | null;
644
+ note: string | null;
645
+ reference: string | null;
646
+ }
647
+ interface OrdersPage {
648
+ orders: Order[];
649
+ nextCursor: string | null;
650
+ invoiceNote: string;
651
+ }
652
+ interface ReferralStats {
653
+ slug?: string | null;
654
+ referrals: unknown[];
655
+ [k: string]: unknown;
656
+ }
524
657
 
525
658
  declare class MailMaskError extends Error {
526
659
  status: number;
@@ -547,6 +680,8 @@ declare class MailMask {
547
680
  signature: SignatureResource;
548
681
  canned: CannedResource;
549
682
  account: AccountResource;
683
+ inbox: InboxResource;
684
+ referrals: ReferralsResource;
550
685
  constructor(config: MailMaskConfig);
551
686
  }
552
687
  type Req = <T>(path: string, opts?: RequestInit) => Promise<T>;
@@ -565,6 +700,19 @@ declare class DomainsResource {
565
700
  dnsSetup(id: string, opts?: {
566
701
  live?: boolean;
567
702
  }): Promise<DnsSetup>;
703
+ /** Logo de la firma (PNG, JPG o WebP; máx. 500 KB). Se ve en todo correo en markdown. */
704
+ setLogo(id: string, file: Blob, filename?: string): Promise<{
705
+ ok: boolean;
706
+ logoUrl: string;
707
+ }>;
708
+ /** Logo desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
709
+ setLogoFromUrl(id: string, url: string): Promise<{
710
+ ok: boolean;
711
+ logoUrl: string;
712
+ }>;
713
+ removeLogo(id: string): Promise<{
714
+ ok: boolean;
715
+ }>;
568
716
  }
569
717
  declare class DnsResource {
570
718
  private req;
@@ -645,6 +793,8 @@ declare class AttachmentsResource {
645
793
  constructor(req: Req);
646
794
  /** Máx. 5 MB. Ejecutables bloqueados (415). La llave vale hasta que se envía. */
647
795
  upload(domainId: string, input: UploadAttachmentInput): Promise<UploadedAttachment>;
796
+ /** Desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
797
+ uploadFromUrl(domainId: string, url: string, filename?: string): Promise<UploadedAttachment>;
648
798
  }
649
799
  declare class SuppressionsResource {
650
800
  private req;
@@ -702,7 +852,18 @@ declare class BillingResource {
702
852
  */
703
853
  checkout(domainId: string, kind?: "domain" | "storage50" | "sends100", opts?: {
704
854
  payerEmail?: string;
855
+ period?: "monthly" | "annual";
705
856
  }): Promise<CheckoutLink>;
857
+ /** Cancela la suscripción de un add-on; el cupo sigue hasta el fin del periodo pagado. */
858
+ cancelAddon(addonId: string): Promise<{
859
+ ok: boolean;
860
+ activeUntil: string | null;
861
+ }>;
862
+ /** Historial de cobros, cortesías y cancelaciones (más reciente primero). */
863
+ orders(opts?: {
864
+ limit?: number;
865
+ before?: string;
866
+ }): Promise<OrdersPage>;
706
867
  }
707
868
  declare class RegistrationsResource {
708
869
  private req;
@@ -721,6 +882,11 @@ declare class RegistrationsResource {
721
882
  renewal(regId: string, opts?: {
722
883
  payerEmail?: string;
723
884
  }): Promise<RenewalLink>;
885
+ /** Deja de cobrar la renovación anual. El dominio sigue vigente hasta su vencimiento. */
886
+ cancelRenewal(regId: string): Promise<{
887
+ ok: boolean;
888
+ aviso: string;
889
+ }>;
724
890
  }
725
891
  declare class TransfersResource {
726
892
  private req;
@@ -810,6 +976,67 @@ declare class AccountResource {
810
976
  ok: boolean;
811
977
  }>;
812
978
  }
979
+ /**
980
+ * La Bandeja: conversaciones del dominio. Todo pasa por los mismos permisos que la app
981
+ * (dueño, admin o agente invitado) y los mismos topes de envío.
982
+ */
983
+ declare class InboxResource {
984
+ private req;
985
+ private raw;
986
+ constructor(req: Req, raw: (path: string) => Promise<Response>);
987
+ list(domainId: string, opts?: InboxListOptions): Promise<InboxPage>;
988
+ /** Conversación con sus mensajes (los 30 más recientes, o anteriores a `before`). Abrirla la marca leída. */
989
+ get(domainId: string, conversationId: string, opts?: {
990
+ before?: string;
991
+ }): Promise<InboxConversationDetail>;
992
+ /** Un correo nuevo desde una máscara: abre un hilo. Gasta cuota de envío (dominio activado). */
993
+ compose(domainId: string, input: InboxComposeInput): Promise<{
994
+ ok: boolean;
995
+ conversationId: string;
996
+ messageId: string;
997
+ }>;
998
+ /** Responde en el hilo desde la máscara del hilo. No gasta cuota de envío. */
999
+ reply(domainId: string, conversationId: string, input: InboxReplyInput): Promise<{
1000
+ ok: boolean;
1001
+ messageId: string;
1002
+ }>;
1003
+ update(domainId: string, conversationId: string, input: InboxUpdateInput): Promise<InboxConversation>;
1004
+ markRead(domainId: string, conversationId: string): Promise<{
1005
+ ok: boolean;
1006
+ unreadCount: number;
1007
+ }>;
1008
+ /** Sin `assignedTo` la deja sin asignar. */
1009
+ assign(domainId: string, conversationId: string, assignedTo?: string): Promise<InboxConversation>;
1010
+ /** Nota interna: la ve el equipo, nunca el contacto. */
1011
+ addNote(domainId: string, conversationId: string, body: string): Promise<InboxNote>;
1012
+ /** A la papelera (se puede restaurar). Máx. 200 por llamada. */
1013
+ delete(domainId: string, conversationIds: string[]): Promise<{
1014
+ ok: boolean;
1015
+ deleted: number;
1016
+ }>;
1017
+ restore(domainId: string, conversationId: string): Promise<{
1018
+ ok: boolean;
1019
+ }>;
1020
+ metrics(domainId: string, opts?: {
1021
+ days?: number;
1022
+ }): Promise<Record<string, unknown>>;
1023
+ /** Bytes de un adjunto de un mensaje (id del mensaje e índice de `attachments`). */
1024
+ attachment(domainId: string, conversationId: string, messageId: string, index: number): Promise<Response>;
1025
+ }
1026
+ declare class ReferralsResource {
1027
+ private req;
1028
+ constructor(req: Req);
1029
+ get(): Promise<ReferralStats>;
1030
+ /** 3-30 caracteres: minúsculas, números y guiones. */
1031
+ setSlug(slug: string): Promise<{
1032
+ ok: boolean;
1033
+ slug: string;
1034
+ }>;
1035
+ /** Nombre que ven los invitados (2-40 caracteres). */
1036
+ setName(name: string): Promise<{
1037
+ ok: boolean;
1038
+ }>;
1039
+ }
813
1040
 
814
1041
  interface WebhookSignatureHeaders {
815
1042
  /** Header `X-MailMask-Signature`, con forma `sha256=<hex>`. */
@@ -824,4 +1051,4 @@ interface WebhookSignatureHeaders {
824
1051
  */
825
1052
  declare function verifyWebhookSignature(secret: string, headers: WebhookSignatureHeaders, rawBody: string, toleranceMs?: number): Promise<boolean>;
826
1053
 
827
- export { type AccountProfile, type Addon, type AddonsResponse, type Alias, type AliasCreated, type ApiKey, type AttachmentRef, type BillingStatus, type BulkJob, type BulkJobCreated, type BulkSendInput, type CannedReply, type CheckoutLink, type CreateAliasInput, type CreateRuleInput, type CreateWebhookInput, type DnsChangeResult, type DnsDelegation, type DnsImportResult, type DnsListResponse, type DnsPreset, type DnsRRSet, type DnsRRSetAnotado, type DnsRecord, type DnsRecordType, type DnsSetup, type DnsSetupRecord, type DnsZoneCreated, type DnsZoneState, type Domain, type DomainCreated, type DomainInvite, type DomainMember, type DomainRegistration, type DomainRegistrationCreated, type DomainSearchResult, type DomainVerification, type EmailLog, MailMask, type MailMaskConfig, MailMaskError, type MailboxCreated, type RenewalLink, type Rule, type RuleAction, type RuleField, type RuleMatch, type SendEmailInput, type SendOptions, type SmtpCredential, type SmtpCredentialCreated, type Suppression, type TldPrice, type TransferCheck, type TransferDnsInventory, type TransferRequirement, type UpdateAliasInput, type UpdateRuleInput, type UpdateWebhookInput, type UploadAttachmentInput, type UploadedAttachment, type Webhook, type WebhookCreated, type WebhookDelivery, type WebhookEvent, type WebhookPayload, type WebhookSignatureHeaders, verifyWebhookSignature };
1054
+ export { type AccountProfile, type Addon, type AddonsResponse, type Alias, type AliasCreated, type ApiKey, type AttachmentRef, type BillingStatus, type BulkJob, type BulkJobCreated, type BulkSendInput, type CannedReply, type CheckoutLink, type CreateAliasInput, type CreateRuleInput, type CreateWebhookInput, type DnsChangeResult, type DnsDelegation, type DnsImportResult, type DnsListResponse, type DnsPreset, type DnsRRSet, type DnsRRSetAnotado, type DnsRecord, type DnsRecordType, type DnsSetup, type DnsSetupRecord, type DnsZoneCreated, type DnsZoneState, type Domain, type DomainCreated, type DomainInvite, type DomainMember, type DomainRegistration, type DomainRegistrationCreated, type DomainSearchResult, type DomainVerification, type EmailLog, type InboxAttachment, type InboxComposeInput, type InboxConversation, type InboxConversationDetail, type InboxListOptions, type InboxMessage, type InboxNote, type InboxPage, type InboxReplyInput, type InboxStatus, type InboxUpdateInput, MailMask, type MailMaskConfig, MailMaskError, type MailboxCreated, type Order, type OrdersPage, type ReferralStats, type RenewalLink, type Rule, type RuleAction, type RuleField, type RuleMatch, type SendEmailInput, type SendOptions, type SmtpCredential, type SmtpCredentialCreated, type Suppression, type TldPrice, type TransferCheck, type TransferDnsInventory, type TransferRequirement, type UpdateAliasInput, type UpdateRuleInput, type UpdateWebhookInput, type UploadAttachmentInput, type UploadedAttachment, type Webhook, type WebhookCreated, type WebhookDelivery, type WebhookEvent, type WebhookPayload, type WebhookSignatureHeaders, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -48,6 +48,8 @@ var MailMask = class {
48
48
  this.signature = new SignatureResource(req);
49
49
  this.canned = new CannedResource(req);
50
50
  this.account = new AccountResource(req);
51
+ this.inbox = new InboxResource(req, (path) => requestRaw(this.baseUrl, this.apiKey, path, doFetch));
52
+ this.referrals = new ReferralsResource(req);
51
53
  }
52
54
  };
53
55
  var DomainsResource = class {
@@ -76,6 +78,19 @@ var DomainsResource = class {
76
78
  dnsSetup(id, opts) {
77
79
  return this.req(`/api/domains/${id}/dns-setup${opts?.live ? "?live=1" : ""}`);
78
80
  }
81
+ /** Logo de la firma (PNG, JPG o WebP; máx. 500 KB). Se ve en todo correo en markdown. */
82
+ setLogo(id, file, filename = "logo") {
83
+ const form = new FormData();
84
+ form.append("file", file, filename);
85
+ return this.req(`/api/domains/${id}/logo`, { method: "POST", body: form });
86
+ }
87
+ /** Logo desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
88
+ setLogoFromUrl(id, url) {
89
+ return this.req(`/api/domains/${id}/logo`, { method: "POST", body: JSON.stringify({ fromUrl: url }) });
90
+ }
91
+ removeLogo(id) {
92
+ return this.req(`/api/domains/${id}/logo`, { method: "DELETE" });
93
+ }
79
94
  };
80
95
  var DnsResource = class {
81
96
  constructor(req) {
@@ -196,6 +211,10 @@ var AttachmentsResource = class {
196
211
  form.append("file", blob, input.filename);
197
212
  return this.req(`/api/domains/${domainId}/attachments`, { method: "POST", body: form });
198
213
  }
214
+ /** Desde un adjunto del chat del asistente (URL firmada de `/api/asistente/files/*`). */
215
+ uploadFromUrl(domainId, url, filename) {
216
+ return this.req(`/api/domains/${domainId}/attachments`, { method: "POST", body: JSON.stringify({ fromUrl: url, filename }) });
217
+ }
199
218
  };
200
219
  var SuppressionsResource = class {
201
220
  constructor(req) {
@@ -278,7 +297,19 @@ var BillingResource = class {
278
297
  * El usuario la abre y paga; hasta entonces no cambia nada.
279
298
  */
280
299
  checkout(domainId, kind = "domain", opts) {
281
- return this.req("/api/addons/checkout", { method: "POST", body: JSON.stringify({ kind, domainId, payerEmail: opts?.payerEmail }) });
300
+ return this.req("/api/addons/checkout", { method: "POST", body: JSON.stringify({ kind, domainId, payerEmail: opts?.payerEmail, period: opts?.period }) });
301
+ }
302
+ /** Cancela la suscripción de un add-on; el cupo sigue hasta el fin del periodo pagado. */
303
+ cancelAddon(addonId) {
304
+ return this.req(`/api/addons/${addonId}/cancel`, { method: "POST" });
305
+ }
306
+ /** Historial de cobros, cortesías y cancelaciones (más reciente primero). */
307
+ orders(opts) {
308
+ const qs = new URLSearchParams();
309
+ if (opts?.limit) qs.set("limit", String(opts.limit));
310
+ if (opts?.before) qs.set("before", opts.before);
311
+ const q = qs.toString();
312
+ return this.req(`/api/billing/orders${q ? `?${q}` : ""}`);
282
313
  }
283
314
  };
284
315
  var RegistrationsResource = class {
@@ -306,6 +337,10 @@ var RegistrationsResource = class {
306
337
  renewal(regId, opts) {
307
338
  return this.req(`/api/domains/registrations/${regId}/renewal`, { method: "POST", body: JSON.stringify({ payerEmail: opts?.payerEmail }) });
308
339
  }
340
+ /** Deja de cobrar la renovación anual. El dominio sigue vigente hasta su vencimiento. */
341
+ cancelRenewal(regId) {
342
+ return this.req(`/api/domains/registrations/${regId}/renewal/cancel`, { method: "POST" });
343
+ }
309
344
  };
310
345
  var TransfersResource = class {
311
346
  constructor(req) {
@@ -398,6 +433,77 @@ var AccountResource = class {
398
433
  return this.req("/api/profile/avatar", { method: "DELETE" });
399
434
  }
400
435
  };
436
+ var InboxResource = class {
437
+ constructor(req, raw) {
438
+ this.req = req;
439
+ this.raw = raw;
440
+ }
441
+ list(domainId, opts) {
442
+ const qs = new URLSearchParams({ domainId });
443
+ for (const [k, v] of Object.entries(opts ?? {})) if (v !== void 0 && v !== "") qs.set(k, String(v));
444
+ return this.req(`/api/bandeja/conversations?${qs}`);
445
+ }
446
+ /** Conversación con sus mensajes (los 30 más recientes, o anteriores a `before`). Abrirla la marca leída. */
447
+ get(domainId, conversationId, opts) {
448
+ const qs = new URLSearchParams({ domainId });
449
+ if (opts?.before) qs.set("before", opts.before);
450
+ return this.req(`/api/bandeja/conversations/${conversationId}?${qs}`);
451
+ }
452
+ /** Un correo nuevo desde una máscara: abre un hilo. Gasta cuota de envío (dominio activado). */
453
+ compose(domainId, input) {
454
+ return this.req("/api/bandeja/conversations", { method: "POST", body: JSON.stringify({ ...input, domainId }) });
455
+ }
456
+ /** Responde en el hilo desde la máscara del hilo. No gasta cuota de envío. */
457
+ reply(domainId, conversationId, input) {
458
+ return this.req(`/api/bandeja/conversations/${conversationId}/reply`, { method: "POST", body: JSON.stringify({ ...input, domainId }) });
459
+ }
460
+ update(domainId, conversationId, input) {
461
+ return this.req(`/api/bandeja/conversations/${conversationId}`, { method: "PATCH", body: JSON.stringify({ ...input, domainId }) });
462
+ }
463
+ markRead(domainId, conversationId) {
464
+ return this.req(`/api/bandeja/conversations/${conversationId}/read`, { method: "POST", body: JSON.stringify({ domainId }) });
465
+ }
466
+ /** Sin `assignedTo` la deja sin asignar. */
467
+ assign(domainId, conversationId, assignedTo) {
468
+ return this.req(`/api/bandeja/conversations/${conversationId}/assign`, { method: "POST", body: JSON.stringify({ domainId, assignedTo }) });
469
+ }
470
+ /** Nota interna: la ve el equipo, nunca el contacto. */
471
+ addNote(domainId, conversationId, body) {
472
+ return this.req(`/api/bandeja/conversations/${conversationId}/note`, { method: "POST", body: JSON.stringify({ domainId, body }) });
473
+ }
474
+ /** A la papelera (se puede restaurar). Máx. 200 por llamada. */
475
+ delete(domainId, conversationIds) {
476
+ return this.req("/api/bandeja/conversations/bulk-delete", { method: "POST", body: JSON.stringify({ domainId, ids: conversationIds }) });
477
+ }
478
+ restore(domainId, conversationId) {
479
+ return this.req(`/api/bandeja/conversations/${conversationId}/restore`, { method: "POST", body: JSON.stringify({ domainId }) });
480
+ }
481
+ metrics(domainId, opts) {
482
+ const qs = new URLSearchParams({ domainId });
483
+ if (opts?.days) qs.set("days", String(opts.days));
484
+ return this.req(`/api/bandeja/metrics?${qs}`);
485
+ }
486
+ /** Bytes de un adjunto de un mensaje (id del mensaje e índice de `attachments`). */
487
+ attachment(domainId, conversationId, messageId, index) {
488
+ return this.raw(`/api/bandeja/conversations/${conversationId}/attachments/${messageId}/${index}?domainId=${encodeURIComponent(domainId)}`);
489
+ }
490
+ };
491
+ var ReferralsResource = class {
492
+ constructor(req) {
493
+ this.req = req;
494
+ }
495
+ get() {
496
+ return this.req("/api/referrals");
497
+ }
498
+ /** 3-30 caracteres: minúsculas, números y guiones. */
499
+ setSlug(slug) {
500
+ return this.req("/api/referrals/slug", { method: "PUT", body: JSON.stringify({ slug }) });
501
+ }
502
+ /** Nombre que ven los invitados (2-40 caracteres). */
503
+ setName(name) {
504
+ return this.req("/api/referrals/name", { method: "PUT", body: JSON.stringify({ name }) });
505
+ }
506
+ };
401
507
 
402
508
  // src/verify.ts
403
509
  function hex(buf) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@easybits.cloud/mailmask",
3
- "version": "0.4.3",
3
+ "version": "0.4.4",
4
4
  "description": "Official SDK for the MailMask email alias/forwarding API",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",