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 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`, `/presupuestos/draft` and `/whatsapp/order-draft`, and any AI
801
- * route added later. There is no second spelling and no 429 for it.
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, WhatsApp or storefront customer. Actor is the
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);
@@ -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. Its WhatsApp catalogue
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
  /**
@@ -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 do not select a
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
- * WhatsApp checkout attempted, while the store has no payment methods at
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 and WhatsApp checkout business refusals. None allocates an order
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, or a checkout choosing an online
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 right now (its provider is not connected).
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
  *
@@ -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.
@@ -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 whatsappCommerce/aiFeatures/mobileApp/customDomain are
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.STORE_WHATSAPP_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;
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
@@ -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 scheduled
424
- * WhatsApp leg), so both legs share one cooldown. It is absent on a
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";
@@ -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. Its WhatsApp catalogue
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. Its WhatsApp catalogue
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
  /**
@@ -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, and its absence is the contract
22
- * rather than an oversight. The platform's WhatsApp send path
23
- * (`POST /tenants/whatsapp`, `mode: 'template'`) is a synchronous HTTP
24
- * handler, not a queue producer, and Meta requires a pre-approved template
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
  /**
@@ -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' | 'whatsapp';
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 | NotifyWhatsAppSuppressionReason;
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#`. */