platform-types 1.10.761 → 1.10.763
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/ai.d.ts +2 -174
- package/dist/audit.d.ts +12 -1
- package/dist/cjs/index.js +0 -1
- package/dist/cjs/kitRecipe.js +1 -2
- package/dist/cjs/notification.js +27 -2
- package/dist/cjs/order.js +10 -3
- package/dist/cjs/paymentAttempt.js +29 -4
- package/dist/cjs/socket.js +12 -7
- package/dist/cjs/subscription.js +1 -3
- package/dist/cjs/wire.js +1 -3
- package/dist/customer.d.ts +11 -2
- package/dist/index.d.ts +0 -1
- package/dist/index.js +0 -1
- package/dist/kitRecipe.d.ts +1 -2
- package/dist/kitRecipe.js +1 -2
- package/dist/maintenance.d.ts +4 -9
- package/dist/notification.d.ts +29 -6
- package/dist/notification.js +27 -2
- package/dist/order.d.ts +8 -7
- package/dist/order.js +10 -3
- package/dist/paymentAttempt.d.ts +99 -8
- package/dist/paymentAttempt.js +28 -3
- package/dist/platform.d.ts +2 -5
- package/dist/product.d.ts +1 -1
- package/dist/reminder.d.ts +5 -4
- package/dist/socket.d.ts +1 -1
- package/dist/socket.js +12 -7
- package/dist/store.d.ts +10 -20
- package/dist/subscription.d.ts +3 -3
- package/dist/subscription.js +1 -3
- package/dist/wire.d.ts +0 -4
- package/dist/wire.js +0 -2
- package/package.json +1 -1
- package/dist/cjs/whatsapp.js +0 -70
- package/dist/whatsapp.d.ts +0 -148
- package/dist/whatsapp.js +0 -67
package/dist/ai.d.ts
CHANGED
|
@@ -621,184 +621,12 @@ declare global {
|
|
|
621
621
|
/** Email body: trimmed, non-empty, within the send path's body bound. */
|
|
622
622
|
body: string;
|
|
623
623
|
}
|
|
624
|
-
interface WhatsAppOrderDraftRequest {
|
|
625
|
-
/** Meta's message id of an INBOUND message this store received. The server re-reads its text. */
|
|
626
|
-
messageId: string;
|
|
627
|
-
/** `CUST` + 6–10 digits. Prices the draft at the list a cart prices this customer at (a missing, 0 or deleted list is PUBLICO 1); absent → the store default. */
|
|
628
|
-
customerId?: string;
|
|
629
|
-
}
|
|
630
|
-
/**
|
|
631
|
-
* One product a parsed item could be. Every field but `score` is read off the
|
|
632
|
-
* store's own product row and priced by the server — never model output.
|
|
633
|
-
*/
|
|
634
|
-
interface WhatsAppOrderDraftMatch {
|
|
635
|
-
productId: string;
|
|
636
|
-
sku: string;
|
|
637
|
-
name: string;
|
|
638
|
-
/** Unit price at the customer's list, in `currency`. Indicative: the order create path re-prices. */
|
|
639
|
-
amount: number;
|
|
640
|
-
currency: string;
|
|
641
|
-
/** Token-overlap similarity of the item phrase and the product name, 0–1. Best first. */
|
|
642
|
-
score: number;
|
|
643
|
-
}
|
|
644
|
-
interface WhatsAppOrderDraftItem {
|
|
645
|
-
/** The product as the model read it from the message, at most 120 characters. Display it, never parse it. */
|
|
646
|
-
text: string;
|
|
647
|
-
/** A whole number of units, 1–999, or `null` when the model's reading was not one — never guessed. */
|
|
648
|
-
quantity: number | null;
|
|
649
|
-
/** The model's own confidence in this item, 0–1. */
|
|
650
|
-
confidence: number;
|
|
651
|
-
/** At most three, best first. Empty when nothing sellable matched. */
|
|
652
|
-
matches: WhatsAppOrderDraftMatch[];
|
|
653
|
-
/** The first match is close enough to stand as the line without a person choosing. */
|
|
654
|
-
matched: boolean;
|
|
655
|
-
}
|
|
656
|
-
/**
|
|
657
|
-
* Why a person must take the conversation over, in this order:
|
|
658
|
-
* - `requested` — the customer asked to talk to someone.
|
|
659
|
-
* - `not_an_order` — the message asks for no products.
|
|
660
|
-
* - `no_items` — it reads as an order, but no product could be picked out.
|
|
661
|
-
* - `low_confidence` — the model is below 0.7 on at least one item.
|
|
662
|
-
* - `invalid_quantity` — at least one item's quantity is `null`.
|
|
663
|
-
* - `no_match` — nothing sellable matched at least one item.
|
|
664
|
-
* - `weak_match` — at least one item has matches, none close enough to stand alone.
|
|
665
|
-
*/
|
|
666
|
-
type WhatsAppOrderDraftHandoffReason = 'requested' | 'not_an_order' | 'no_items' | 'low_confidence' | 'invalid_quantity' | 'no_match' | 'weak_match';
|
|
667
|
-
/**
|
|
668
|
-
* `data` payload of the success envelope. ⚠️ A DRAFT: nothing was placed,
|
|
669
|
-
* reserved or sent. Every draft still needs a staff member to place the
|
|
670
|
-
* order; `handoff.needed` says one must also talk to the customer.
|
|
671
|
-
*/
|
|
672
|
-
interface WhatsAppOrderDraftResponse {
|
|
673
|
-
messageId: string;
|
|
674
|
-
intent: 'order' | 'human' | 'other';
|
|
675
|
-
items: WhatsAppOrderDraftItem[];
|
|
676
|
-
handoff: {
|
|
677
|
-
needed: boolean;
|
|
678
|
-
reasons: WhatsAppOrderDraftHandoffReason[];
|
|
679
|
-
};
|
|
680
|
-
/** More than 10 items were read; the rest were dropped. */
|
|
681
|
-
truncated: boolean;
|
|
682
|
-
/** The model that read the message. */
|
|
683
|
-
model: string;
|
|
684
|
-
/** Echoed when sent. */
|
|
685
|
-
customerId?: string;
|
|
686
|
-
}
|
|
687
|
-
/**
|
|
688
|
-
* The `error` codes this endpoint answers, beyond `GatingErrorCode`
|
|
689
|
-
* (`PLAN_UPGRADE_REQUIRED` for `aiFeatures` or `whatsappCommerce`,
|
|
690
|
-
* `IMPERSONATION_READONLY`).
|
|
691
|
-
*
|
|
692
|
-
* FREE — no model call was made:
|
|
693
|
-
* - `VALIDATION_FAILED` · 400.
|
|
694
|
-
* - `AI_OPT_OUT` · 403 — AI is off for this store, or its state could not be read.
|
|
695
|
-
* - `WHATSAPP_MESSAGE_NOT_FOUND` · 404 — no INBOUND message of this store has that id.
|
|
696
|
-
* - `WHATSAPP_MESSAGE_NOT_TEXT` · 422 — the message has no text (a photo, a sticker).
|
|
697
|
-
* - `WHATSAPP_ORDER_DRAFT_MESSAGE_TOO_LONG` · 422 — over 1000 characters.
|
|
698
|
-
* - `CUSTOMER_NOT_FOUND` · 404 — `customerId` names no active customer of this store.
|
|
699
|
-
* - `COST_CEILING_EXCEEDED` · 403 or 503 — see `AiCostCeilingRefusal`.
|
|
700
|
-
* - `AI_WHATSAPP_ORDER_DRAFT_DISABLED` · 503 — the platform kill-switch for
|
|
701
|
-
* this feature is off. Distinct from a ceiling: nothing was spent and no
|
|
702
|
-
* budget is exhausted. Like `AI_OPT_OUT`, it is checked AFTER the stored
|
|
703
|
-
* draft is read, so a message that already has a `ready` draft is still
|
|
704
|
-
* answered with it (200, no spend) while the switch is off. The automatic
|
|
705
|
-
* worker checks it before it claims the message and skips it — no draft
|
|
706
|
-
* row, no frame — so the message stays undrafted until a staff `POST`.
|
|
707
|
-
* - `AI_UNAVAILABLE` · 503 — the platform could not make the model call at
|
|
708
|
-
* all (a server-side fault, the same code on every AI endpoint). Nothing
|
|
709
|
-
* was sent or spent; the message's claim is settled `failed`, so a later
|
|
710
|
-
* `POST` drafts it. The automatic worker writes no draft row for it at all
|
|
711
|
-
* and retries the message itself.
|
|
712
|
-
* - `WHATSAPP_ORDER_DRAFT_PENDING` · 409 — the message is being drafted right
|
|
713
|
-
* now (by the automatic worker or another request); carries
|
|
714
|
-
* `status: 'pending'`. Wait for the `whatsapp-order-draft` frame or retry.
|
|
715
|
-
* A `pending` claim older than 60 s is dead (its invocation timed out
|
|
716
|
-
* before settling) and the next `POST` takes it over instead.
|
|
717
|
-
*
|
|
718
|
-
* A `POST` for a message that already has a `ready` stored draft answers
|
|
719
|
-
* that draft (200) and spends nothing; only an absent, `failed` or stale one is
|
|
720
|
-
* drafted again. A `failed` draft whose call was METERED (below) is spent on
|
|
721
|
-
* a second time when a `POST` retries it — the worker never does.
|
|
722
|
-
*
|
|
723
|
-
* METERED — the call ran and its output was refused:
|
|
724
|
-
* - `WHATSAPP_ORDER_DRAFT_BLOCKED` · 422 — the guardrail refused; carries `reason`
|
|
725
|
-
* (filter type names only).
|
|
726
|
-
* - `WHATSAPP_ORDER_DRAFT_GENERATION_FAILED` · 502 — the output did not parse.
|
|
727
|
-
*/
|
|
728
|
-
type WhatsAppOrderDraftErrorCode = 'VALIDATION_FAILED' | 'AI_OPT_OUT' | 'WHATSAPP_MESSAGE_NOT_FOUND' | 'WHATSAPP_MESSAGE_NOT_TEXT' | 'WHATSAPP_ORDER_DRAFT_MESSAGE_TOO_LONG' | 'CUSTOMER_NOT_FOUND' | 'COST_CEILING_EXCEEDED' | 'AI_WHATSAPP_ORDER_DRAFT_DISABLED' | 'AI_UNAVAILABLE' | 'WHATSAPP_ORDER_DRAFT_PENDING' | 'WHATSAPP_ORDER_DRAFT_BLOCKED' | 'WHATSAPP_ORDER_DRAFT_GENERATION_FAILED';
|
|
729
|
-
/**
|
|
730
|
-
* The one stored draft of a message — built by the automatic worker when
|
|
731
|
-
* the message arrived (stores with `config.whatsappOrderAutoDraft` on) or
|
|
732
|
-
* by a staff `POST /whatsapp/order-draft`. Read at `GET
|
|
733
|
-
* /whatsapp/order-draft?messageId=`. The worker pushes it as the
|
|
734
|
-
* `whatsapp-order-draft` frame when it settles, through `wsPostStore` with
|
|
735
|
-
* `audience: 'operator'` — the store's operator sockets, never the
|
|
736
|
-
* customer's. Kept as long as the message it reads (90 days).
|
|
737
|
-
*
|
|
738
|
-
* - `pending` — being drafted; no `draft`, no `error`.
|
|
739
|
-
* - `ready` — `draft` is set. Still a DRAFT: staff place the order.
|
|
740
|
-
* - `failed` — `error` is set, one of `WhatsAppOrderDraftErrorCode` or
|
|
741
|
-
* `WHATSAPP_ORDER_DRAFT_FAILED` for an unexpected fault. The worker never
|
|
742
|
-
* retries it; a staff `POST` does.
|
|
743
|
-
*/
|
|
744
|
-
interface WhatsAppStoredOrderDraft {
|
|
745
|
-
messageId: string;
|
|
746
|
-
status: 'pending' | 'ready' | 'failed';
|
|
747
|
-
draft?: WhatsAppOrderDraftResponse;
|
|
748
|
-
error?: string;
|
|
749
|
-
/** Epoch ms. */
|
|
750
|
-
createdAt: number;
|
|
751
|
-
/** Epoch ms. */
|
|
752
|
-
updatedAt: number;
|
|
753
|
-
}
|
|
754
|
-
/** Staff sends a priced quote to the sender of one stored inbound WhatsApp message. No AI spend. */
|
|
755
|
-
interface WhatsAppOrderConfirmationRequest {
|
|
756
|
-
messageId: string;
|
|
757
|
-
presupuestoId: string;
|
|
758
|
-
paymentMethod?: number;
|
|
759
|
-
deliveryMethod?: number;
|
|
760
|
-
}
|
|
761
|
-
type WhatsAppOrderConfirmationStatus = 'sending' | 'awaiting' | 'confirming' | 'confirmed' | 'cancelled' | 'changes_requested' | 'expired' | 'superseded' | 'failed';
|
|
762
|
-
/**
|
|
763
|
-
* Public confirmation returned by POST /whatsapp/order-draft/confirmation and
|
|
764
|
-
* emitted to operator sockets. The private nonce and sender number never reach
|
|
765
|
-
* this shape. An accepted staff-authored quote is converted through the existing
|
|
766
|
-
* atomic order service; an AI parse cannot create an order.
|
|
767
|
-
*/
|
|
768
|
-
interface WhatsAppOrderConfirmation {
|
|
769
|
-
messageId: string;
|
|
770
|
-
presupuestoId: string;
|
|
771
|
-
status: WhatsAppOrderConfirmationStatus;
|
|
772
|
-
customerId: string;
|
|
773
|
-
paymentMethod?: number;
|
|
774
|
-
deliveryMethod?: number;
|
|
775
|
-
sentBy: {
|
|
776
|
-
userId: string;
|
|
777
|
-
fullName: string;
|
|
778
|
-
};
|
|
779
|
-
/** Epoch ms; the earlier of the quote expiry and 24 hours after sending. */
|
|
780
|
-
expiresAt: number;
|
|
781
|
-
sentMessageId?: string;
|
|
782
|
-
orderId?: string;
|
|
783
|
-
/** A stable refusal code, never a raw provider message or customer text. */
|
|
784
|
-
error?: string;
|
|
785
|
-
createdAt: number;
|
|
786
|
-
updatedAt: number;
|
|
787
|
-
}
|
|
788
|
-
/**
|
|
789
|
-
* Route refusals in addition to the existing entitlement/impersonation codes.
|
|
790
|
-
* `…_DISABLED` (503) is the `whatsappOrderConfirmationEnabled` platform switch;
|
|
791
|
-
* `…_RECIPIENT_MISMATCH` (409) is a quote whose customer phone is not the
|
|
792
|
-
* source message's sender; `…_SETTLED` (409) carries the final confirmation
|
|
793
|
-
* in `data` (confirmed, cancelled, superseded, or failed after the tap).
|
|
794
|
-
*/
|
|
795
|
-
type WhatsAppOrderConfirmationErrorCode = 'VALIDATION_FAILED' | 'ADMIN_REQUIRED' | 'WHATSAPP_MESSAGE_NOT_FOUND' | 'PRESUPUESTO_NOT_FOUND' | 'PRESUPUESTO_NOT_MUTABLE' | 'CUSTOMER_NOT_FOUND' | 'PAYMENT_METHOD_NOT_FOUND' | 'DELIVERY_METHOD_NOT_FOUND' | 'WHATSAPP_WINDOW_CLOSED' | 'WHATSAPP_ORDER_CONFIRMATION_DISABLED' | 'WHATSAPP_ORDER_CONFIRMATION_RECIPIENT_MISMATCH' | 'WHATSAPP_ORDER_CONFIRMATION_PENDING' | 'WHATSAPP_ORDER_CONFIRMATION_SETTLED' | 'PLATFORM_INTEGRATION_DISABLED' | 'WHATSAPP_NOT_CONNECTED' | 'WHATSAPP_RECIPIENT_NOT_ALLOWED' | 'WHATSAPP_SEND_UNCONFIRMED' | 'WHATSAPP_SEND_FAILED' | 'WHATSAPP_TEMPLATE_NOT_APPROVED' | 'WHATSAPP_RECIPIENT_OPTED_OUT' | 'WHATSAPP_RATE_LIMITED' | 'WHATSAPP_ACCOUNT_SUSPENDED' | 'WHATSAPP_TOKEN_REJECTED';
|
|
796
624
|
/**
|
|
797
625
|
* The ONE spent-budget refusal every AI spend route answers —
|
|
798
626
|
* `POST /products/enrich`, `/reports/narrative`, `/marketing/copy`,
|
|
799
627
|
* `/reminders/draft`, `/suppliers/doc-extract`,
|
|
800
|
-
* `/suppliers/price-list-extract
|
|
801
|
-
*
|
|
628
|
+
* `/suppliers/price-list-extract` and `/presupuestos/draft`, and any AI route
|
|
629
|
+
* added later. There is no second spelling and no 429 for it.
|
|
802
630
|
*
|
|
803
631
|
* - 403 — the TENANT's own ceiling. Carries `feature`, `upsell` and `period`.
|
|
804
632
|
* `upsell` is true only for `monthly`: a daily tenant ceiling is one
|
package/dist/audit.d.ts
CHANGED
|
@@ -58,7 +58,8 @@ declare global {
|
|
|
58
58
|
*
|
|
59
59
|
* - `operator` — a store user acting through the App. Actor is that user.
|
|
60
60
|
* - `platform` — a MANAGER acting through `/platform/*`. Actor is that user.
|
|
61
|
-
* - `customer` — a web
|
|
61
|
+
* - `customer` — a web or storefront customer (older rows also carry ones who
|
|
62
|
+
* ordered through the since-removed WhatsApp checkout). Actor is the
|
|
62
63
|
* `CUST…` id with `fullName: ''` ALWAYS: an `AUDIT#` row has no TTL and is
|
|
63
64
|
* not reached by erasure, so a stored customer name could never be erased.
|
|
64
65
|
* Render the name from the live customer row.
|
|
@@ -153,6 +154,16 @@ declare global {
|
|
|
153
154
|
| 'order_shipment_created'
|
|
154
155
|
/** A shipment was voided; when the order was delivered, this un-delivered it. */
|
|
155
156
|
| 'order_shipment_voided' | 'payment_linked' | 'payment_unlinked'
|
|
157
|
+
/**
|
|
158
|
+
* An operator closed the order's storefront payment attempt that sat in
|
|
159
|
+
* `resolution` (`POST /payments/attempts { mode: 'resolve' }`). Records a
|
|
160
|
+
* decision only — no money moved and the order row is untouched.
|
|
161
|
+
* `before`: `attemptId`, `state` (`'resolution'`), `resolutionCause`.
|
|
162
|
+
* `after`: `attemptId`, `state` (`'resolved'`), `outcome` (`'refunded'` |
|
|
163
|
+
* `'kept'`) and the operator's reason as `'[present]'` — presence only, the
|
|
164
|
+
* words stay on the attempt row.
|
|
165
|
+
*/
|
|
166
|
+
| 'payment_attempt_resolved'
|
|
156
167
|
/** HISTORICAL: written only by the removed outbound MercadoPago refund; kept so old timeline rows still parse. */
|
|
157
168
|
| 'payment_refunded'
|
|
158
169
|
/** At least one till tender leg was appended (an absorbed replay writes none). */
|
package/dist/cjs/index.js
CHANGED
|
@@ -122,7 +122,6 @@ __exportStar(require("./userActivity.js"), exports);
|
|
|
122
122
|
__exportStar(require("./valuation.js"), exports);
|
|
123
123
|
__exportStar(require("./webhook.js"), exports);
|
|
124
124
|
__exportStar(require("./wire.js"), exports);
|
|
125
|
-
__exportStar(require("./whatsapp.js"), exports);
|
|
126
125
|
__exportStar(require("./workItem.js"), exports);
|
|
127
126
|
__exportStar(require("./zone.js"), exports);
|
|
128
127
|
__exportStar(require("./provinces.js"), exports);
|
package/dist/cjs/kitRecipe.js
CHANGED
|
@@ -28,8 +28,7 @@ const product_ts_1 = require("./product.js");
|
|
|
28
28
|
*
|
|
29
29
|
* - `counter` — the operator basket and `POST /orders`, which the app's POS and
|
|
30
30
|
* the mobile app share;
|
|
31
|
-
* - `storefront` — the shopper cart and the web checkout.
|
|
32
|
-
* and order drafts still leave kits out.
|
|
31
|
+
* - `storefront` — the shopper cart and the web checkout.
|
|
33
32
|
*/
|
|
34
33
|
exports.KIT_SALE_CHANNELS = ['counter', 'storefront'];
|
|
35
34
|
/**
|
package/dist/cjs/notification.js
CHANGED
|
@@ -5,8 +5,8 @@ exports.NotificationTypeEnum = void 0;
|
|
|
5
5
|
// Indexed producers resolve candidates through `getNotificationSubscribers`:
|
|
6
6
|
// legacy opt-ins and explicit channel maps remain source data on USER rows.
|
|
7
7
|
// Addressed ERROR / ML_FACTURADOR_COLLISION / ML_SELLER_SWITCHED /
|
|
8
|
-
// ML_CONNECTION_BROKEN / MENTION / CUSTOMER_PENDING_APPROVAL
|
|
9
|
-
// producer subscriber audience;
|
|
8
|
+
// ML_CONNECTION_BROKEN / MENTION / CUSTOMER_PENDING_APPROVAL /
|
|
9
|
+
// PAYMENT_ATTEMPT_RESOLUTION do not select a producer subscriber audience;
|
|
10
10
|
// the consumer still reads the live USER row for each delivery channel.
|
|
11
11
|
// AFIP_CERT_EXPIRY is seeded on the founding user and uses the subscriber index.
|
|
12
12
|
// Exported as a real enum consumed by api and app; adding an indexed type
|
|
@@ -174,4 +174,29 @@ var NotificationTypeEnum;
|
|
|
174
174
|
* storefront socket), and never the registrant's email address.
|
|
175
175
|
*/
|
|
176
176
|
NotificationTypeEnum["CUSTOMER_PENDING_APPROVAL"] = "CUSTOMER_PENDING_APPROVAL";
|
|
177
|
+
/**
|
|
178
|
+
* A storefront online payment attempt entered `resolution`: Mercado Pago
|
|
179
|
+
* money landed that did not settle its order (a late capture after the hold
|
|
180
|
+
* ended or the order was cancelled, a second approval, an amount or order
|
|
181
|
+
* mismatch, an order already paid). Names the order (`orderId`) and the
|
|
182
|
+
* cause, in the title and description; the app opens the resolution queue
|
|
183
|
+
* (`GET /payments/attempts?state=resolution`) from it.
|
|
184
|
+
*
|
|
185
|
+
* ⚠️ ADMIN-ONLY, and its own preference key. The producer fans out to every
|
|
186
|
+
* non-disabled ADMIN of the store (`listActiveAdmins`) — the tier that may
|
|
187
|
+
* read and close the queue — and never to a plain USER, so a client offers
|
|
188
|
+
* the `PAYMENT_ATTEMPT_RESOLUTION` toggle to ADMINs only. No legacy opt-in
|
|
189
|
+
* scan, as for `CUSTOMER_PENDING_APPROVAL` (a new key is seeded nowhere): the
|
|
190
|
+
* consumer enforces explicit type/channel preferences
|
|
191
|
+
* (`notificationPreferences.PAYMENT_ATTEMPT_RESOLUTION`), default-on when
|
|
192
|
+
* absent. Additive — no backfill or consumer migration owed.
|
|
193
|
+
*
|
|
194
|
+
* Once per new approval: it rings on the committed move INTO the state, and
|
|
195
|
+
* again on each further APPROVAL recorded on an attempt already there (new
|
|
196
|
+
* money the operator has not seen — a pending decision is then refused
|
|
197
|
+
* `409 PAYMENT_ATTEMPT_CHANGED`). A replayed approval moves nothing and rings
|
|
198
|
+
* nothing. An attempt an operator closed (`resolved`) and a later approval
|
|
199
|
+
* re-opens rings again.
|
|
200
|
+
*/
|
|
201
|
+
NotificationTypeEnum["PAYMENT_ATTEMPT_RESOLUTION"] = "PAYMENT_ATTEMPT_RESOLUTION";
|
|
177
202
|
})(NotificationTypeEnum || (exports.NotificationTypeEnum = NotificationTypeEnum = {}));
|
package/dist/cjs/order.js
CHANGED
|
@@ -364,14 +364,14 @@ exports.orderFulfilmentProgress = orderFulfilmentProgress;
|
|
|
364
364
|
* `data.shiftId`. Logged; reconcile the queued sale by hand.
|
|
365
365
|
* - `ORDER_CURRENCY_NOT_SUBSCRIBED` · 400 — the sale's currency has no
|
|
366
366
|
* subscription in the store's `currencies`. Logged.
|
|
367
|
-
* - `PAYMENT_METHODS_NOT_CONFIGURED` · 409 — `tenders` sent, or storefront
|
|
368
|
-
*
|
|
367
|
+
* - `PAYMENT_METHODS_NOT_CONFIGURED` · 409 — `tenders` sent, or storefront
|
|
368
|
+
* checkout attempted, while the store has no payment methods at
|
|
369
369
|
* all. Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
370
370
|
* - `PAYMENT_METHOD_NOT_FOUND` · 400 — a tender leg's `method`, or storefront
|
|
371
371
|
* checkout's `paymentMethod`, names none of the store's payment methods.
|
|
372
372
|
* Storefront checkout carries `data: {}` and refuses before the cart read.
|
|
373
373
|
*
|
|
374
|
-
* Storefront
|
|
374
|
+
* Storefront checkout business refusals. None allocates an order
|
|
375
375
|
* id, redeems a coupon or writes an order; none is logged as an error:
|
|
376
376
|
* - `DELIVERY_METHOD_NOT_FOUND` · 400 — `deliveryMethod` is not in the store's
|
|
377
377
|
* delivery catalogue, including an absent/empty catalogue. `data: {}`;
|
|
@@ -628,6 +628,13 @@ exports.ORDER_ERROR_CODES = [
|
|
|
628
628
|
'ORDER_CURRENCY_NOT_SUBSCRIBED',
|
|
629
629
|
'PAYMENT_METHODS_NOT_CONFIGURED',
|
|
630
630
|
'PAYMENT_METHOD_NOT_FOUND',
|
|
631
|
+
// An online method (`Method.storefront: 'mp-checkout-pro'`) the store cannot
|
|
632
|
+
// take for this cart: Mercado Pago not connected, or a cart not in pesos.
|
|
633
|
+
'PAYMENT_METHOD_UNAVAILABLE',
|
|
634
|
+
// Storefront checkout: the cart re-priced since the shopper saw it (re-read and
|
|
635
|
+
// confirm), and an allocated order id already taken (retry).
|
|
636
|
+
'CART_PRICES_CHANGED',
|
|
637
|
+
'ORDER_ID_COLLISION',
|
|
631
638
|
'DELIVERY_METHOD_NOT_FOUND',
|
|
632
639
|
'ORDER_BELOW_MINIMUM_PURCHASE',
|
|
633
640
|
'ORDER_INVALID_CART',
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* no operator write can carry it back onto the order.
|
|
20
20
|
*/
|
|
21
21
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
-
exports.PAYMENT_HOLD_MINUTES_DEFAULT = exports.PAYMENT_HOLD_MINUTES_MAX = exports.PAYMENT_HOLD_MINUTES_MIN = exports.PAYMENT_ATTEMPT_RESOLUTION_CAUSES = exports.ORDER_NOT_PAYABLE_REASONS = exports.PAYMENT_ATTEMPT_ERROR_CODES = exports.PAYMENT_ATTEMPT_STATES = void 0;
|
|
22
|
+
exports.PAYMENT_HOLD_MINUTES_DEFAULT = exports.PAYMENT_HOLD_MINUTES_MAX = exports.PAYMENT_HOLD_MINUTES_MIN = exports.PAYMENT_ATTEMPT_RESOLUTION_CAUSES = exports.ORDER_NOT_PAYABLE_REASONS = exports.PAYMENT_ATTEMPT_RESOLUTION_REASON_MAX = exports.PAYMENT_ATTEMPT_RESOLUTION_OUTCOMES = exports.PAYMENT_ATTEMPT_ERROR_CODES = exports.PAYMENT_ATTEMPT_STATES = void 0;
|
|
23
23
|
/** Every {@link PaymentAttemptState}, in lifecycle order. */
|
|
24
24
|
exports.PAYMENT_ATTEMPT_STATES = [
|
|
25
25
|
'created',
|
|
@@ -31,10 +31,11 @@ exports.PAYMENT_ATTEMPT_STATES = [
|
|
|
31
31
|
'refunded',
|
|
32
32
|
'charged_back',
|
|
33
33
|
'resolution',
|
|
34
|
+
'resolved',
|
|
34
35
|
];
|
|
35
36
|
/**
|
|
36
|
-
* Every refusal code a payment-attempt start,
|
|
37
|
-
* method, answers:
|
|
37
|
+
* Every refusal code a payment-attempt start, a checkout choosing an online
|
|
38
|
+
* method, or an operator closing a resolution answers:
|
|
38
39
|
*
|
|
39
40
|
* - `PAYMENT_PROVIDER_NOT_CONNECTED` · 412 — the store has no Mercado Pago
|
|
40
41
|
* account connected.
|
|
@@ -44,9 +45,20 @@ exports.PAYMENT_ATTEMPT_STATES = [
|
|
|
44
45
|
* {@link OrderNotPayableData}.
|
|
45
46
|
* - `PAYMENT_ATTEMPT_EXPIRED` · 410 — the attempt's `expiresAt` passed.
|
|
46
47
|
* - `PAYMENT_METHOD_UNAVAILABLE` · 409 — the checkout chose an online payment
|
|
47
|
-
* method the store cannot take
|
|
48
|
+
* method the store cannot take for this cart: its provider is not connected,
|
|
49
|
+
* or the cart is not in pesos (Checkout Pro here charges ARS only). `data` is
|
|
50
|
+
* `{}`. Also published in `ORDER_ERROR_CODES` — web `POST /orders` answers it.
|
|
48
51
|
* - `MP_PREFERENCE_CREATE_FAILED` · 502 — Mercado Pago refused the checkout or
|
|
49
52
|
* did not answer in time. No attempt was written, so starting again is safe.
|
|
53
|
+
* - `PAYMENT_ATTEMPT_NOT_FOUND` · 404 — the resolve named an attempt the store
|
|
54
|
+
* does not have, or an `orderId` that is not the attempt's.
|
|
55
|
+
* - `PAYMENT_ATTEMPT_NOT_IN_RESOLUTION` · 409 — the resolve's attempt is not in
|
|
56
|
+
* `resolution` (never was, or another operator closed it first). Nothing
|
|
57
|
+
* written; `data.state` is the state it is in.
|
|
58
|
+
* - `PAYMENT_ATTEMPT_CHANGED` · 409 — the attempt is still in `resolution` but
|
|
59
|
+
* is not the one the operator decided on: its `updatedAt` is not the request's
|
|
60
|
+
* `expectedUpdatedAt` (a further payment was recorded on it, for one). Nothing
|
|
61
|
+
* written; `data` is {@link PaymentAttemptChangedData}.
|
|
50
62
|
*/
|
|
51
63
|
exports.PAYMENT_ATTEMPT_ERROR_CODES = [
|
|
52
64
|
'PAYMENT_PROVIDER_NOT_CONNECTED',
|
|
@@ -55,7 +67,20 @@ exports.PAYMENT_ATTEMPT_ERROR_CODES = [
|
|
|
55
67
|
'PAYMENT_ATTEMPT_EXPIRED',
|
|
56
68
|
'PAYMENT_METHOD_UNAVAILABLE',
|
|
57
69
|
'MP_PREFERENCE_CREATE_FAILED',
|
|
70
|
+
'PAYMENT_ATTEMPT_NOT_FOUND',
|
|
71
|
+
'PAYMENT_ATTEMPT_NOT_IN_RESOLUTION',
|
|
72
|
+
'PAYMENT_ATTEMPT_CHANGED',
|
|
58
73
|
];
|
|
74
|
+
/**
|
|
75
|
+
* Every `outcome` of {@link ResolvePaymentAttemptRequest}:
|
|
76
|
+
*
|
|
77
|
+
* - `refunded` — staff refunded the payment in Mercado Pago's panel.
|
|
78
|
+
* - `kept` — the money stays with the store (for instance, the order is
|
|
79
|
+
* fulfilled by hand on it).
|
|
80
|
+
*/
|
|
81
|
+
exports.PAYMENT_ATTEMPT_RESOLUTION_OUTCOMES = ['refunded', 'kept'];
|
|
82
|
+
/** The longest `reason` a resolve may record, in characters after trimming. */
|
|
83
|
+
exports.PAYMENT_ATTEMPT_RESOLUTION_REASON_MAX = 500;
|
|
59
84
|
/**
|
|
60
85
|
* Every `data.reason` of `409 ORDER_NOT_PAYABLE`:
|
|
61
86
|
*
|
package/dist/cjs/socket.js
CHANGED
|
@@ -501,13 +501,6 @@ exports.SOCKET_ACTIONS = [
|
|
|
501
501
|
// Notifications & messaging.
|
|
502
502
|
'notifications',
|
|
503
503
|
'support-message',
|
|
504
|
-
/**
|
|
505
|
-
* An automatic WhatsApp order draft settled (`ready` or `failed`). The
|
|
506
|
-
* operator sockets of the store only; `data` is a `WhatsAppStoredOrderDraft`.
|
|
507
|
-
*/
|
|
508
|
-
'whatsapp-order-draft',
|
|
509
|
-
/** Staff quote confirmation state; operator audience only, data: WhatsAppOrderConfirmation. */
|
|
510
|
-
'whatsapp-order-confirmation',
|
|
511
504
|
// Payments & providers.
|
|
512
505
|
'payment_received',
|
|
513
506
|
// Operator-only observation invalidation; never a receipt or customer frame.
|
|
@@ -528,6 +521,18 @@ exports.SOCKET_ACTIONS = [
|
|
|
528
521
|
* customer broadcast. Sent once per committed state move of the attempt.
|
|
529
522
|
*/
|
|
530
523
|
'orderPaymentAttempt',
|
|
524
|
+
/**
|
|
525
|
+
* A storefront payment attempt an operator acts on changed: it entered
|
|
526
|
+
* `resolution`, took a further NEW approval while in it, or an operator
|
|
527
|
+
* closed it (`resolved`). `data` is
|
|
528
|
+
* `PaymentAttemptOperatorView` (`paymentAttempt.ts`) — never the checkout
|
|
529
|
+
* URL or the Preference id.
|
|
530
|
+
*
|
|
531
|
+
* ⚠️ OPERATOR sockets of the store only, and ADMIN tier only (`wsPostStore`
|
|
532
|
+
* with `lowTierData: null` — the tier `GET /payments/attempts` admits). Never
|
|
533
|
+
* a customer socket: the shopper's own frame is `orderPaymentAttempt`.
|
|
534
|
+
*/
|
|
535
|
+
'paymentAttemptChanged',
|
|
531
536
|
'stripe',
|
|
532
537
|
'subscription',
|
|
533
538
|
// Fiscal.
|
package/dist/cjs/subscription.js
CHANGED
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
* - Feature keys now match the BE wire format directly (renamed afip→afipInvoicing,
|
|
26
26
|
* cash→cashManagement, reportsAdvanced→advancedReports as of 2026-04-26). The interim
|
|
27
27
|
* paymentIntegrations key was split into domesticPayments + stripePayments.
|
|
28
|
-
* New keys
|
|
28
|
+
* New keys aiFeatures/mobileApp/customDomain are
|
|
29
29
|
* declared here even when their epics haven't shipped — the matrix can set
|
|
30
30
|
* enabled:false until they do.
|
|
31
31
|
*/
|
|
@@ -113,7 +113,6 @@ exports.FEATURE_KEYS = [
|
|
|
113
113
|
'importExport',
|
|
114
114
|
'domesticPayments',
|
|
115
115
|
'stripePayments',
|
|
116
|
-
'whatsappCommerce',
|
|
117
116
|
'aiFeatures',
|
|
118
117
|
'mobileApp',
|
|
119
118
|
'customBranding',
|
|
@@ -133,5 +132,4 @@ exports.FEATURE_KEYS = [
|
|
|
133
132
|
'webhooks',
|
|
134
133
|
'maxOrdersMonth',
|
|
135
134
|
'maxInvoicesMonth',
|
|
136
|
-
'whatsappMessages',
|
|
137
135
|
];
|
package/dist/cjs/wire.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* describes the result in the same edit.
|
|
19
19
|
*/
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.ROW_TTL_KEYS = exports.USER_TOTP_INTERNAL_KEYS = exports.STORE_TIENDANUBE_SECRET_KEYS = exports.
|
|
21
|
+
exports.ROW_TTL_KEYS = exports.USER_TOTP_INTERNAL_KEYS = exports.STORE_TIENDANUBE_SECRET_KEYS = exports.STORE_MERCADOLIBRE_SECRET_KEYS = exports.STORE_GMAIL_SECRET_KEYS = exports.STORE_MP_SECRET_KEYS = exports.STORE_AFIP_SECRET_KEYS = exports.RESPONSE_STRIPPED_KEYS = void 0;
|
|
22
22
|
/**
|
|
23
23
|
* The seven keys `response()` deletes from `body.data`.
|
|
24
24
|
*
|
|
@@ -67,8 +67,6 @@ exports.STORE_MERCADOLIBRE_SECRET_KEYS = [
|
|
|
67
67
|
'refreshTokenEncrypted',
|
|
68
68
|
'refreshAttemptAt',
|
|
69
69
|
];
|
|
70
|
-
/** WhatsApp's only secret field on `Store.integrations.whatsapp`. */
|
|
71
|
-
exports.STORE_WHATSAPP_SECRET_KEYS = ['accessToken'];
|
|
72
70
|
/**
|
|
73
71
|
* KMS-ciphertext TiendaNube OAuth credential on `Store.integrations.tiendanube`.
|
|
74
72
|
* A single `accessTokenEncrypted` — TiendaNube issues no refresh token, so there
|
package/dist/customer.d.ts
CHANGED
|
@@ -420,8 +420,8 @@ declare global {
|
|
|
420
420
|
* already makes on this row.
|
|
421
421
|
*
|
|
422
422
|
* ⚠️ Fed ONLY by a `ReminderRecord` with `kind: 'reminder'` — a delivered
|
|
423
|
-
* collections chase on ANY channel (the email leg or the
|
|
424
|
-
* WhatsApp leg), so
|
|
423
|
+
* collections chase on ANY channel (the email leg, or on older rows the
|
|
424
|
+
* since-removed WhatsApp leg), so every leg shared one cooldown. It is absent on a
|
|
425
425
|
* customer who was never chased, and that is correct rather than missing:
|
|
426
426
|
* populating it from transactional mail would read as "already chased" to
|
|
427
427
|
* a collections operator who would then skip a debtor.
|
|
@@ -1593,10 +1593,19 @@ declare global {
|
|
|
1593
1593
|
* `register`, `mode: 'social'` with the same provider on `register-social`
|
|
1594
1594
|
* (that account has no password) — never to register again, which the email
|
|
1595
1595
|
* uniqueness constraint would now refuse.
|
|
1596
|
+
*
|
|
1597
|
+
* In a store that approves registrations first, the answer is the created
|
|
1598
|
+
* customer with `accessState: 'pending'` and NO session: no token and no
|
|
1599
|
+
* `sessionIssued`. The client tells the shopper the account awaits approval;
|
|
1600
|
+
* signing in is refused until the store approves it.
|
|
1596
1601
|
*/
|
|
1597
1602
|
type CustomerRegisterResult = AuthCustomer | (Customer & {
|
|
1598
1603
|
accessToken?: never;
|
|
1599
1604
|
sessionIssued: false;
|
|
1605
|
+
}) | (Customer & {
|
|
1606
|
+
accessState: 'pending';
|
|
1607
|
+
accessToken?: never;
|
|
1608
|
+
sessionIssued?: never;
|
|
1600
1609
|
});
|
|
1601
1610
|
}
|
|
1602
1611
|
export {};
|
package/dist/index.d.ts
CHANGED
|
@@ -98,7 +98,6 @@ export * from './userActivity.ts';
|
|
|
98
98
|
export * from './valuation.ts';
|
|
99
99
|
export * from './webhook.ts';
|
|
100
100
|
export * from './wire.ts';
|
|
101
|
-
export * from './whatsapp.ts';
|
|
102
101
|
export * from './workItem.ts';
|
|
103
102
|
export * from './zone.ts';
|
|
104
103
|
export * from './provinces.ts';
|
package/dist/index.js
CHANGED
|
@@ -106,7 +106,6 @@ export * from "./userActivity.js";
|
|
|
106
106
|
export * from "./valuation.js";
|
|
107
107
|
export * from "./webhook.js";
|
|
108
108
|
export * from "./wire.js";
|
|
109
|
-
export * from "./whatsapp.js";
|
|
110
109
|
export * from "./workItem.js";
|
|
111
110
|
export * from "./zone.js";
|
|
112
111
|
export * from "./provinces.js";
|
package/dist/kitRecipe.d.ts
CHANGED
|
@@ -24,8 +24,7 @@
|
|
|
24
24
|
*
|
|
25
25
|
* - `counter` — the operator basket and `POST /orders`, which the app's POS and
|
|
26
26
|
* the mobile app share;
|
|
27
|
-
* - `storefront` — the shopper cart and the web checkout.
|
|
28
|
-
* and order drafts still leave kits out.
|
|
27
|
+
* - `storefront` — the shopper cart and the web checkout.
|
|
29
28
|
*/
|
|
30
29
|
export declare const KIT_SALE_CHANNELS: readonly ["counter", "storefront"];
|
|
31
30
|
/**
|
package/dist/kitRecipe.js
CHANGED
|
@@ -25,8 +25,7 @@ import { MAX_BASE_QUANTITY } from "./product.js";
|
|
|
25
25
|
*
|
|
26
26
|
* - `counter` — the operator basket and `POST /orders`, which the app's POS and
|
|
27
27
|
* the mobile app share;
|
|
28
|
-
* - `storefront` — the shopper cart and the web checkout.
|
|
29
|
-
* and order drafts still leave kits out.
|
|
28
|
+
* - `storefront` — the shopper cart and the web checkout.
|
|
30
29
|
*/
|
|
31
30
|
export const KIT_SALE_CHANNELS = ['counter', 'storefront'];
|
|
32
31
|
/**
|
package/dist/maintenance.d.ts
CHANGED
|
@@ -18,15 +18,10 @@ declare global {
|
|
|
18
18
|
/**
|
|
19
19
|
* A channel a maintenance broadcast can actually leave the platform on.
|
|
20
20
|
*
|
|
21
|
-
* ⚠️ `'whatsapp'` is deliberately ABSENT
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
* per message: a fleet-wide fan-out through it would be N inline Graph API
|
|
26
|
-
* calls inside one request, against a template that does not exist yet.
|
|
27
|
-
* Declaring the channel here before either is true would let a caller ask
|
|
28
|
-
* for a send this service cannot make and would have to refuse at runtime.
|
|
29
|
-
* Adding the member later is purely additive for every consumer.
|
|
21
|
+
* ⚠️ `'whatsapp'` is deliberately ABSENT: the platform has no WhatsApp send
|
|
22
|
+
* path, so declaring it would let a caller ask for a send this service cannot
|
|
23
|
+
* make and would have to refuse at runtime. Adding the member later is purely
|
|
24
|
+
* additive for every consumer.
|
|
30
25
|
*/
|
|
31
26
|
type MaintenanceBroadcastChannel = 'email' | 'sms';
|
|
32
27
|
/**
|
package/dist/notification.d.ts
CHANGED
|
@@ -152,7 +152,32 @@ export declare enum NotificationTypeEnum {
|
|
|
152
152
|
* audience — the operator bell would reach the pending registrant's own
|
|
153
153
|
* storefront socket), and never the registrant's email address.
|
|
154
154
|
*/
|
|
155
|
-
CUSTOMER_PENDING_APPROVAL = "CUSTOMER_PENDING_APPROVAL"
|
|
155
|
+
CUSTOMER_PENDING_APPROVAL = "CUSTOMER_PENDING_APPROVAL",
|
|
156
|
+
/**
|
|
157
|
+
* A storefront online payment attempt entered `resolution`: Mercado Pago
|
|
158
|
+
* money landed that did not settle its order (a late capture after the hold
|
|
159
|
+
* ended or the order was cancelled, a second approval, an amount or order
|
|
160
|
+
* mismatch, an order already paid). Names the order (`orderId`) and the
|
|
161
|
+
* cause, in the title and description; the app opens the resolution queue
|
|
162
|
+
* (`GET /payments/attempts?state=resolution`) from it.
|
|
163
|
+
*
|
|
164
|
+
* ⚠️ ADMIN-ONLY, and its own preference key. The producer fans out to every
|
|
165
|
+
* non-disabled ADMIN of the store (`listActiveAdmins`) — the tier that may
|
|
166
|
+
* read and close the queue — and never to a plain USER, so a client offers
|
|
167
|
+
* the `PAYMENT_ATTEMPT_RESOLUTION` toggle to ADMINs only. No legacy opt-in
|
|
168
|
+
* scan, as for `CUSTOMER_PENDING_APPROVAL` (a new key is seeded nowhere): the
|
|
169
|
+
* consumer enforces explicit type/channel preferences
|
|
170
|
+
* (`notificationPreferences.PAYMENT_ATTEMPT_RESOLUTION`), default-on when
|
|
171
|
+
* absent. Additive — no backfill or consumer migration owed.
|
|
172
|
+
*
|
|
173
|
+
* Once per new approval: it rings on the committed move INTO the state, and
|
|
174
|
+
* again on each further APPROVAL recorded on an attempt already there (new
|
|
175
|
+
* money the operator has not seen — a pending decision is then refused
|
|
176
|
+
* `409 PAYMENT_ATTEMPT_CHANGED`). A replayed approval moves nothing and rings
|
|
177
|
+
* nothing. An attempt an operator closed (`resolved`) and a later approval
|
|
178
|
+
* re-opens rings again.
|
|
179
|
+
*/
|
|
180
|
+
PAYMENT_ATTEMPT_RESOLUTION = "PAYMENT_ATTEMPT_RESOLUTION"
|
|
156
181
|
}
|
|
157
182
|
declare global {
|
|
158
183
|
type CustomerNotificationPreferences = Partial<Record<'reminder-scheduled' | 'appointment-reminder', {
|
|
@@ -316,13 +341,11 @@ declare global {
|
|
|
316
341
|
* What the outbound seam (`notify()`) knew about one call the moment its
|
|
317
342
|
* transport returned. It is never a delivery receipt: `enqueued` and
|
|
318
343
|
* `handed-off` say a queue or a sender took the message, and `sent` says the
|
|
319
|
-
* provider accepted it. Later SES events arrive through `EMAILEVENT
|
|
320
|
-
* WhatsApp status callbacks update the established `WHATSAPP#` history.
|
|
344
|
+
* provider accepted it. Later SES events arrive through `EMAILEVENT#`.
|
|
321
345
|
*/
|
|
322
346
|
type NotifyDeliveryOutcome = 'sent' | 'suppressed' | 'not-sent' | 'enqueued' | 'handed-off' | 'failed';
|
|
323
347
|
/** Why a channel did not deliver, including send-time preference refusals. */
|
|
324
348
|
type NotifyNotSentReason = 'skipped-by-preference' | 'demo' | 'suppressed' | 'refused';
|
|
325
|
-
type NotifyWhatsAppSuppressionReason = 'allowlist-missing' | 'recipient-malformed' | 'recipient-not-allowlisted';
|
|
326
349
|
/**
|
|
327
350
|
* A recorded transport outcome or send-time preference refusal — the
|
|
328
351
|
* wire half of the `NOTIFY#{storeId}` delivery row. The stored row,
|
|
@@ -337,14 +360,14 @@ declare global {
|
|
|
337
360
|
* `transport`, plus a count.
|
|
338
361
|
*/
|
|
339
362
|
interface NotifyDelivery {
|
|
340
|
-
transport: 'email' | 'queue' | 'ses' | 'ses-marketing' | 'push'
|
|
363
|
+
transport: 'email' | 'queue' | 'ses' | 'ses-marketing' | 'push';
|
|
341
364
|
/** The closed audience enum `notify()` accepts. */
|
|
342
365
|
audience: 'store-customer' | 'account-holder' | 'store-operator' | 'platform-staff' | 'marketing-recipient';
|
|
343
366
|
/** The producer's event name. Never recipient data. */
|
|
344
367
|
logTag: string;
|
|
345
368
|
outcome: NotifyDeliveryOutcome;
|
|
346
369
|
/** Only when `outcome` is `'not-sent'` or `'suppressed'`. */
|
|
347
|
-
reason?: NotifyNotSentReason
|
|
370
|
+
reason?: NotifyNotSentReason;
|
|
348
371
|
/** Provider channel for sent email; semantic channel for preference skips. */
|
|
349
372
|
channel?: 'gmail' | 'ses' | NotificationPreferenceChannel;
|
|
350
373
|
/** Only when SES returned one. The join key to `EMAILEVENT#`. */
|