@easybits.cloud/mailmask 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +128 -18
- package/dist/index.js +117 -18
- package/dist/partner-contract.d.ts +195 -43
- package/dist/partner.d.ts +33 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -20,11 +20,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
20
20
|
// src/index.ts
|
|
21
21
|
var index_exports = {};
|
|
22
22
|
__export(index_exports, {
|
|
23
|
+
AUTO_TOPUP_SUGGESTIONS: () => AUTO_TOPUP_SUGGESTIONS,
|
|
23
24
|
AuthError: () => AuthError,
|
|
24
25
|
BALANCE_LOW_FRACTION: () => BALANCE_LOW_FRACTION,
|
|
25
26
|
BALANCE_MOVEMENT_KINDS: () => BALANCE_MOVEMENT_KINDS,
|
|
26
27
|
ConflictError: () => ConflictError,
|
|
27
28
|
DOMAIN_CLAIM_TTL_DAYS: () => DOMAIN_CLAIM_TTL_DAYS,
|
|
29
|
+
DailyLimitError: () => DailyLimitError,
|
|
28
30
|
EXTERNAL_ID_RE: () => EXTERNAL_ID_RE,
|
|
29
31
|
FALLBACK_LABEL_RE: () => FALLBACK_LABEL_RE,
|
|
30
32
|
ForbiddenError: () => ForbiddenError,
|
|
@@ -43,8 +45,10 @@ __export(index_exports, {
|
|
|
43
45
|
NotFoundError: () => NotFoundError,
|
|
44
46
|
PARTNER_ADMIN_ROUTES: () => PARTNER_ADMIN_ROUTES,
|
|
45
47
|
PARTNER_API_PREFIX: () => PARTNER_API_PREFIX,
|
|
48
|
+
PARTNER_CURRENCIES: () => PARTNER_CURRENCIES,
|
|
46
49
|
PARTNER_ERROR_STATUS: () => PARTNER_ERROR_STATUS,
|
|
47
50
|
PARTNER_HEADERS: () => PARTNER_HEADERS,
|
|
51
|
+
PARTNER_PRICES: () => PARTNER_PRICES,
|
|
48
52
|
PARTNER_PRICE_PER_EMAIL_CENTS: () => PARTNER_PRICE_PER_EMAIL_CENTS,
|
|
49
53
|
PARTNER_ROUTES: () => PARTNER_ROUTES,
|
|
50
54
|
PARTNER_SIGNATURE_TOLERANCE_S: () => PARTNER_SIGNATURE_TOLERANCE_S,
|
|
@@ -52,6 +56,7 @@ __export(index_exports, {
|
|
|
52
56
|
PARTNER_TOPUP_MAX_CENTS: () => PARTNER_TOPUP_MAX_CENTS,
|
|
53
57
|
PARTNER_TOPUP_MIN_CENTS: () => PARTNER_TOPUP_MIN_CENTS,
|
|
54
58
|
PARTNER_WEBHOOK_EVENTS: () => PARTNER_WEBHOOK_EVENTS,
|
|
59
|
+
PARTNER_WELCOME_CENTS: () => PARTNER_WELCOME_CENTS,
|
|
55
60
|
PartnerApiError: () => PartnerApiError,
|
|
56
61
|
PausedError: () => PausedError,
|
|
57
62
|
QuotaError: () => QuotaError,
|
|
@@ -62,12 +67,17 @@ __export(index_exports, {
|
|
|
62
67
|
STRICT_FIRST_DAYS: () => STRICT_FIRST_DAYS,
|
|
63
68
|
TAG_RE: () => TAG_RE,
|
|
64
69
|
TEMPLATE_VAR_NAME_RE: () => TEMPLATE_VAR_NAME_RE,
|
|
70
|
+
TENANT_DAILY_LIMIT_MAX: () => TENANT_DAILY_LIMIT_MAX,
|
|
71
|
+
TENANT_DAILY_LIMIT_START: () => TENANT_DAILY_LIMIT_START,
|
|
72
|
+
TENANT_WARMUP_STEP_DAYS: () => TENANT_WARMUP_STEP_DAYS,
|
|
65
73
|
TimeoutError: () => TimeoutError,
|
|
66
74
|
UNSUBSCRIBE_URL_VAR: () => UNSUBSCRIBE_URL_VAR,
|
|
67
75
|
ValidationError: () => ValidationError,
|
|
68
76
|
WEBHOOK_HEADERS: () => WEBHOOK_HEADERS,
|
|
69
77
|
WEBHOOK_TOLERANCE_MS: () => WEBHOOK_TOLERANCE_MS,
|
|
70
78
|
createWebhookHandler: () => createWebhookHandler,
|
|
79
|
+
estimateSendDays: () => estimateSendDays,
|
|
80
|
+
formatMoney: () => formatMoney,
|
|
71
81
|
isValidExternalId: () => isValidExternalId,
|
|
72
82
|
isValidFallbackLabel: () => isValidFallbackLabel,
|
|
73
83
|
partnerSignatureBase: () => partnerSignatureBase,
|
|
@@ -80,6 +90,7 @@ __export(index_exports, {
|
|
|
80
90
|
templateVarsProblem: () => templateVarsProblem,
|
|
81
91
|
verifyWebhook: () => verifyWebhook,
|
|
82
92
|
verifyWebhookSignature: () => verifyWebhookSignature,
|
|
93
|
+
warmupLimit: () => warmupLimit,
|
|
83
94
|
webhookSignatureBase: () => webhookSignatureBase
|
|
84
95
|
});
|
|
85
96
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -724,11 +735,16 @@ var PARTNER_ERROR_STATUS = {
|
|
|
724
735
|
/** El tenant está en pausa (por MailMask o por el partner). No se manda nada hasta `resume`. */
|
|
725
736
|
tenant_paused: 423,
|
|
726
737
|
/**
|
|
727
|
-
* Saldo prepagado insuficiente (con `balanceCents` y `requiredCents`).
|
|
728
|
-
*
|
|
738
|
+
* Saldo prepagado insuficiente (con `balanceCents` y `requiredCents`). No se reintenta: recarga
|
|
739
|
+
* con `POST /topup`.
|
|
729
740
|
*/
|
|
730
741
|
insufficient_balance: 402,
|
|
731
|
-
/**
|
|
742
|
+
/**
|
|
743
|
+
* El tenant llegó a su límite del día (con `limit`, `sentToday` y `resetsAt`, la medianoche UTC).
|
|
744
|
+
* Sólo en envíos sueltos: un lote no falla, espera al día siguiente (`batch.throttled`).
|
|
745
|
+
*/
|
|
746
|
+
daily_limit: 429,
|
|
747
|
+
/** Ya no sale desde la 0.8 (no hay tope mensual); se deja para clientes viejos. */
|
|
732
748
|
quota_exceeded: 429,
|
|
733
749
|
/** Demasiadas peticiones; reintenta tras `Retry-After`. */
|
|
734
750
|
rate_limited: 429,
|
|
@@ -742,6 +758,30 @@ function isValidExternalId(id) {
|
|
|
742
758
|
var MAX_BATCH_RECIPIENTS = 1e4;
|
|
743
759
|
var MAX_TAGS = 10;
|
|
744
760
|
var TAG_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
761
|
+
var TENANT_DAILY_LIMIT_START = 2e3;
|
|
762
|
+
var TENANT_DAILY_LIMIT_MAX = 2e4;
|
|
763
|
+
var TENANT_WARMUP_STEP_DAYS = 7;
|
|
764
|
+
function warmupLimit(step) {
|
|
765
|
+
return Math.min(TENANT_DAILY_LIMIT_MAX, TENANT_DAILY_LIMIT_START * 2 ** Math.max(0, step));
|
|
766
|
+
}
|
|
767
|
+
function estimateSendDays(s, recipients) {
|
|
768
|
+
let left = recipients - Math.max(0, s.dailyLimit - s.sentToday);
|
|
769
|
+
if (left <= 0) return 1;
|
|
770
|
+
let days = 1;
|
|
771
|
+
let limit = s.dailyLimit;
|
|
772
|
+
let nextAt = s.nextStepAt ? Date.parse(s.nextStepAt) : null;
|
|
773
|
+
let day = Date.parse(s.resetsAt);
|
|
774
|
+
while (left > 0 && days < 3650) {
|
|
775
|
+
while (nextAt !== null && nextAt <= day && limit < TENANT_DAILY_LIMIT_MAX && !s.fixed) {
|
|
776
|
+
limit = Math.min(TENANT_DAILY_LIMIT_MAX, limit * 2);
|
|
777
|
+
nextAt += TENANT_WARMUP_STEP_DAYS * 864e5;
|
|
778
|
+
}
|
|
779
|
+
left -= limit;
|
|
780
|
+
days++;
|
|
781
|
+
day += 864e5;
|
|
782
|
+
}
|
|
783
|
+
return days;
|
|
784
|
+
}
|
|
745
785
|
var DOMAIN_CLAIM_TTL_DAYS = 7;
|
|
746
786
|
var FALLBACK_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
747
787
|
var RESERVED_FALLBACK_LABELS = [
|
|
@@ -807,12 +847,25 @@ function personalizePartnerMessage(input) {
|
|
|
807
847
|
...text !== void 0 ? { text: renderTemplate(text, vars) } : {}
|
|
808
848
|
};
|
|
809
849
|
}
|
|
810
|
-
var
|
|
811
|
-
var
|
|
812
|
-
|
|
813
|
-
|
|
850
|
+
var PARTNER_CURRENCIES = ["MXN", "USD"];
|
|
851
|
+
var PARTNER_PRICES = {
|
|
852
|
+
MXN: { perEmailCents: 6, tenantMonthCents: 4900, welcomeCents: 5e4, topupMinCents: 5e4, topupMaxCents: 1e7 },
|
|
853
|
+
USD: { perEmailCents: 0.35, tenantMonthCents: 290, welcomeCents: 2900, topupMinCents: 2900, topupMaxCents: 55e4 }
|
|
854
|
+
};
|
|
855
|
+
var PARTNER_PRICE_PER_EMAIL_CENTS = PARTNER_PRICES.MXN.perEmailCents;
|
|
856
|
+
var PARTNER_TENANT_MONTH_CENTS = PARTNER_PRICES.MXN.tenantMonthCents;
|
|
857
|
+
var PARTNER_WELCOME_CENTS = PARTNER_PRICES.MXN.welcomeCents;
|
|
858
|
+
var PARTNER_TOPUP_MIN_CENTS = PARTNER_PRICES.MXN.topupMinCents;
|
|
859
|
+
var PARTNER_TOPUP_MAX_CENTS = PARTNER_PRICES.MXN.topupMaxCents;
|
|
860
|
+
function formatMoney(cents, currency) {
|
|
861
|
+
const v = Math.abs(cents) / 100;
|
|
862
|
+
const decimals = v !== 0 && v < 0.01 ? 4 : 2;
|
|
863
|
+
const n = v.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
|
|
864
|
+
return `${cents < 0 ? "\u2212" : ""}$${n} ${currency}`;
|
|
865
|
+
}
|
|
814
866
|
var BALANCE_LOW_FRACTION = 0.2;
|
|
815
867
|
var BALANCE_MOVEMENT_KINDS = ["topup", "send", "tenant_fee", "refund", "adjust"];
|
|
868
|
+
var AUTO_TOPUP_SUGGESTIONS = { MXN: [500, 1e3, 2500], USD: [29, 59, 149] };
|
|
816
869
|
var PARTNER_WEBHOOK_EVENTS = [
|
|
817
870
|
"email.sent",
|
|
818
871
|
"email.delivered",
|
|
@@ -823,7 +876,8 @@ var PARTNER_WEBHOOK_EVENTS = [
|
|
|
823
876
|
"tenant.paused",
|
|
824
877
|
"tenant.resumed",
|
|
825
878
|
"domain.verified",
|
|
826
|
-
"balance.low"
|
|
879
|
+
"balance.low",
|
|
880
|
+
"batch.throttled"
|
|
827
881
|
];
|
|
828
882
|
var WEBHOOK_HEADERS = {
|
|
829
883
|
event: "X-MailMask-Event",
|
|
@@ -858,6 +912,8 @@ var PARTNER_ROUTES = {
|
|
|
858
912
|
balance: { method: "GET", path: "/balance" },
|
|
859
913
|
balanceMovements: { method: "GET", path: "/balance/movements" },
|
|
860
914
|
topup: { method: "POST", path: "/topup" },
|
|
915
|
+
getAutoTopup: { method: "GET", path: "/auto-topup" },
|
|
916
|
+
setAutoTopup: { method: "PUT", path: "/auto-topup" },
|
|
861
917
|
getWebhook: { method: "GET", path: "/webhook" },
|
|
862
918
|
setWebhook: { method: "PUT", path: "/webhook" },
|
|
863
919
|
testWebhook: { method: "POST", path: "/webhook/test" },
|
|
@@ -877,10 +933,14 @@ var PARTNER_ADMIN_ROUTES = {
|
|
|
877
933
|
getBalance: { method: "GET", path: "/api/partners/:partnerId/balance" },
|
|
878
934
|
/** Sólo MailMask (admin): abono o cargo manual (`adjust`). */
|
|
879
935
|
adjustBalance: { method: "POST", path: "/api/partners/:partnerId/balance/adjust" },
|
|
880
|
-
/** Sólo MailMask (admin): prende o apaga el cobro por adelantado. */
|
|
881
|
-
setPrepaidEnforced: { method: "PUT", path: "/api/partners/:partnerId/prepaid" },
|
|
882
936
|
/** Recarga con MercadoPago desde la sesión del dueño (misma respuesta que `POST /topup`). */
|
|
883
937
|
topup: { method: "POST", path: "/api/partners/:partnerId/topup" },
|
|
938
|
+
getAutoTopup: { method: "GET", path: "/api/partners/:partnerId/auto-topup" },
|
|
939
|
+
setAutoTopup: { method: "PUT", path: "/api/partners/:partnerId/auto-topup" },
|
|
940
|
+
/** Sólo MailMask: moneda del saldo, mientras no haya más movimientos que la bienvenida. */
|
|
941
|
+
setCurrency: { method: "PUT", path: "/api/partners/:partnerId/currency" },
|
|
942
|
+
/** Sólo MailMask: fija (o quita, con `null`) el límite diario de un tenant. Devuelve el `Tenant`. */
|
|
943
|
+
setTenantDailyLimit: { method: "PUT", path: "/api/partners/:partnerId/tenants/:externalId/daily-limit" },
|
|
884
944
|
listCredentials: { method: "GET", path: "/api/partners/:partnerId/credentials" },
|
|
885
945
|
createCredential: { method: "POST", path: "/api/partners/:partnerId/credentials" },
|
|
886
946
|
rotateCredential: { method: "POST", path: "/api/partners/:partnerId/credentials/:keyId/rotate" },
|
|
@@ -894,8 +954,8 @@ var PartnerApiError = class extends MailMaskError {
|
|
|
894
954
|
code: body.code,
|
|
895
955
|
requestId: meta.requestId,
|
|
896
956
|
cause: meta.cause,
|
|
897
|
-
// `quota_exceeded`
|
|
898
|
-
retryable: status === 0 || status >= 500 || status === 429 && body.code !== "quota_exceeded"
|
|
957
|
+
// `daily_limit` (y el viejo `quota_exceeded`) son 429 que no se arreglan reintentando: hasta mañana.
|
|
958
|
+
retryable: status === 0 || status >= 500 || status === 429 && body.code !== "quota_exceeded" && body.code !== "daily_limit"
|
|
899
959
|
});
|
|
900
960
|
this.kind = "unknown";
|
|
901
961
|
this.name = "PartnerApiError";
|
|
@@ -998,6 +1058,16 @@ var RateLimitError = class extends QuotaError {
|
|
|
998
1058
|
this.kind = "rate_limit";
|
|
999
1059
|
}
|
|
1000
1060
|
};
|
|
1061
|
+
var DailyLimitError = class extends QuotaError {
|
|
1062
|
+
constructor() {
|
|
1063
|
+
super(...arguments);
|
|
1064
|
+
this.name = "DailyLimitError";
|
|
1065
|
+
this.kind = "daily_limit";
|
|
1066
|
+
}
|
|
1067
|
+
get sentToday() {
|
|
1068
|
+
return this.body.sentToday;
|
|
1069
|
+
}
|
|
1070
|
+
};
|
|
1001
1071
|
var InsufficientBalanceError = class extends PartnerApiError {
|
|
1002
1072
|
constructor() {
|
|
1003
1073
|
super(...arguments);
|
|
@@ -1010,6 +1080,10 @@ var InsufficientBalanceError = class extends PartnerApiError {
|
|
|
1010
1080
|
get requiredCents() {
|
|
1011
1081
|
return this.body.requiredCents;
|
|
1012
1082
|
}
|
|
1083
|
+
/** Moneda de los dos montos de arriba. */
|
|
1084
|
+
get currency() {
|
|
1085
|
+
return this.body.currency;
|
|
1086
|
+
}
|
|
1013
1087
|
};
|
|
1014
1088
|
var NetworkError = class extends PartnerApiError {
|
|
1015
1089
|
constructor(message, cause) {
|
|
@@ -1029,6 +1103,7 @@ function errorFor(status, body, fallback, meta = {}) {
|
|
|
1029
1103
|
const msg = body.error || fallback;
|
|
1030
1104
|
if (body.code === "reputation_hold") return new ReputationHoldError(status, msg, body, meta);
|
|
1031
1105
|
if (body.code === "recipient_suppressed") return new RecipientSuppressedError(status, msg, body, meta);
|
|
1106
|
+
if (status === 429 && body.code === "daily_limit") return new DailyLimitError(status, msg, body, meta);
|
|
1032
1107
|
if (status === 429 && body.code !== "quota_exceeded") return new RateLimitError(status, msg, body, meta);
|
|
1033
1108
|
switch (status) {
|
|
1034
1109
|
case 401:
|
|
@@ -1249,12 +1324,24 @@ var MailMaskPartner = class {
|
|
|
1249
1324
|
return (await this.request("GET", `${PARTNER_ROUTES.balanceMovements.path}${qs ? `?${qs}` : ""}`)).data;
|
|
1250
1325
|
}
|
|
1251
1326
|
/**
|
|
1252
|
-
* Liga de MercadoPago para recargar saldo (pago único
|
|
1253
|
-
*
|
|
1327
|
+
* Liga de MercadoPago para recargar saldo (pago único; `amount` en unidades enteras de tu moneda:
|
|
1328
|
+
* MXN 500 a 100,000, USD 29 a 5,500). El saldo sube cuando MercadoPago confirma el pago, no al
|
|
1329
|
+
* crear la liga. Abre `initPoint` en el navegador de quien paga.
|
|
1254
1330
|
*/
|
|
1255
1331
|
async topup(input) {
|
|
1256
1332
|
return (await this.request("POST", PARTNER_ROUTES.topup.path, input)).data;
|
|
1257
1333
|
}
|
|
1334
|
+
/** La recarga automática mensual: `off`, `pending` (falta autorizarla) o `active`. */
|
|
1335
|
+
async autoTopup() {
|
|
1336
|
+
return (await this.request("GET", PARTNER_ROUTES.getAutoTopup.path)).data;
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Prende o cambia (`amount` entero de tu moneda) la recarga automática mensual, o la apaga
|
|
1340
|
+
* (`amount: null`). Al prenderla o cambiarla devuelve `initPoint`: ábrelo para autorizar el cobro.
|
|
1341
|
+
*/
|
|
1342
|
+
async setAutoTopup(input) {
|
|
1343
|
+
return (await this.request("PUT", PARTNER_ROUTES.setAutoTopup.path, input)).data;
|
|
1344
|
+
}
|
|
1258
1345
|
/** Uso del mes (`YYYY-MM`, default el mes en curso UTC): tenants activos y envíos. */
|
|
1259
1346
|
async usage(opts = {}) {
|
|
1260
1347
|
const q = opts.month ? `?month=${encodeURIComponent(opts.month)}` : "";
|
|
@@ -1455,10 +1542,18 @@ var MailMaskPartnerAdmin = class {
|
|
|
1455
1542
|
setReputationPolicy(partnerId, policy) {
|
|
1456
1543
|
return this.req("setReputationPolicy", { partnerId }, { policy });
|
|
1457
1544
|
}
|
|
1545
|
+
/** Sólo MailMask (admin): moneda del saldo (MXN o USD); sólo antes de cualquier movimiento aparte de la bienvenida. */
|
|
1546
|
+
setCurrency(partnerId, currency) {
|
|
1547
|
+
return this.req("setCurrency", { partnerId }, { currency });
|
|
1548
|
+
}
|
|
1458
1549
|
/** Sólo MailMask (admin): levanta cualquier pausa, también la de reputación. */
|
|
1459
1550
|
resumeTenant(partnerId, externalId) {
|
|
1460
1551
|
return this.req("resumeTenant", { partnerId, externalId });
|
|
1461
1552
|
}
|
|
1553
|
+
/** Sólo MailMask: tope diario fijo del tenant, o `null` para volver al calentamiento. */
|
|
1554
|
+
setTenantDailyLimit(partnerId, externalId, limit) {
|
|
1555
|
+
return this.req("setTenantDailyLimit", { partnerId, externalId }, { limit });
|
|
1556
|
+
}
|
|
1462
1557
|
/**
|
|
1463
1558
|
* Sólo MailMask (admin): crea o adopta la hosted zone de la zona de respaldo (`marketing.denik.me`)
|
|
1464
1559
|
* y devuelve los NS que el partner tiene que delegar. Idempotente con la misma zona.
|
|
@@ -1478,14 +1573,18 @@ var MailMaskPartnerAdmin = class {
|
|
|
1478
1573
|
adjustBalance(partnerId, input) {
|
|
1479
1574
|
return this.req("adjustBalance", { partnerId }, input);
|
|
1480
1575
|
}
|
|
1481
|
-
/** Sólo MailMask (admin): prende o apaga el cobro por adelantado del partner. */
|
|
1482
|
-
setPrepaidEnforced(partnerId, enforced) {
|
|
1483
|
-
return this.req("setPrepaidEnforced", { partnerId }, { enforced });
|
|
1484
|
-
}
|
|
1485
1576
|
/** Liga de MercadoPago para recargar, con la llave del dueño. */
|
|
1486
1577
|
topup(partnerId, input) {
|
|
1487
1578
|
return this.req("topup", { partnerId }, input);
|
|
1488
1579
|
}
|
|
1580
|
+
/** La recarga automática mensual del partner (dueño o MailMask). */
|
|
1581
|
+
getAutoTopup(partnerId) {
|
|
1582
|
+
return this.req("getAutoTopup", { partnerId });
|
|
1583
|
+
}
|
|
1584
|
+
/** Prende, cambia (`amount`) o apaga (`null`) la recarga automática; trae `initPoint` al prenderla. */
|
|
1585
|
+
setAutoTopup(partnerId, input) {
|
|
1586
|
+
return this.req("setAutoTopup", { partnerId }, input);
|
|
1587
|
+
}
|
|
1489
1588
|
listCredentials(partnerId) {
|
|
1490
1589
|
return this.req("listCredentials", { partnerId });
|
|
1491
1590
|
}
|
|
@@ -1504,11 +1603,13 @@ var MailMaskPartnerAdmin = class {
|
|
|
1504
1603
|
};
|
|
1505
1604
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1506
1605
|
0 && (module.exports = {
|
|
1606
|
+
AUTO_TOPUP_SUGGESTIONS,
|
|
1507
1607
|
AuthError,
|
|
1508
1608
|
BALANCE_LOW_FRACTION,
|
|
1509
1609
|
BALANCE_MOVEMENT_KINDS,
|
|
1510
1610
|
ConflictError,
|
|
1511
1611
|
DOMAIN_CLAIM_TTL_DAYS,
|
|
1612
|
+
DailyLimitError,
|
|
1512
1613
|
EXTERNAL_ID_RE,
|
|
1513
1614
|
FALLBACK_LABEL_RE,
|
|
1514
1615
|
ForbiddenError,
|
|
@@ -1527,8 +1628,10 @@ var MailMaskPartnerAdmin = class {
|
|
|
1527
1628
|
NotFoundError,
|
|
1528
1629
|
PARTNER_ADMIN_ROUTES,
|
|
1529
1630
|
PARTNER_API_PREFIX,
|
|
1631
|
+
PARTNER_CURRENCIES,
|
|
1530
1632
|
PARTNER_ERROR_STATUS,
|
|
1531
1633
|
PARTNER_HEADERS,
|
|
1634
|
+
PARTNER_PRICES,
|
|
1532
1635
|
PARTNER_PRICE_PER_EMAIL_CENTS,
|
|
1533
1636
|
PARTNER_ROUTES,
|
|
1534
1637
|
PARTNER_SIGNATURE_TOLERANCE_S,
|
|
@@ -1536,6 +1639,7 @@ var MailMaskPartnerAdmin = class {
|
|
|
1536
1639
|
PARTNER_TOPUP_MAX_CENTS,
|
|
1537
1640
|
PARTNER_TOPUP_MIN_CENTS,
|
|
1538
1641
|
PARTNER_WEBHOOK_EVENTS,
|
|
1642
|
+
PARTNER_WELCOME_CENTS,
|
|
1539
1643
|
PartnerApiError,
|
|
1540
1644
|
PausedError,
|
|
1541
1645
|
QuotaError,
|
|
@@ -1546,12 +1650,17 @@ var MailMaskPartnerAdmin = class {
|
|
|
1546
1650
|
STRICT_FIRST_DAYS,
|
|
1547
1651
|
TAG_RE,
|
|
1548
1652
|
TEMPLATE_VAR_NAME_RE,
|
|
1653
|
+
TENANT_DAILY_LIMIT_MAX,
|
|
1654
|
+
TENANT_DAILY_LIMIT_START,
|
|
1655
|
+
TENANT_WARMUP_STEP_DAYS,
|
|
1549
1656
|
TimeoutError,
|
|
1550
1657
|
UNSUBSCRIBE_URL_VAR,
|
|
1551
1658
|
ValidationError,
|
|
1552
1659
|
WEBHOOK_HEADERS,
|
|
1553
1660
|
WEBHOOK_TOLERANCE_MS,
|
|
1554
1661
|
createWebhookHandler,
|
|
1662
|
+
estimateSendDays,
|
|
1663
|
+
formatMoney,
|
|
1555
1664
|
isValidExternalId,
|
|
1556
1665
|
isValidFallbackLabel,
|
|
1557
1666
|
partnerSignatureBase,
|
|
@@ -1564,5 +1673,6 @@ var MailMaskPartnerAdmin = class {
|
|
|
1564
1673
|
templateVarsProblem,
|
|
1565
1674
|
verifyWebhook,
|
|
1566
1675
|
verifyWebhookSignature,
|
|
1676
|
+
warmupLimit,
|
|
1567
1677
|
webhookSignatureBase
|
|
1568
1678
|
});
|
package/dist/index.js
CHANGED
|
@@ -638,11 +638,16 @@ var PARTNER_ERROR_STATUS = {
|
|
|
638
638
|
/** El tenant está en pausa (por MailMask o por el partner). No se manda nada hasta `resume`. */
|
|
639
639
|
tenant_paused: 423,
|
|
640
640
|
/**
|
|
641
|
-
* Saldo prepagado insuficiente (con `balanceCents` y `requiredCents`).
|
|
642
|
-
*
|
|
641
|
+
* Saldo prepagado insuficiente (con `balanceCents` y `requiredCents`). No se reintenta: recarga
|
|
642
|
+
* con `POST /topup`.
|
|
643
643
|
*/
|
|
644
644
|
insufficient_balance: 402,
|
|
645
|
-
/**
|
|
645
|
+
/**
|
|
646
|
+
* El tenant llegó a su límite del día (con `limit`, `sentToday` y `resetsAt`, la medianoche UTC).
|
|
647
|
+
* Sólo en envíos sueltos: un lote no falla, espera al día siguiente (`batch.throttled`).
|
|
648
|
+
*/
|
|
649
|
+
daily_limit: 429,
|
|
650
|
+
/** Ya no sale desde la 0.8 (no hay tope mensual); se deja para clientes viejos. */
|
|
646
651
|
quota_exceeded: 429,
|
|
647
652
|
/** Demasiadas peticiones; reintenta tras `Retry-After`. */
|
|
648
653
|
rate_limited: 429,
|
|
@@ -656,6 +661,30 @@ function isValidExternalId(id) {
|
|
|
656
661
|
var MAX_BATCH_RECIPIENTS = 1e4;
|
|
657
662
|
var MAX_TAGS = 10;
|
|
658
663
|
var TAG_RE = /^[A-Za-z0-9_-]{1,64}$/;
|
|
664
|
+
var TENANT_DAILY_LIMIT_START = 2e3;
|
|
665
|
+
var TENANT_DAILY_LIMIT_MAX = 2e4;
|
|
666
|
+
var TENANT_WARMUP_STEP_DAYS = 7;
|
|
667
|
+
function warmupLimit(step) {
|
|
668
|
+
return Math.min(TENANT_DAILY_LIMIT_MAX, TENANT_DAILY_LIMIT_START * 2 ** Math.max(0, step));
|
|
669
|
+
}
|
|
670
|
+
function estimateSendDays(s, recipients) {
|
|
671
|
+
let left = recipients - Math.max(0, s.dailyLimit - s.sentToday);
|
|
672
|
+
if (left <= 0) return 1;
|
|
673
|
+
let days = 1;
|
|
674
|
+
let limit = s.dailyLimit;
|
|
675
|
+
let nextAt = s.nextStepAt ? Date.parse(s.nextStepAt) : null;
|
|
676
|
+
let day = Date.parse(s.resetsAt);
|
|
677
|
+
while (left > 0 && days < 3650) {
|
|
678
|
+
while (nextAt !== null && nextAt <= day && limit < TENANT_DAILY_LIMIT_MAX && !s.fixed) {
|
|
679
|
+
limit = Math.min(TENANT_DAILY_LIMIT_MAX, limit * 2);
|
|
680
|
+
nextAt += TENANT_WARMUP_STEP_DAYS * 864e5;
|
|
681
|
+
}
|
|
682
|
+
left -= limit;
|
|
683
|
+
days++;
|
|
684
|
+
day += 864e5;
|
|
685
|
+
}
|
|
686
|
+
return days;
|
|
687
|
+
}
|
|
659
688
|
var DOMAIN_CLAIM_TTL_DAYS = 7;
|
|
660
689
|
var FALLBACK_LABEL_RE = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
|
|
661
690
|
var RESERVED_FALLBACK_LABELS = [
|
|
@@ -721,12 +750,25 @@ function personalizePartnerMessage(input) {
|
|
|
721
750
|
...text !== void 0 ? { text: renderTemplate(text, vars) } : {}
|
|
722
751
|
};
|
|
723
752
|
}
|
|
724
|
-
var
|
|
725
|
-
var
|
|
726
|
-
|
|
727
|
-
|
|
753
|
+
var PARTNER_CURRENCIES = ["MXN", "USD"];
|
|
754
|
+
var PARTNER_PRICES = {
|
|
755
|
+
MXN: { perEmailCents: 6, tenantMonthCents: 4900, welcomeCents: 5e4, topupMinCents: 5e4, topupMaxCents: 1e7 },
|
|
756
|
+
USD: { perEmailCents: 0.35, tenantMonthCents: 290, welcomeCents: 2900, topupMinCents: 2900, topupMaxCents: 55e4 }
|
|
757
|
+
};
|
|
758
|
+
var PARTNER_PRICE_PER_EMAIL_CENTS = PARTNER_PRICES.MXN.perEmailCents;
|
|
759
|
+
var PARTNER_TENANT_MONTH_CENTS = PARTNER_PRICES.MXN.tenantMonthCents;
|
|
760
|
+
var PARTNER_WELCOME_CENTS = PARTNER_PRICES.MXN.welcomeCents;
|
|
761
|
+
var PARTNER_TOPUP_MIN_CENTS = PARTNER_PRICES.MXN.topupMinCents;
|
|
762
|
+
var PARTNER_TOPUP_MAX_CENTS = PARTNER_PRICES.MXN.topupMaxCents;
|
|
763
|
+
function formatMoney(cents, currency) {
|
|
764
|
+
const v = Math.abs(cents) / 100;
|
|
765
|
+
const decimals = v !== 0 && v < 0.01 ? 4 : 2;
|
|
766
|
+
const n = v.toLocaleString("en-US", { minimumFractionDigits: decimals, maximumFractionDigits: decimals });
|
|
767
|
+
return `${cents < 0 ? "\u2212" : ""}$${n} ${currency}`;
|
|
768
|
+
}
|
|
728
769
|
var BALANCE_LOW_FRACTION = 0.2;
|
|
729
770
|
var BALANCE_MOVEMENT_KINDS = ["topup", "send", "tenant_fee", "refund", "adjust"];
|
|
771
|
+
var AUTO_TOPUP_SUGGESTIONS = { MXN: [500, 1e3, 2500], USD: [29, 59, 149] };
|
|
730
772
|
var PARTNER_WEBHOOK_EVENTS = [
|
|
731
773
|
"email.sent",
|
|
732
774
|
"email.delivered",
|
|
@@ -737,7 +779,8 @@ var PARTNER_WEBHOOK_EVENTS = [
|
|
|
737
779
|
"tenant.paused",
|
|
738
780
|
"tenant.resumed",
|
|
739
781
|
"domain.verified",
|
|
740
|
-
"balance.low"
|
|
782
|
+
"balance.low",
|
|
783
|
+
"batch.throttled"
|
|
741
784
|
];
|
|
742
785
|
var WEBHOOK_HEADERS = {
|
|
743
786
|
event: "X-MailMask-Event",
|
|
@@ -772,6 +815,8 @@ var PARTNER_ROUTES = {
|
|
|
772
815
|
balance: { method: "GET", path: "/balance" },
|
|
773
816
|
balanceMovements: { method: "GET", path: "/balance/movements" },
|
|
774
817
|
topup: { method: "POST", path: "/topup" },
|
|
818
|
+
getAutoTopup: { method: "GET", path: "/auto-topup" },
|
|
819
|
+
setAutoTopup: { method: "PUT", path: "/auto-topup" },
|
|
775
820
|
getWebhook: { method: "GET", path: "/webhook" },
|
|
776
821
|
setWebhook: { method: "PUT", path: "/webhook" },
|
|
777
822
|
testWebhook: { method: "POST", path: "/webhook/test" },
|
|
@@ -791,10 +836,14 @@ var PARTNER_ADMIN_ROUTES = {
|
|
|
791
836
|
getBalance: { method: "GET", path: "/api/partners/:partnerId/balance" },
|
|
792
837
|
/** Sólo MailMask (admin): abono o cargo manual (`adjust`). */
|
|
793
838
|
adjustBalance: { method: "POST", path: "/api/partners/:partnerId/balance/adjust" },
|
|
794
|
-
/** Sólo MailMask (admin): prende o apaga el cobro por adelantado. */
|
|
795
|
-
setPrepaidEnforced: { method: "PUT", path: "/api/partners/:partnerId/prepaid" },
|
|
796
839
|
/** Recarga con MercadoPago desde la sesión del dueño (misma respuesta que `POST /topup`). */
|
|
797
840
|
topup: { method: "POST", path: "/api/partners/:partnerId/topup" },
|
|
841
|
+
getAutoTopup: { method: "GET", path: "/api/partners/:partnerId/auto-topup" },
|
|
842
|
+
setAutoTopup: { method: "PUT", path: "/api/partners/:partnerId/auto-topup" },
|
|
843
|
+
/** Sólo MailMask: moneda del saldo, mientras no haya más movimientos que la bienvenida. */
|
|
844
|
+
setCurrency: { method: "PUT", path: "/api/partners/:partnerId/currency" },
|
|
845
|
+
/** Sólo MailMask: fija (o quita, con `null`) el límite diario de un tenant. Devuelve el `Tenant`. */
|
|
846
|
+
setTenantDailyLimit: { method: "PUT", path: "/api/partners/:partnerId/tenants/:externalId/daily-limit" },
|
|
798
847
|
listCredentials: { method: "GET", path: "/api/partners/:partnerId/credentials" },
|
|
799
848
|
createCredential: { method: "POST", path: "/api/partners/:partnerId/credentials" },
|
|
800
849
|
rotateCredential: { method: "POST", path: "/api/partners/:partnerId/credentials/:keyId/rotate" },
|
|
@@ -808,8 +857,8 @@ var PartnerApiError = class extends MailMaskError {
|
|
|
808
857
|
code: body.code,
|
|
809
858
|
requestId: meta.requestId,
|
|
810
859
|
cause: meta.cause,
|
|
811
|
-
// `quota_exceeded`
|
|
812
|
-
retryable: status === 0 || status >= 500 || status === 429 && body.code !== "quota_exceeded"
|
|
860
|
+
// `daily_limit` (y el viejo `quota_exceeded`) son 429 que no se arreglan reintentando: hasta mañana.
|
|
861
|
+
retryable: status === 0 || status >= 500 || status === 429 && body.code !== "quota_exceeded" && body.code !== "daily_limit"
|
|
813
862
|
});
|
|
814
863
|
this.kind = "unknown";
|
|
815
864
|
this.name = "PartnerApiError";
|
|
@@ -912,6 +961,16 @@ var RateLimitError = class extends QuotaError {
|
|
|
912
961
|
this.kind = "rate_limit";
|
|
913
962
|
}
|
|
914
963
|
};
|
|
964
|
+
var DailyLimitError = class extends QuotaError {
|
|
965
|
+
constructor() {
|
|
966
|
+
super(...arguments);
|
|
967
|
+
this.name = "DailyLimitError";
|
|
968
|
+
this.kind = "daily_limit";
|
|
969
|
+
}
|
|
970
|
+
get sentToday() {
|
|
971
|
+
return this.body.sentToday;
|
|
972
|
+
}
|
|
973
|
+
};
|
|
915
974
|
var InsufficientBalanceError = class extends PartnerApiError {
|
|
916
975
|
constructor() {
|
|
917
976
|
super(...arguments);
|
|
@@ -924,6 +983,10 @@ var InsufficientBalanceError = class extends PartnerApiError {
|
|
|
924
983
|
get requiredCents() {
|
|
925
984
|
return this.body.requiredCents;
|
|
926
985
|
}
|
|
986
|
+
/** Moneda de los dos montos de arriba. */
|
|
987
|
+
get currency() {
|
|
988
|
+
return this.body.currency;
|
|
989
|
+
}
|
|
927
990
|
};
|
|
928
991
|
var NetworkError = class extends PartnerApiError {
|
|
929
992
|
constructor(message, cause) {
|
|
@@ -943,6 +1006,7 @@ function errorFor(status, body, fallback, meta = {}) {
|
|
|
943
1006
|
const msg = body.error || fallback;
|
|
944
1007
|
if (body.code === "reputation_hold") return new ReputationHoldError(status, msg, body, meta);
|
|
945
1008
|
if (body.code === "recipient_suppressed") return new RecipientSuppressedError(status, msg, body, meta);
|
|
1009
|
+
if (status === 429 && body.code === "daily_limit") return new DailyLimitError(status, msg, body, meta);
|
|
946
1010
|
if (status === 429 && body.code !== "quota_exceeded") return new RateLimitError(status, msg, body, meta);
|
|
947
1011
|
switch (status) {
|
|
948
1012
|
case 401:
|
|
@@ -1163,12 +1227,24 @@ var MailMaskPartner = class {
|
|
|
1163
1227
|
return (await this.request("GET", `${PARTNER_ROUTES.balanceMovements.path}${qs ? `?${qs}` : ""}`)).data;
|
|
1164
1228
|
}
|
|
1165
1229
|
/**
|
|
1166
|
-
* Liga de MercadoPago para recargar saldo (pago único
|
|
1167
|
-
*
|
|
1230
|
+
* Liga de MercadoPago para recargar saldo (pago único; `amount` en unidades enteras de tu moneda:
|
|
1231
|
+
* MXN 500 a 100,000, USD 29 a 5,500). El saldo sube cuando MercadoPago confirma el pago, no al
|
|
1232
|
+
* crear la liga. Abre `initPoint` en el navegador de quien paga.
|
|
1168
1233
|
*/
|
|
1169
1234
|
async topup(input) {
|
|
1170
1235
|
return (await this.request("POST", PARTNER_ROUTES.topup.path, input)).data;
|
|
1171
1236
|
}
|
|
1237
|
+
/** La recarga automática mensual: `off`, `pending` (falta autorizarla) o `active`. */
|
|
1238
|
+
async autoTopup() {
|
|
1239
|
+
return (await this.request("GET", PARTNER_ROUTES.getAutoTopup.path)).data;
|
|
1240
|
+
}
|
|
1241
|
+
/**
|
|
1242
|
+
* Prende o cambia (`amount` entero de tu moneda) la recarga automática mensual, o la apaga
|
|
1243
|
+
* (`amount: null`). Al prenderla o cambiarla devuelve `initPoint`: ábrelo para autorizar el cobro.
|
|
1244
|
+
*/
|
|
1245
|
+
async setAutoTopup(input) {
|
|
1246
|
+
return (await this.request("PUT", PARTNER_ROUTES.setAutoTopup.path, input)).data;
|
|
1247
|
+
}
|
|
1172
1248
|
/** Uso del mes (`YYYY-MM`, default el mes en curso UTC): tenants activos y envíos. */
|
|
1173
1249
|
async usage(opts = {}) {
|
|
1174
1250
|
const q = opts.month ? `?month=${encodeURIComponent(opts.month)}` : "";
|
|
@@ -1369,10 +1445,18 @@ var MailMaskPartnerAdmin = class {
|
|
|
1369
1445
|
setReputationPolicy(partnerId, policy) {
|
|
1370
1446
|
return this.req("setReputationPolicy", { partnerId }, { policy });
|
|
1371
1447
|
}
|
|
1448
|
+
/** Sólo MailMask (admin): moneda del saldo (MXN o USD); sólo antes de cualquier movimiento aparte de la bienvenida. */
|
|
1449
|
+
setCurrency(partnerId, currency) {
|
|
1450
|
+
return this.req("setCurrency", { partnerId }, { currency });
|
|
1451
|
+
}
|
|
1372
1452
|
/** Sólo MailMask (admin): levanta cualquier pausa, también la de reputación. */
|
|
1373
1453
|
resumeTenant(partnerId, externalId) {
|
|
1374
1454
|
return this.req("resumeTenant", { partnerId, externalId });
|
|
1375
1455
|
}
|
|
1456
|
+
/** Sólo MailMask: tope diario fijo del tenant, o `null` para volver al calentamiento. */
|
|
1457
|
+
setTenantDailyLimit(partnerId, externalId, limit) {
|
|
1458
|
+
return this.req("setTenantDailyLimit", { partnerId, externalId }, { limit });
|
|
1459
|
+
}
|
|
1376
1460
|
/**
|
|
1377
1461
|
* Sólo MailMask (admin): crea o adopta la hosted zone de la zona de respaldo (`marketing.denik.me`)
|
|
1378
1462
|
* y devuelve los NS que el partner tiene que delegar. Idempotente con la misma zona.
|
|
@@ -1392,14 +1476,18 @@ var MailMaskPartnerAdmin = class {
|
|
|
1392
1476
|
adjustBalance(partnerId, input) {
|
|
1393
1477
|
return this.req("adjustBalance", { partnerId }, input);
|
|
1394
1478
|
}
|
|
1395
|
-
/** Sólo MailMask (admin): prende o apaga el cobro por adelantado del partner. */
|
|
1396
|
-
setPrepaidEnforced(partnerId, enforced) {
|
|
1397
|
-
return this.req("setPrepaidEnforced", { partnerId }, { enforced });
|
|
1398
|
-
}
|
|
1399
1479
|
/** Liga de MercadoPago para recargar, con la llave del dueño. */
|
|
1400
1480
|
topup(partnerId, input) {
|
|
1401
1481
|
return this.req("topup", { partnerId }, input);
|
|
1402
1482
|
}
|
|
1483
|
+
/** La recarga automática mensual del partner (dueño o MailMask). */
|
|
1484
|
+
getAutoTopup(partnerId) {
|
|
1485
|
+
return this.req("getAutoTopup", { partnerId });
|
|
1486
|
+
}
|
|
1487
|
+
/** Prende, cambia (`amount`) o apaga (`null`) la recarga automática; trae `initPoint` al prenderla. */
|
|
1488
|
+
setAutoTopup(partnerId, input) {
|
|
1489
|
+
return this.req("setAutoTopup", { partnerId }, input);
|
|
1490
|
+
}
|
|
1403
1491
|
listCredentials(partnerId) {
|
|
1404
1492
|
return this.req("listCredentials", { partnerId });
|
|
1405
1493
|
}
|
|
@@ -1417,11 +1505,13 @@ var MailMaskPartnerAdmin = class {
|
|
|
1417
1505
|
}
|
|
1418
1506
|
};
|
|
1419
1507
|
export {
|
|
1508
|
+
AUTO_TOPUP_SUGGESTIONS,
|
|
1420
1509
|
AuthError,
|
|
1421
1510
|
BALANCE_LOW_FRACTION,
|
|
1422
1511
|
BALANCE_MOVEMENT_KINDS,
|
|
1423
1512
|
ConflictError,
|
|
1424
1513
|
DOMAIN_CLAIM_TTL_DAYS,
|
|
1514
|
+
DailyLimitError,
|
|
1425
1515
|
EXTERNAL_ID_RE,
|
|
1426
1516
|
FALLBACK_LABEL_RE,
|
|
1427
1517
|
ForbiddenError,
|
|
@@ -1440,8 +1530,10 @@ export {
|
|
|
1440
1530
|
NotFoundError,
|
|
1441
1531
|
PARTNER_ADMIN_ROUTES,
|
|
1442
1532
|
PARTNER_API_PREFIX,
|
|
1533
|
+
PARTNER_CURRENCIES,
|
|
1443
1534
|
PARTNER_ERROR_STATUS,
|
|
1444
1535
|
PARTNER_HEADERS,
|
|
1536
|
+
PARTNER_PRICES,
|
|
1445
1537
|
PARTNER_PRICE_PER_EMAIL_CENTS,
|
|
1446
1538
|
PARTNER_ROUTES,
|
|
1447
1539
|
PARTNER_SIGNATURE_TOLERANCE_S,
|
|
@@ -1449,6 +1541,7 @@ export {
|
|
|
1449
1541
|
PARTNER_TOPUP_MAX_CENTS,
|
|
1450
1542
|
PARTNER_TOPUP_MIN_CENTS,
|
|
1451
1543
|
PARTNER_WEBHOOK_EVENTS,
|
|
1544
|
+
PARTNER_WELCOME_CENTS,
|
|
1452
1545
|
PartnerApiError,
|
|
1453
1546
|
PausedError,
|
|
1454
1547
|
QuotaError,
|
|
@@ -1459,12 +1552,17 @@ export {
|
|
|
1459
1552
|
STRICT_FIRST_DAYS,
|
|
1460
1553
|
TAG_RE,
|
|
1461
1554
|
TEMPLATE_VAR_NAME_RE,
|
|
1555
|
+
TENANT_DAILY_LIMIT_MAX,
|
|
1556
|
+
TENANT_DAILY_LIMIT_START,
|
|
1557
|
+
TENANT_WARMUP_STEP_DAYS,
|
|
1462
1558
|
TimeoutError,
|
|
1463
1559
|
UNSUBSCRIBE_URL_VAR,
|
|
1464
1560
|
ValidationError,
|
|
1465
1561
|
WEBHOOK_HEADERS,
|
|
1466
1562
|
WEBHOOK_TOLERANCE_MS,
|
|
1467
1563
|
createWebhookHandler,
|
|
1564
|
+
estimateSendDays,
|
|
1565
|
+
formatMoney,
|
|
1468
1566
|
isValidExternalId,
|
|
1469
1567
|
isValidFallbackLabel,
|
|
1470
1568
|
partnerSignatureBase,
|
|
@@ -1477,5 +1575,6 @@ export {
|
|
|
1477
1575
|
templateVarsProblem,
|
|
1478
1576
|
verifyWebhook,
|
|
1479
1577
|
verifyWebhookSignature,
|
|
1578
|
+
warmupLimit,
|
|
1480
1579
|
webhookSignatureBase
|
|
1481
1580
|
};
|
|
@@ -60,11 +60,16 @@ export declare const PARTNER_ERROR_STATUS: {
|
|
|
60
60
|
/** El tenant está en pausa (por MailMask o por el partner). No se manda nada hasta `resume`. */
|
|
61
61
|
readonly tenant_paused: 423;
|
|
62
62
|
/**
|
|
63
|
-
* Saldo prepagado insuficiente (con `balanceCents` y `requiredCents`).
|
|
64
|
-
*
|
|
63
|
+
* Saldo prepagado insuficiente (con `balanceCents` y `requiredCents`). No se reintenta: recarga
|
|
64
|
+
* con `POST /topup`.
|
|
65
65
|
*/
|
|
66
66
|
readonly insufficient_balance: 402;
|
|
67
|
-
/**
|
|
67
|
+
/**
|
|
68
|
+
* El tenant llegó a su límite del día (con `limit`, `sentToday` y `resetsAt`, la medianoche UTC).
|
|
69
|
+
* Sólo en envíos sueltos: un lote no falla, espera al día siguiente (`batch.throttled`).
|
|
70
|
+
*/
|
|
71
|
+
readonly daily_limit: 429;
|
|
72
|
+
/** Ya no sale desde la 0.8 (no hay tope mensual); se deja para clientes viejos. */
|
|
68
73
|
readonly quota_exceeded: 429;
|
|
69
74
|
/** Demasiadas peticiones; reintenta tras `Retry-After`. */
|
|
70
75
|
readonly rate_limited: 429;
|
|
@@ -77,12 +82,15 @@ export interface PartnerErrorBody {
|
|
|
77
82
|
code: PartnerErrorCode;
|
|
78
83
|
/** Sólo en `invalid_request`: el campo que falló, si aplica. */
|
|
79
84
|
field?: string;
|
|
80
|
-
/** Sólo en `
|
|
85
|
+
/** Sólo en `daily_limit`: el límite de hoy, lo enviado y cuándo se reinicia (medianoche UTC). */
|
|
81
86
|
limit?: number;
|
|
87
|
+
sentToday?: number;
|
|
82
88
|
resetsAt?: string;
|
|
83
|
-
/** Sólo en `insufficient_balance`: saldo actual y lo que pedía el envío (centavos
|
|
89
|
+
/** Sólo en `insufficient_balance`: saldo actual y lo que pedía el envío (centavos de `currency`). */
|
|
84
90
|
balanceCents?: number;
|
|
85
91
|
requiredCents?: number;
|
|
92
|
+
/** Moneda de `balanceCents` y `requiredCents`. */
|
|
93
|
+
currency?: PartnerCurrency;
|
|
86
94
|
/** Sólo en `recipient_suppressed`. */
|
|
87
95
|
reason?: SuppressionReason;
|
|
88
96
|
stream?: MessageStream;
|
|
@@ -112,7 +120,38 @@ export interface Tenant {
|
|
|
112
120
|
lastSendAt: string | null;
|
|
113
121
|
createdAt: string;
|
|
114
122
|
updatedAt: string;
|
|
123
|
+
/** Límite diario con calentamiento. Ver `TenantSending`. */
|
|
124
|
+
sending: TenantSending;
|
|
115
125
|
}
|
|
126
|
+
/**
|
|
127
|
+
* Límite diario por tenant que crece solo, como el calentamiento de SES: empieza en
|
|
128
|
+
* `TENANT_DAILY_LIMIT_START` al primer envío y se duplica cada `TENANT_WARMUP_STEP_DAYS` días sanos
|
|
129
|
+
* (rebotes < 2 %, quejas < 0.1 %) hasta `TENANT_DAILY_LIMIT_MAX`. Una pausa por reputación lo
|
|
130
|
+
* regresa al inicio al reanudar. No hay tope mensual: el saldo es el otro freno.
|
|
131
|
+
*/
|
|
132
|
+
export declare const TENANT_DAILY_LIMIT_START = 2000;
|
|
133
|
+
export declare const TENANT_DAILY_LIMIT_MAX = 20000;
|
|
134
|
+
export declare const TENANT_WARMUP_STEP_DAYS = 7;
|
|
135
|
+
/** El límite del escalón `step` (0 = inicio). */
|
|
136
|
+
export declare function warmupLimit(step: number): number;
|
|
137
|
+
export interface TenantSending {
|
|
138
|
+
/** Correos que puede mandar hoy (UTC) en total. */
|
|
139
|
+
dailyLimit: number;
|
|
140
|
+
sentToday: number;
|
|
141
|
+
/** Medianoche UTC siguiente. */
|
|
142
|
+
resetsAt: string;
|
|
143
|
+
/** Cuándo sube al siguiente escalón si sigue sano; null = ya en el máximo, con tope fijo o sin envíos aún. */
|
|
144
|
+
nextStepAt: string | null;
|
|
145
|
+
/** El límite que tendrá en `nextStepAt`; null si no sube. */
|
|
146
|
+
nextStepLimit: number | null;
|
|
147
|
+
/** true = MailMask fijó el límite a mano (no se calienta). */
|
|
148
|
+
fixed: boolean;
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Días (contando hoy) que tarda en salir un lote de `recipients` correos si los escalones llegan a
|
|
152
|
+
* tiempo. 1 = sale hoy. Sirve para avisar «se manda en N días» antes de encolar.
|
|
153
|
+
*/
|
|
154
|
+
export declare function estimateSendDays(s: TenantSending, recipients: number): number;
|
|
116
155
|
/** `PUT /tenants/:externalId` — crea o actualiza. 201 si lo creó, 200 si ya existía. */
|
|
117
156
|
export interface PutTenantRequest {
|
|
118
157
|
name?: string;
|
|
@@ -351,6 +390,11 @@ export interface BatchStatus {
|
|
|
351
390
|
lastError: string | null;
|
|
352
391
|
createdAt: string;
|
|
353
392
|
completedAt: string | null;
|
|
393
|
+
/**
|
|
394
|
+
* El lote llegó al límite diario del tenant y sigue solo a esta hora (medianoche UTC); null si no
|
|
395
|
+
* está esperando por el límite. Mientras espera, el lote no caduca.
|
|
396
|
+
*/
|
|
397
|
+
waitingUntil: string | null;
|
|
354
398
|
/**
|
|
355
399
|
* Sólo en modo de prueba: el lote se valida y responde `completed` al instante (los suprimidos en
|
|
356
400
|
* `skippedSuppressed`, el resto en `sent`), con `batchId` `test_…` que no se guarda (su GET da 404).
|
|
@@ -368,6 +412,8 @@ export interface TenantUsage {
|
|
|
368
412
|
bounced: number;
|
|
369
413
|
complained: number;
|
|
370
414
|
unsubscribed: number;
|
|
415
|
+
/** Límite diario de hoy; falta si el tenant ya se borró. */
|
|
416
|
+
sending?: TenantSending;
|
|
371
417
|
}
|
|
372
418
|
/** `GET /usage?month=YYYY-MM` (default: el mes en curso, UTC). Activo = al menos un envío en el mes. */
|
|
373
419
|
export interface UsageResponse {
|
|
@@ -378,18 +424,37 @@ export interface UsageResponse {
|
|
|
378
424
|
}
|
|
379
425
|
/**
|
|
380
426
|
* El partner paga por adelantado: cada correo y la cuota mensual de cada tenant activo se
|
|
381
|
-
* descuentan de un saldo que se recarga con MercadoPago (`POST /topup`).
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
/**
|
|
386
|
-
* Cuota mensual por tenant activo. Activo = envía ese mes: se descuenta con su primer envío del
|
|
387
|
-
* mes (UTC), una sola vez, así que un tenant dormido no cuesta nada.
|
|
427
|
+
* descuentan de un saldo que se recarga con MercadoPago (`POST /topup`). El saldo es en la moneda
|
|
428
|
+
* del partner (MXN o USD) y es la única unidad: no hay «créditos». Todos los montos `*Cents` son
|
|
429
|
+
* centavos de esa moneda y pueden traer decimales (en USD un correo cuesta 0.35 centavos; por
|
|
430
|
+
* dentro se lleva en milésimas de centavo). Se muestran con 2 decimales.
|
|
388
431
|
*/
|
|
389
|
-
export
|
|
390
|
-
|
|
391
|
-
export
|
|
392
|
-
|
|
432
|
+
export type PartnerCurrency = "MXN" | "USD";
|
|
433
|
+
export declare const PARTNER_CURRENCIES: readonly PartnerCurrency[];
|
|
434
|
+
export interface PartnerPrices {
|
|
435
|
+
/** Por correo enviado (por destinatario). */
|
|
436
|
+
perEmailCents: number;
|
|
437
|
+
/**
|
|
438
|
+
* Cuota mensual por tenant activo. Activo = envía ese mes: se descuenta con su primer envío del
|
|
439
|
+
* mes (UTC), una sola vez, así que un tenant dormido no cuesta nada.
|
|
440
|
+
*/
|
|
441
|
+
tenantMonthCents: number;
|
|
442
|
+
/** Saldo de bienvenida con el que nace el partner (`adjust`, idemKey `welcome:<partnerId>`). */
|
|
443
|
+
welcomeCents: number;
|
|
444
|
+
/** Recarga mínima y máxima por pago (enteros de la moneda × 100). */
|
|
445
|
+
topupMinCents: number;
|
|
446
|
+
topupMaxCents: number;
|
|
447
|
+
}
|
|
448
|
+
/** Precios por moneda. USD = MXN redondeado; se cobra en MXN por MercadoPago con el tipo de cambio. */
|
|
449
|
+
export declare const PARTNER_PRICES: Record<PartnerCurrency, PartnerPrices>;
|
|
450
|
+
/** Los de MXN, con su nombre de antes (0.7). */
|
|
451
|
+
export declare const PARTNER_PRICE_PER_EMAIL_CENTS: number;
|
|
452
|
+
export declare const PARTNER_TENANT_MONTH_CENTS: number;
|
|
453
|
+
export declare const PARTNER_WELCOME_CENTS: number;
|
|
454
|
+
export declare const PARTNER_TOPUP_MIN_CENTS: number;
|
|
455
|
+
export declare const PARTNER_TOPUP_MAX_CENTS: number;
|
|
456
|
+
/** `$1,234.50 USD`: 2 decimales (4 si el monto es menor a un centavo, como el precio por correo en USD). */
|
|
457
|
+
export declare function formatMoney(cents: number, currency: PartnerCurrency): string;
|
|
393
458
|
/** `balance.low` sale cuando el saldo baja del 20 % de la última recarga (una vez por recarga). */
|
|
394
459
|
export declare const BALANCE_LOW_FRACTION = 0.2;
|
|
395
460
|
export type BalanceMovementKind = "topup" | "send" | "tenant_fee" | "refund" | "adjust";
|
|
@@ -409,18 +474,11 @@ export interface BalanceMovement {
|
|
|
409
474
|
}
|
|
410
475
|
/** `GET /balance` */
|
|
411
476
|
export interface BalanceResponse {
|
|
412
|
-
|
|
477
|
+
/** La moneda del saldo y de todos los montos de esta respuesta. */
|
|
478
|
+
currency: PartnerCurrency;
|
|
479
|
+
/** Sin saldo suficiente el envío se rechaza (402 `insufficient_balance`) y el lote espera. Siempre. */
|
|
413
480
|
balanceCents: number;
|
|
414
|
-
|
|
415
|
-
* true = sin saldo suficiente los envíos se rechazan (402 `insufficient_balance`) y los lotes
|
|
416
|
-
* esperan. false = el saldo se lleva igual (puede quedar negativo) pero no frena nada.
|
|
417
|
-
*/
|
|
418
|
-
enforced: boolean;
|
|
419
|
-
prices: {
|
|
420
|
-
perEmailCents: number;
|
|
421
|
-
tenantMonthCents: number;
|
|
422
|
-
topupMinCents: number;
|
|
423
|
-
};
|
|
481
|
+
prices: PartnerPrices;
|
|
424
482
|
lastTopup: {
|
|
425
483
|
amountCents: number;
|
|
426
484
|
at: string;
|
|
@@ -429,7 +487,7 @@ export interface BalanceResponse {
|
|
|
429
487
|
lowBalanceThresholdCents: number | null;
|
|
430
488
|
/** Mes en curso (UTC). */
|
|
431
489
|
month: string;
|
|
432
|
-
/** Tenants
|
|
490
|
+
/** Tenants que enviaron este mes (la misma cuenta que `/usage`): cada uno paga la cuota del mes. */
|
|
433
491
|
activeTenants: number;
|
|
434
492
|
/** Correos cobrados en el mes (sin los devueltos). */
|
|
435
493
|
monthEmails: number;
|
|
@@ -444,6 +502,8 @@ export interface BalanceMovementsQuery {
|
|
|
444
502
|
kind?: BalanceMovementKind[];
|
|
445
503
|
}
|
|
446
504
|
export interface BalanceMovementsResponse {
|
|
505
|
+
/** La moneda de los montos. */
|
|
506
|
+
currency: PartnerCurrency;
|
|
447
507
|
movements: BalanceMovement[];
|
|
448
508
|
nextCursor: string | null;
|
|
449
509
|
}
|
|
@@ -452,37 +512,89 @@ export interface BalanceMovementsResponse {
|
|
|
452
512
|
* el pago (webhook), no al crear la liga. `returnUrl` (https) es a dónde regresa el navegador.
|
|
453
513
|
*/
|
|
454
514
|
export interface TopupRequest {
|
|
455
|
-
/**
|
|
456
|
-
|
|
515
|
+
/**
|
|
516
|
+
* Unidades enteras de la moneda del partner (MXN: 500 a 100,000; USD: 29 a 5,500). En USD
|
|
517
|
+
* MercadoPago cobra el equivalente en MXN con el tipo de cambio de MailMask y se abona lo pedido
|
|
518
|
+
* en USD.
|
|
519
|
+
*/
|
|
520
|
+
amount?: number;
|
|
521
|
+
/** Lo mismo que `amount`, sólo para partners en MXN (0.7). */
|
|
522
|
+
amountMxn?: number;
|
|
457
523
|
returnUrl?: string;
|
|
458
524
|
}
|
|
459
525
|
export interface TopupResponse {
|
|
460
526
|
topupId: string;
|
|
527
|
+
/** Lo que se abona al saldo, en la moneda del partner. */
|
|
461
528
|
amountCents: number;
|
|
529
|
+
currency: PartnerCurrency;
|
|
530
|
+
/** Lo que cobra MercadoPago, en centavos MXN (igual a `amountCents` si el partner es MXN). */
|
|
531
|
+
chargeMxnCents: number;
|
|
532
|
+
/** MXN por USD con que se cotizó; null en MXN. */
|
|
533
|
+
fxRate: number | null;
|
|
462
534
|
/** Abre esto en el navegador de quien paga. */
|
|
463
535
|
initPoint: string;
|
|
464
536
|
}
|
|
537
|
+
/**
|
|
538
|
+
* Recarga automática mensual: un cobro de MercadoPago cada mes (preapproval con la tarjeta del
|
|
539
|
+
* dueño) que abona `amountCents` al saldo con nota «Recarga automática». En USD MercadoPago cobra
|
|
540
|
+
* `chargeMxnCents` (fijado al activarla) y se abona lo elegido en USD.
|
|
541
|
+
*/
|
|
542
|
+
export interface AutoTopup {
|
|
543
|
+
/** off = apagada; pending = falta autorizarla en MercadoPago (`initPoint`); active = cobra cada mes. */
|
|
544
|
+
status: "off" | "pending" | "active";
|
|
545
|
+
currency: PartnerCurrency;
|
|
546
|
+
amountCents: number | null;
|
|
547
|
+
chargeMxnCents: number | null;
|
|
548
|
+
nextChargeAt: string | null;
|
|
549
|
+
lastChargeAt: string | null;
|
|
550
|
+
/** Cobros rechazados seguidos (se reinicia con uno aprobado). */
|
|
551
|
+
failedCharges: number;
|
|
552
|
+
lastError: string | null;
|
|
553
|
+
/** Sólo en la respuesta de prenderla o cambiarla: ábrelo para autorizar el cobro mensual. */
|
|
554
|
+
initPoint?: string;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* `PUT /auto-topup` — `amount` en unidades enteras de la moneda (mismo rango que `/topup`) la prende
|
|
558
|
+
* o cambia (cancela la anterior y crea otra); `null` la apaga.
|
|
559
|
+
*/
|
|
560
|
+
export interface SetAutoTopupRequest {
|
|
561
|
+
amount: number | null;
|
|
562
|
+
returnUrl?: string;
|
|
563
|
+
}
|
|
564
|
+
/** Montos sugeridos para la recarga automática (unidades enteras). */
|
|
565
|
+
export declare const AUTO_TOPUP_SUGGESTIONS: Record<PartnerCurrency, readonly number[]>;
|
|
465
566
|
/**
|
|
466
567
|
* `GET /api/partners/:partnerId/balance` (dueño o MailMask): el saldo, sus últimos 20 movimientos,
|
|
467
568
|
* el partner (con `tenants` y `ownerEmail`) y si quien mira es de MailMask (ve abonar y el cobro).
|
|
468
569
|
*/
|
|
570
|
+
/** Un tenant en la ficha: los 50 que enviaron más recientemente, con su límite de hoy. */
|
|
571
|
+
export interface PartnerDetailTenant {
|
|
572
|
+
externalId: string;
|
|
573
|
+
name: string | null;
|
|
574
|
+
status: TenantStatus;
|
|
575
|
+
lastSendAt: string | null;
|
|
576
|
+
sending: TenantSending;
|
|
577
|
+
}
|
|
469
578
|
export type PartnerBalanceDetail = BalanceResponse & {
|
|
470
579
|
movements: BalanceMovement[];
|
|
471
580
|
partner: PartnerSummary;
|
|
581
|
+
tenants: PartnerDetailTenant[];
|
|
582
|
+
/** La recarga automática mensual. */
|
|
583
|
+
autoTopup: AutoTopup;
|
|
472
584
|
staff: boolean;
|
|
473
585
|
};
|
|
586
|
+
/** `PUT /api/partners/:partnerId/tenants/:externalId/daily-limit` — sólo MailMask: tope fijo o `null` (vuelve al calentamiento). */
|
|
587
|
+
export interface SetTenantDailyLimitRequest {
|
|
588
|
+
limit: number | null;
|
|
589
|
+
}
|
|
474
590
|
/** `POST /api/partners/:partnerId/balance/adjust` — sólo MailMask (admin): abono o cargo manual. */
|
|
475
591
|
export interface AdjustBalanceRequest {
|
|
476
|
-
/** Centavos
|
|
592
|
+
/** Centavos enteros de la moneda del partner, distinto de 0 (negativo = cargo). */
|
|
477
593
|
amountCents: number;
|
|
478
594
|
note: string;
|
|
479
595
|
/** Repetir con la misma llave no vuelve a abonar. */
|
|
480
596
|
idempotencyKey?: string;
|
|
481
597
|
}
|
|
482
|
-
/** `PUT /api/partners/:partnerId/prepaid` — sólo MailMask (admin): prende o apaga el cobro por adelantado. */
|
|
483
|
-
export interface SetPrepaidEnforcedRequest {
|
|
484
|
-
enforced: boolean;
|
|
485
|
-
}
|
|
486
598
|
/** `GET /webhook` */
|
|
487
599
|
export interface WebhookConfig {
|
|
488
600
|
url: string | null;
|
|
@@ -516,7 +628,7 @@ export interface RotateWebhookSecretResponse {
|
|
|
516
628
|
export interface TestWebhookResponse {
|
|
517
629
|
deliveryId: string;
|
|
518
630
|
}
|
|
519
|
-
export declare const PARTNER_WEBHOOK_EVENTS: readonly ["email.sent", "email.delivered", "email.bounced", "email.complained", "email.received", "contact.unsubscribed", "tenant.paused", "tenant.resumed", "domain.verified", "balance.low"];
|
|
631
|
+
export declare const PARTNER_WEBHOOK_EVENTS: readonly ["email.sent", "email.delivered", "email.bounced", "email.complained", "email.received", "contact.unsubscribed", "tenant.paused", "tenant.resumed", "domain.verified", "balance.low", "batch.throttled"];
|
|
520
632
|
export type PartnerWebhookEvent = typeof PARTNER_WEBHOOK_EVENTS[number];
|
|
521
633
|
/** Headers de cada entrega al webhook del partner (los mismos que los webhooks de dominio). */
|
|
522
634
|
export declare const WEBHOOK_HEADERS: {
|
|
@@ -599,6 +711,15 @@ export interface PartnerEventData {
|
|
|
599
711
|
balanceCents: number;
|
|
600
712
|
thresholdCents: number;
|
|
601
713
|
lastTopupCents: number;
|
|
714
|
+
currency: PartnerCurrency;
|
|
715
|
+
};
|
|
716
|
+
/** Un lote llegó al límite diario del tenant: sigue solo en `resumesAt`. Una vez por lote. */
|
|
717
|
+
"batch.throttled": {
|
|
718
|
+
batchId: string;
|
|
719
|
+
sent: number;
|
|
720
|
+
total: number;
|
|
721
|
+
dailyLimit: number;
|
|
722
|
+
resumesAt: string;
|
|
602
723
|
};
|
|
603
724
|
ping: Record<string, never>;
|
|
604
725
|
}
|
|
@@ -623,6 +744,7 @@ export declare const STRICT_FIRST_DAYS = 30;
|
|
|
623
744
|
export interface PartnerSummary {
|
|
624
745
|
id: string;
|
|
625
746
|
name: string;
|
|
747
|
+
/** `sendsPerTenantMonth` ya no frena (0.8): el límite es diario por tenant, ver `TenantSending`. */
|
|
626
748
|
plan: {
|
|
627
749
|
includedTenants: number;
|
|
628
750
|
sendsPerTenantMonth: number;
|
|
@@ -636,9 +758,9 @@ export interface PartnerSummary {
|
|
|
636
758
|
effectiveReputationPolicy: ReputationPolicy;
|
|
637
759
|
/** Zona de respaldo (`marketing.denik.me`); null = sin zona. Ver `FallbackZone`. */
|
|
638
760
|
fallbackZone: string | null;
|
|
639
|
-
/** Saldo prepagado
|
|
761
|
+
/** Saldo prepagado, en centavos de `currency`. Ver `BalanceResponse`. */
|
|
640
762
|
balanceCents: number;
|
|
641
|
-
|
|
763
|
+
currency: PartnerCurrency;
|
|
642
764
|
/** Sólo en `GET /api/partners?all=1` (MailMask, admin): tenants totales y activos del mes. */
|
|
643
765
|
tenants?: {
|
|
644
766
|
total: number;
|
|
@@ -654,6 +776,15 @@ export interface CreatePartnerRequest {
|
|
|
654
776
|
ownerEmail: string;
|
|
655
777
|
plan?: Partial<PartnerSummary["plan"]>;
|
|
656
778
|
reputationPolicy?: ReputationPolicy | null;
|
|
779
|
+
/** Moneda del saldo; default MXN. Nace con la bienvenida de esa moneda. */
|
|
780
|
+
currency?: PartnerCurrency;
|
|
781
|
+
}
|
|
782
|
+
/**
|
|
783
|
+
* `PUT /api/partners/:partnerId/currency` — sólo MailMask, y sólo mientras el partner no tenga más
|
|
784
|
+
* movimientos que la bienvenida (que se cambia por la de la nueva moneda).
|
|
785
|
+
*/
|
|
786
|
+
export interface SetPartnerCurrencyRequest {
|
|
787
|
+
currency: PartnerCurrency;
|
|
657
788
|
}
|
|
658
789
|
/** `PUT /api/partners/:partnerId/reputation-policy` — sólo MailMask (admin); null = automática. */
|
|
659
790
|
export interface SetReputationPolicyRequest {
|
|
@@ -773,6 +904,14 @@ export declare const PARTNER_ROUTES: {
|
|
|
773
904
|
readonly method: "POST";
|
|
774
905
|
readonly path: "/topup";
|
|
775
906
|
};
|
|
907
|
+
readonly getAutoTopup: {
|
|
908
|
+
readonly method: "GET";
|
|
909
|
+
readonly path: "/auto-topup";
|
|
910
|
+
};
|
|
911
|
+
readonly setAutoTopup: {
|
|
912
|
+
readonly method: "PUT";
|
|
913
|
+
readonly path: "/auto-topup";
|
|
914
|
+
};
|
|
776
915
|
readonly getWebhook: {
|
|
777
916
|
readonly method: "GET";
|
|
778
917
|
readonly path: "/webhook";
|
|
@@ -829,16 +968,29 @@ export declare const PARTNER_ADMIN_ROUTES: {
|
|
|
829
968
|
readonly method: "POST";
|
|
830
969
|
readonly path: "/api/partners/:partnerId/balance/adjust";
|
|
831
970
|
};
|
|
832
|
-
/** Sólo MailMask (admin): prende o apaga el cobro por adelantado. */
|
|
833
|
-
readonly setPrepaidEnforced: {
|
|
834
|
-
readonly method: "PUT";
|
|
835
|
-
readonly path: "/api/partners/:partnerId/prepaid";
|
|
836
|
-
};
|
|
837
971
|
/** Recarga con MercadoPago desde la sesión del dueño (misma respuesta que `POST /topup`). */
|
|
838
972
|
readonly topup: {
|
|
839
973
|
readonly method: "POST";
|
|
840
974
|
readonly path: "/api/partners/:partnerId/topup";
|
|
841
975
|
};
|
|
976
|
+
readonly getAutoTopup: {
|
|
977
|
+
readonly method: "GET";
|
|
978
|
+
readonly path: "/api/partners/:partnerId/auto-topup";
|
|
979
|
+
};
|
|
980
|
+
readonly setAutoTopup: {
|
|
981
|
+
readonly method: "PUT";
|
|
982
|
+
readonly path: "/api/partners/:partnerId/auto-topup";
|
|
983
|
+
};
|
|
984
|
+
/** Sólo MailMask: moneda del saldo, mientras no haya más movimientos que la bienvenida. */
|
|
985
|
+
readonly setCurrency: {
|
|
986
|
+
readonly method: "PUT";
|
|
987
|
+
readonly path: "/api/partners/:partnerId/currency";
|
|
988
|
+
};
|
|
989
|
+
/** Sólo MailMask: fija (o quita, con `null`) el límite diario de un tenant. Devuelve el `Tenant`. */
|
|
990
|
+
readonly setTenantDailyLimit: {
|
|
991
|
+
readonly method: "PUT";
|
|
992
|
+
readonly path: "/api/partners/:partnerId/tenants/:externalId/daily-limit";
|
|
993
|
+
};
|
|
842
994
|
readonly listCredentials: {
|
|
843
995
|
readonly method: "GET";
|
|
844
996
|
readonly path: "/api/partners/:partnerId/credentials";
|
package/dist/partner.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { MailMaskError } from "./client.js";
|
|
2
|
-
import type { TemplateVars, PartnerSummary, CreatePartnerRequest, ReputationPolicy, ListCredentialsResponse, CreateCredentialRequest, CreateCredentialResponse, RotateCredentialRequest, RotateCredentialResponse, RevokeCredentialResponse, PartnerErrorBody, PartnerErrorCode, Tenant, PutTenantRequest, ListTenantsQuery, ListTenantsResponse, DeleteTenantResponse, PartnerDomain, SendRequest, SendResponse, BatchRequest, BatchStatus, UsageResponse, WebhookConfig, SetWebhookRequest, SetWebhookResponse, TestWebhookResponse, PartnerWebhookPayload, RotateWebhookSecretRequest, RotateWebhookSecretResponse, MessageStream, SuppressionReason, FallbackZone, BalanceResponse, BalanceMovementsQuery, BalanceMovementsResponse, TopupRequest, TopupResponse, PartnerBalanceDetail, AdjustBalanceRequest } from "./partner-contract.js";
|
|
2
|
+
import type { TemplateVars, PartnerSummary, CreatePartnerRequest, ReputationPolicy, ListCredentialsResponse, CreateCredentialRequest, CreateCredentialResponse, RotateCredentialRequest, RotateCredentialResponse, RevokeCredentialResponse, PartnerErrorBody, PartnerErrorCode, Tenant, PutTenantRequest, ListTenantsQuery, ListTenantsResponse, DeleteTenantResponse, PartnerDomain, SendRequest, SendResponse, BatchRequest, BatchStatus, UsageResponse, WebhookConfig, SetWebhookRequest, SetWebhookResponse, TestWebhookResponse, PartnerWebhookPayload, RotateWebhookSecretRequest, RotateWebhookSecretResponse, MessageStream, SuppressionReason, FallbackZone, BalanceResponse, BalanceMovementsQuery, BalanceMovementsResponse, TopupRequest, TopupResponse, PartnerBalanceDetail, AdjustBalanceRequest, PartnerCurrency, AutoTopup, SetAutoTopupRequest } from "./partner-contract.js";
|
|
3
3
|
export * from "./partner-contract.js";
|
|
4
4
|
/**
|
|
5
5
|
* Discriminante estable de los errores de partners, para un `switch` sin cadenas de `instanceof`.
|
|
6
6
|
* `network` y `timeout` llevan `status` 0 (no hubo respuesta); `unknown` es un status que el
|
|
7
7
|
* contrato no define (p. ej. un 400 de un proxy).
|
|
8
8
|
*/
|
|
9
|
-
export type PartnerErrorKind = "auth" | "forbidden" | "reputation_hold" | "not_found" | "conflict" | "validation" | "suppressed" | "paused" | "quota" | "insufficient_balance" | "rate_limit" | "server" | "network" | "timeout" | "unknown";
|
|
9
|
+
export type PartnerErrorKind = "auth" | "forbidden" | "reputation_hold" | "not_found" | "conflict" | "validation" | "suppressed" | "paused" | "quota" | "daily_limit" | "insufficient_balance" | "rate_limit" | "server" | "network" | "timeout" | "unknown";
|
|
10
10
|
/** Metadatos de la respuesta que no vienen en el cuerpo. */
|
|
11
11
|
export interface PartnerErrorMeta {
|
|
12
12
|
requestId?: string;
|
|
@@ -101,14 +101,25 @@ export declare class RateLimitError extends QuotaError {
|
|
|
101
101
|
kind: PartnerErrorKind;
|
|
102
102
|
}
|
|
103
103
|
/**
|
|
104
|
-
*
|
|
105
|
-
*
|
|
104
|
+
* 429 `daily_limit`: el tenant llegó a su límite del día (crece solo con buena reputación). NO se
|
|
105
|
+
* reintenta: vuelve a intentar después de `resetsAt` (medianoche UTC) o manda un `batch`, que espera
|
|
106
|
+
* solo. Trae `limit` y `sentToday`.
|
|
107
|
+
*/
|
|
108
|
+
export declare class DailyLimitError extends QuotaError {
|
|
109
|
+
name: string;
|
|
110
|
+
kind: PartnerErrorKind;
|
|
111
|
+
get sentToday(): number | undefined;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* 402 `insufficient_balance`: el saldo prepagado no alcanza. No se reintenta: recarga con `partner.topup()`. Trae `balanceCents`, `requiredCents` y `currency`.
|
|
106
115
|
*/
|
|
107
116
|
export declare class InsufficientBalanceError extends PartnerApiError {
|
|
108
117
|
name: string;
|
|
109
118
|
kind: PartnerErrorKind;
|
|
110
119
|
get balanceCents(): number | undefined;
|
|
111
120
|
get requiredCents(): number | undefined;
|
|
121
|
+
/** Moneda de los dos montos de arriba. */
|
|
122
|
+
get currency(): PartnerCurrency | undefined;
|
|
112
123
|
}
|
|
113
124
|
/** No hubo respuesta: DNS, conexión rechazada o cortada. `status` 0. */
|
|
114
125
|
export declare class NetworkError extends PartnerApiError {
|
|
@@ -233,10 +244,18 @@ export declare class MailMaskPartner {
|
|
|
233
244
|
/** Movimientos del saldo, del más nuevo al más viejo; pagina con `nextCursor`. */
|
|
234
245
|
balanceMovements(query?: BalanceMovementsQuery): Promise<BalanceMovementsResponse>;
|
|
235
246
|
/**
|
|
236
|
-
* Liga de MercadoPago para recargar saldo (pago único
|
|
237
|
-
*
|
|
247
|
+
* Liga de MercadoPago para recargar saldo (pago único; `amount` en unidades enteras de tu moneda:
|
|
248
|
+
* MXN 500 a 100,000, USD 29 a 5,500). El saldo sube cuando MercadoPago confirma el pago, no al
|
|
249
|
+
* crear la liga. Abre `initPoint` en el navegador de quien paga.
|
|
238
250
|
*/
|
|
239
251
|
topup(input: TopupRequest): Promise<TopupResponse>;
|
|
252
|
+
/** La recarga automática mensual: `off`, `pending` (falta autorizarla) o `active`. */
|
|
253
|
+
autoTopup(): Promise<AutoTopup>;
|
|
254
|
+
/**
|
|
255
|
+
* Prende o cambia (`amount` entero de tu moneda) la recarga automática mensual, o la apaga
|
|
256
|
+
* (`amount: null`). Al prenderla o cambiarla devuelve `initPoint`: ábrelo para autorizar el cobro.
|
|
257
|
+
*/
|
|
258
|
+
setAutoTopup(input: SetAutoTopupRequest): Promise<AutoTopup>;
|
|
240
259
|
/** Uso del mes (`YYYY-MM`, default el mes en curso UTC): tenants activos y envíos. */
|
|
241
260
|
usage(opts?: {
|
|
242
261
|
month?: string;
|
|
@@ -371,8 +390,12 @@ export declare class MailMaskPartnerAdmin {
|
|
|
371
390
|
createPartner(input: CreatePartnerRequest): Promise<PartnerSummary>;
|
|
372
391
|
/** Sólo MailMask (admin); null = automática (Strict el primer mes, Standard después). */
|
|
373
392
|
setReputationPolicy(partnerId: string, policy: ReputationPolicy | null): Promise<PartnerSummary>;
|
|
393
|
+
/** Sólo MailMask (admin): moneda del saldo (MXN o USD); sólo antes de cualquier movimiento aparte de la bienvenida. */
|
|
394
|
+
setCurrency(partnerId: string, currency: PartnerCurrency): Promise<PartnerSummary>;
|
|
374
395
|
/** Sólo MailMask (admin): levanta cualquier pausa, también la de reputación. */
|
|
375
396
|
resumeTenant(partnerId: string, externalId: string): Promise<Tenant>;
|
|
397
|
+
/** Sólo MailMask: tope diario fijo del tenant, o `null` para volver al calentamiento. */
|
|
398
|
+
setTenantDailyLimit(partnerId: string, externalId: string, limit: number | null): Promise<Tenant>;
|
|
376
399
|
/**
|
|
377
400
|
* Sólo MailMask (admin): crea o adopta la hosted zone de la zona de respaldo (`marketing.denik.me`)
|
|
378
401
|
* y devuelve los NS que el partner tiene que delegar. Idempotente con la misma zona.
|
|
@@ -384,10 +407,12 @@ export declare class MailMaskPartnerAdmin {
|
|
|
384
407
|
getBalance(partnerId: string): Promise<PartnerBalanceDetail>;
|
|
385
408
|
/** Sólo MailMask (admin): abono (o cargo, negativo) manual. Con la misma `idempotencyKey` no se repite. */
|
|
386
409
|
adjustBalance(partnerId: string, input: AdjustBalanceRequest): Promise<PartnerBalanceDetail>;
|
|
387
|
-
/** Sólo MailMask (admin): prende o apaga el cobro por adelantado del partner. */
|
|
388
|
-
setPrepaidEnforced(partnerId: string, enforced: boolean): Promise<PartnerSummary>;
|
|
389
410
|
/** Liga de MercadoPago para recargar, con la llave del dueño. */
|
|
390
411
|
topup(partnerId: string, input: TopupRequest): Promise<TopupResponse>;
|
|
412
|
+
/** La recarga automática mensual del partner (dueño o MailMask). */
|
|
413
|
+
getAutoTopup(partnerId: string): Promise<AutoTopup>;
|
|
414
|
+
/** Prende, cambia (`amount`) o apaga (`null`) la recarga automática; trae `initPoint` al prenderla. */
|
|
415
|
+
setAutoTopup(partnerId: string, input: SetAutoTopupRequest): Promise<AutoTopup>;
|
|
391
416
|
listCredentials(partnerId: string): Promise<ListCredentialsResponse>;
|
|
392
417
|
/** El secreto `mms_…` viene UNA vez en la respuesta. */
|
|
393
418
|
createCredential(partnerId: string, input?: CreateCredentialRequest): Promise<CreateCredentialResponse>;
|