platform-types 1.10.721 → 1.10.723
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/appointment.d.ts +1 -1
- package/dist/appointment.js +2 -0
- package/dist/cjs/appointment.js +2 -0
- package/dist/cjs/store.js +63 -1
- package/dist/cjs/subscription.js +24 -1
- package/dist/store.d.ts +91 -0
- package/dist/store.js +60 -0
- package/dist/subscription.d.ts +180 -6
- package/dist/subscription.js +23 -0
- package/package.json +1 -1
package/dist/appointment.d.ts
CHANGED
|
@@ -959,7 +959,7 @@ declare global {
|
|
|
959
959
|
* `GET /availability`, an operator queuing a party against a full slot rather
|
|
960
960
|
* than configuring the schedule — so its five refusals are listed above.
|
|
961
961
|
*/
|
|
962
|
-
export declare const APPOINTMENT_ERROR_CODES: readonly ["APPOINTMENT_NOT_FOUND", "APPOINTMENT_ID_REQUIRED", "APPOINTMENT_TYPE_DISABLED", "APPOINTMENT_SLOT_UNAVAILABLE", "APPOINTMENT_LEAD_TIME_NOT_MET", "APPOINTMENT_SELF_BOOKING_BLOCKED", "APPOINTMENT_CANCEL_CUTOFF_PASSED", "APPOINTMENT_OUTSIDE_WORKING_HOURS", "APPOINTMENT_TOO_FAR_AHEAD", "APPOINTMENT_ORDER_NOT_FOUND", "APPOINTMENT_ORDER_NOT_SCHEDULABLE", "APPOINTMENT_ORDER_ALREADY_SCHEDULED", "APPOINTMENT_STATUS_TRANSITION_ILLEGAL", "APPOINTMENT_VERSION_CONFLICT", "APPOINTMENT_NOT_CANCELLABLE", "APPOINTMENT_RESCHEDULE_NOOP", "APPOINTMENT_WAITLIST_PARTY_REQUIRED", "APPOINTMENT_WAITLIST_SLOT_AVAILABLE", "APPOINTMENT_WAITLIST_ALREADY_JOINED", "APPOINTMENT_WAITLIST_FULL", "APPOINTMENT_WAITLIST_ENTRY_NOT_FOUND", "INVALID_CURSOR", "RECURRENCE_RULE_MALFORMED", "RECURRENCE_RULE_UNSUPPORTED", "RECURRENCE_UNBOUNDED", "RECURRENCE_TOO_MANY", "APPOINTMENT_NOT_IN_SERIES", "RECURRENCE_SCOPE_REQUIRES_RULE_EDIT", "APPOINTMENT_STATUS_NOT_SCOPEABLE", "RECURRENCE_EXCEPTIONS_UNSUPPORTED", "RECURRENCE_EXCEPTIONS_SCOPE_REQUIRED", "VALIDATION_FAILED", "ROLE_FORBIDDEN", "APPOINTMENT_FEED_SECRET_NOT_CONFIGURED", "APPOINTMENT_FEED_IDENTITY_INVALID"];
|
|
962
|
+
export declare const APPOINTMENT_ERROR_CODES: readonly ["APPOINTMENT_NOT_FOUND", "APPOINTMENT_ID_REQUIRED", "APPOINTMENT_TYPE_DISABLED", "APPOINTMENT_SLOT_UNAVAILABLE", "APPOINTMENT_LEAD_TIME_NOT_MET", "APPOINTMENT_SELF_BOOKING_BLOCKED", "APPOINTMENT_CANCEL_CUTOFF_PASSED", "APPOINTMENT_OUTSIDE_WORKING_HOURS", "APPOINTMENT_TOO_FAR_AHEAD", "APPOINTMENT_ORDER_NOT_FOUND", "APPOINTMENT_ORDER_NOT_SCHEDULABLE", "APPOINTMENT_ORDER_ALREADY_SCHEDULED", "APPOINTMENT_STATUS_TRANSITION_ILLEGAL", "APPOINTMENT_VERSION_CONFLICT", "APPOINTMENT_NOT_CANCELLABLE", "APPOINTMENT_RESCHEDULE_NOOP", "APPOINTMENT_WAITLIST_PARTY_REQUIRED", "APPOINTMENT_WAITLIST_SLOT_AVAILABLE", "APPOINTMENT_WAITLIST_ALREADY_JOINED", "APPOINTMENT_WAITLIST_FULL", "APPOINTMENT_WAITLIST_ENTRY_NOT_FOUND", "INVALID_CURSOR", "RECURRENCE_RULE_MALFORMED", "RECURRENCE_RULE_UNSUPPORTED", "RECURRENCE_UNBOUNDED", "RECURRENCE_TOO_MANY", "APPOINTMENT_NOT_IN_SERIES", "RECURRENCE_SCOPE_REQUIRES_RULE_EDIT", "APPOINTMENT_STATUS_NOT_SCOPEABLE", "RECURRENCE_EXCEPTIONS_UNSUPPORTED", "RECURRENCE_EXCEPTIONS_SCOPE_REQUIRED", "VALIDATION_FAILED", "ROLE_FORBIDDEN", "APPOINTMENT_FEED_SECRET_NOT_CONFIGURED", "APPOINTMENT_FEED_IDENTITY_INVALID", "STORE_MODULE_DISABLED"];
|
|
963
963
|
export type AppointmentErrorCode = (typeof APPOINTMENT_ERROR_CODES)[number];
|
|
964
964
|
/**
|
|
965
965
|
* Which occurrences of a recurring booking an edit applies to —
|
package/dist/appointment.js
CHANGED
|
@@ -141,6 +141,8 @@ export const APPOINTMENT_ERROR_CODES = [
|
|
|
141
141
|
'ROLE_FORBIDDEN',
|
|
142
142
|
'APPOINTMENT_FEED_SECRET_NOT_CONFIGURED',
|
|
143
143
|
'APPOINTMENT_FEED_IDENTITY_INVALID',
|
|
144
|
+
// The storefront's self-booking surface, while the store has `modules.appointments` off.
|
|
145
|
+
'STORE_MODULE_DISABLED',
|
|
144
146
|
];
|
|
145
147
|
/**
|
|
146
148
|
* Which occurrences of a recurring booking an edit applies to —
|
package/dist/cjs/appointment.js
CHANGED
|
@@ -144,6 +144,8 @@ exports.APPOINTMENT_ERROR_CODES = [
|
|
|
144
144
|
'ROLE_FORBIDDEN',
|
|
145
145
|
'APPOINTMENT_FEED_SECRET_NOT_CONFIGURED',
|
|
146
146
|
'APPOINTMENT_FEED_IDENTITY_INVALID',
|
|
147
|
+
// The storefront's self-booking surface, while the store has `modules.appointments` off.
|
|
148
|
+
'STORE_MODULE_DISABLED',
|
|
147
149
|
];
|
|
148
150
|
/**
|
|
149
151
|
* Which occurrences of a recurring booking an edit applies to —
|
package/dist/cjs/store.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.CUSTOM_DOMAIN_ROW_LIMIT = exports.CUSTOM_DOMAIN_SLOT_LIMIT = void 0;
|
|
3
|
+
exports.STORE_MODULE_ERROR_CODES = exports.isStoreModuleOn = exports.isStoreModuleKey = exports.STORE_MODULE_KEYS = exports.CUSTOM_DOMAIN_ROW_LIMIT = exports.CUSTOM_DOMAIN_SLOT_LIMIT = void 0;
|
|
4
4
|
/**
|
|
5
5
|
* How many custom-domain rows a store may hold that count: one active domain
|
|
6
6
|
* and one spare, so a replacement can be verified and provisioned before the
|
|
@@ -18,3 +18,65 @@ exports.CUSTOM_DOMAIN_SLOT_LIMIT = 2;
|
|
|
18
18
|
* `409 DOMAIN_ROW_LIMIT` with this value as `limit`.
|
|
19
19
|
*/
|
|
20
20
|
exports.CUSTOM_DOMAIN_ROW_LIMIT = 10;
|
|
21
|
+
/**
|
|
22
|
+
* Every `StoreModuleKey`, in catalogue order — the ONE list. The type is derived
|
|
23
|
+
* from it, so the `PATCH /store` validator and every client enumerate exactly
|
|
24
|
+
* the modules the type allows, and a module is added in one place.
|
|
25
|
+
*/
|
|
26
|
+
exports.STORE_MODULE_KEYS = [
|
|
27
|
+
'attendance',
|
|
28
|
+
'lots',
|
|
29
|
+
'stocktake',
|
|
30
|
+
'purchases',
|
|
31
|
+
'loyalty',
|
|
32
|
+
'surveys',
|
|
33
|
+
'customerZones',
|
|
34
|
+
'workshop',
|
|
35
|
+
'appointments',
|
|
36
|
+
'cash',
|
|
37
|
+
'multiWarehouse',
|
|
38
|
+
'quotes',
|
|
39
|
+
'promotions',
|
|
40
|
+
'marketing',
|
|
41
|
+
'fiscalInvoicing',
|
|
42
|
+
'customerAccounts',
|
|
43
|
+
];
|
|
44
|
+
/** Whether `value` names a module — narrows an untyped key (a request body, a stored row). */
|
|
45
|
+
const isStoreModuleKey = (value) => typeof value === 'string' && exports.STORE_MODULE_KEYS.includes(value);
|
|
46
|
+
exports.isStoreModuleKey = isStoreModuleKey;
|
|
47
|
+
/**
|
|
48
|
+
* Whether `module` is on for a store whose `config.modules` is `modules`.
|
|
49
|
+
* ⚠️ Absent is ON: only an explicit `false` turns a module off, so a missing
|
|
50
|
+
* map, a missing key and `true` all answer `true`.
|
|
51
|
+
*/
|
|
52
|
+
const isStoreModuleOn = (modules, module) => modules?.[module] !== false;
|
|
53
|
+
exports.isStoreModuleOn = isStoreModuleOn;
|
|
54
|
+
/**
|
|
55
|
+
* Every refusal code the store-module switches put on the wire, beyond the
|
|
56
|
+
* platform-wide set (`VALIDATION_FAILED`, and `STORE_CONFIG_FORBIDDEN` for a
|
|
57
|
+
* plain USER writing the privileged leaf):
|
|
58
|
+
*
|
|
59
|
+
* - `STORE_MODULE_UNKNOWN` (400) — `PATCH /store` named a key outside
|
|
60
|
+
* `STORE_MODULE_KEYS`; `data.module` carries it.
|
|
61
|
+
* - `STORE_MODULE_NOT_BOOLEAN` (400) — a module's value was not `true`/`false`.
|
|
62
|
+
* - `STORE_MODULE_WAREHOUSES_ACTIVE` (409) — `multiWarehouse` off while more
|
|
63
|
+
* than one depósito is active; `data.activeWarehouses` carries the count.
|
|
64
|
+
* - `STORE_MODULE_TRANSFER_IN_FLIGHT` (409) — `multiWarehouse` off while a stock
|
|
65
|
+
* transfer is in transit or partially received; `data.transferId` names one.
|
|
66
|
+
* - `STORE_MODULE_CUSTOMER_BALANCES` (409) — `customerAccounts` off while a
|
|
67
|
+
* customer carries a non-zero balance; `data.customerId` names one.
|
|
68
|
+
* - `STORE_MODULE_BALANCE_CHECK_INCOMPLETE` (409) — the bounded balance read
|
|
69
|
+
* stopped before it could prove every balance is zero. Retrying is harmless but
|
|
70
|
+
* walks the same rows, so a very large customer book keeps answering it.
|
|
71
|
+
* - `STORE_MODULE_DISABLED` (403) — a server-enforced module is off (storefront
|
|
72
|
+
* self-booking, storefront survey); `data.module` names it.
|
|
73
|
+
*/
|
|
74
|
+
exports.STORE_MODULE_ERROR_CODES = [
|
|
75
|
+
'STORE_MODULE_UNKNOWN',
|
|
76
|
+
'STORE_MODULE_NOT_BOOLEAN',
|
|
77
|
+
'STORE_MODULE_WAREHOUSES_ACTIVE',
|
|
78
|
+
'STORE_MODULE_TRANSFER_IN_FLIGHT',
|
|
79
|
+
'STORE_MODULE_CUSTOMER_BALANCES',
|
|
80
|
+
'STORE_MODULE_BALANCE_CHECK_INCOMPLETE',
|
|
81
|
+
'STORE_MODULE_DISABLED',
|
|
82
|
+
];
|
package/dist/cjs/subscription.js
CHANGED
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
* enabled:false until they do.
|
|
31
31
|
*/
|
|
32
32
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
33
|
-
exports.FEATURE_KEYS = exports.isPaidPlanTier = exports.PAID_PLAN_TIERS = exports.PLAN_TIERS = void 0;
|
|
33
|
+
exports.FEATURE_KEYS = exports.isPaidPlanTier = exports.PLAN_CATALOGUE_ERROR_CODES = exports.PLAN_CATALOGUE_TEMPLATE_FIELDS = exports.PAID_PLAN_TIERS = exports.PLAN_TIERS = void 0;
|
|
34
34
|
/*
|
|
35
35
|
* Runtime tuples for the unions above.
|
|
36
36
|
*
|
|
@@ -56,6 +56,29 @@ exports.PLAN_TIERS = exhaustiveTuple()(['basico', 'emprendedor', 'profesional',
|
|
|
56
56
|
* grace sweep's tier fan-out and the provider plan seeders all read it.
|
|
57
57
|
*/
|
|
58
58
|
exports.PAID_PLAN_TIERS = exhaustiveTuple()(['emprendedor', 'profesional', 'avanzado']);
|
|
59
|
+
/** Every template field a plan catalogue draft carries, in the order a diff lists them. */
|
|
60
|
+
exports.PLAN_CATALOGUE_TEMPLATE_FIELDS = exhaustiveTuple()([
|
|
61
|
+
'name',
|
|
62
|
+
'description',
|
|
63
|
+
'displayOrder',
|
|
64
|
+
'isActive',
|
|
65
|
+
'isPopular',
|
|
66
|
+
'color',
|
|
67
|
+
'priceMonthlyCents',
|
|
68
|
+
'priceAnnualCents',
|
|
69
|
+
'currency',
|
|
70
|
+
]);
|
|
71
|
+
/** Every `error` code the plan catalogue draft / publish routes add — the coverage test holds the handlers to it. */
|
|
72
|
+
exports.PLAN_CATALOGUE_ERROR_CODES = exhaustiveTuple()([
|
|
73
|
+
'PLAN_CATALOGUE_REVISION_CONFLICT',
|
|
74
|
+
'PLAN_CATALOGUE_BUSY',
|
|
75
|
+
'PLAN_CATALOGUE_NO_CHANGES',
|
|
76
|
+
'PLAN_CATALOGUE_PUBLICATION_NOT_FOUND',
|
|
77
|
+
'PLAN_CATALOGUE_REQUEST_EXPIRED',
|
|
78
|
+
'PLAN_CATALOGUE_INVALID_CURSOR',
|
|
79
|
+
'PLAN_CATALOGUE_DRAFT_STALE',
|
|
80
|
+
'IDEMPOTENCY_CONFLICT',
|
|
81
|
+
]);
|
|
59
82
|
/** Whether `value` names a paid tier — narrows an untyped read (a stored row, a global) to `PaidPlanTier`. */
|
|
60
83
|
const isPaidPlanTier = (value) => typeof value === 'string' && exports.PAID_PLAN_TIERS.includes(value);
|
|
61
84
|
exports.isPaidPlanTier = isPaidPlanTier;
|
package/dist/store.d.ts
CHANGED
|
@@ -85,6 +85,19 @@ declare global {
|
|
|
85
85
|
/** MercadoLibre orders. */
|
|
86
86
|
mercadolibre?: string;
|
|
87
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* One store-wide module a store can switch off for every user — the
|
|
90
|
+
* catalogue is the shared `domain/STORE_MODULES.md`. Enumerable at runtime as
|
|
91
|
+
* `STORE_MODULE_KEYS`; read a switch through `isStoreModuleOn`.
|
|
92
|
+
*/
|
|
93
|
+
type StoreModuleKey = (typeof STORE_MODULE_KEYS)[number];
|
|
94
|
+
/**
|
|
95
|
+
* `Store.config.modules`. ⚠️ An ABSENT key is ON — only an explicit `false`
|
|
96
|
+
* turns a module off, so a store that never wrote the map (every store that
|
|
97
|
+
* predates it) has every module on. Off HIDES; it never deletes, and the
|
|
98
|
+
* module's existing records stay readable.
|
|
99
|
+
*/
|
|
100
|
+
type StoreModules = Partial<Record<StoreModuleKey, boolean>>;
|
|
88
101
|
interface Ecommerce {
|
|
89
102
|
/**
|
|
90
103
|
* The tenant's «Activar tienda online» switch. Written only by the api's
|
|
@@ -880,8 +893,50 @@ declare global {
|
|
|
880
893
|
* Written through `PATCH /store` `config` (admin tier), merged per channel;
|
|
881
894
|
* a channel sent as `null` clears it. Absent, or a channel absent inside
|
|
882
895
|
* it, means that channel's sales use the primary depósito.
|
|
896
|
+
*
|
|
897
|
+
* ⚠️ Ignored while `modules.multiWarehouse` is `false`: sales and the
|
|
898
|
+
* MercadoLibre feed then resolve to the primary depósito (see `modules`),
|
|
899
|
+
* whatever this holds.
|
|
883
900
|
*/
|
|
884
901
|
channelWarehouses?: StoreChannelWarehouses;
|
|
902
|
+
/**
|
|
903
|
+
* Store-wide module switches — see `StoreModules`. Written through
|
|
904
|
+
* `PATCH /store` `config` at the PRIVILEGED tier (ADMIN/SUPERVISOR/MANAGER;
|
|
905
|
+
* a plain USER is refused `STORE_CONFIG_FORBIDDEN`), merged per key. An
|
|
906
|
+
* unknown key is refused `400 STORE_MODULE_UNKNOWN`, a non-boolean value
|
|
907
|
+
* `400 STORE_MODULE_NOT_BOOLEAN`.
|
|
908
|
+
*
|
|
909
|
+
* Turning a module OFF is refused while it still carries state:
|
|
910
|
+
* `multiWarehouse` while more than one depósito is active
|
|
911
|
+
* (`409 STORE_MODULE_WAREHOUSES_ACTIVE`) or a transfer is in transit or
|
|
912
|
+
* partially received (`409 STORE_MODULE_TRANSFER_IN_FLIGHT`);
|
|
913
|
+
* `customerAccounts` while any customer carries a non-zero balance
|
|
914
|
+
* (`409 STORE_MODULE_CUSTOMER_BALANCES`, or
|
|
915
|
+
* `409 STORE_MODULE_BALANCE_CHECK_INCOMPLETE` when the bounded read could
|
|
916
|
+
* not finish).
|
|
917
|
+
*
|
|
918
|
+
* Enforced on the server for four modules only:
|
|
919
|
+
* - `promotions` — applying one is refused `PROMOTION_NOT_ACTIVE` (the
|
|
920
|
+
* existing promotion refusal, not `STORE_MODULE_DISABLED`), a grant already
|
|
921
|
+
* frozen on a cart stays on the row but derives no money (its
|
|
922
|
+
* `promotionEffect` is removed), the storefront checkout and a service
|
|
923
|
+
* delivery refuse it `409 CART_PROMOTION_UNAVAILABLE` with
|
|
924
|
+
* `data.reason: 'PROMOTION_NOT_ACTIVE'` (removing the grant), and the
|
|
925
|
+
* applicable list is empty. A till ticket last written while promotions
|
|
926
|
+
* were on (it still carries its `promotionEffect`) converts at the price
|
|
927
|
+
* it was sold at.
|
|
928
|
+
* - `appointments` — storefront availability, booking and rescheduling are
|
|
929
|
+
* refused `403 STORE_MODULE_DISABLED`; the shopper's list and cancel stay.
|
|
930
|
+
* - `surveys` — a storefront survey is refused `403 STORE_MODULE_DISABLED`,
|
|
931
|
+
* so none is recorded, broadcast or mailed.
|
|
932
|
+
* - `multiWarehouse` — every sale resolves to the primary depósito (a
|
|
933
|
+
* scoped operator's sale to their own home depósito when the primary is
|
|
934
|
+
* outside their scope), and only the primary feeds MercadoLibre.
|
|
935
|
+
* Every other module is hide-only: its endpoints stay reachable. Public
|
|
936
|
+
* reads carry only `appointments`, `surveys`, `promotions` and
|
|
937
|
+
* `customerAccounts`. `PUT /platform/stores/{storeId}` refuses the leaf.
|
|
938
|
+
*/
|
|
939
|
+
modules?: StoreModules;
|
|
885
940
|
};
|
|
886
941
|
ecommerce?: Ecommerce;
|
|
887
942
|
/**
|
|
@@ -1947,3 +2002,39 @@ export declare const CUSTOM_DOMAIN_SLOT_LIMIT = 2;
|
|
|
1947
2002
|
* `409 DOMAIN_ROW_LIMIT` with this value as `limit`.
|
|
1948
2003
|
*/
|
|
1949
2004
|
export declare const CUSTOM_DOMAIN_ROW_LIMIT = 10;
|
|
2005
|
+
/**
|
|
2006
|
+
* Every `StoreModuleKey`, in catalogue order — the ONE list. The type is derived
|
|
2007
|
+
* from it, so the `PATCH /store` validator and every client enumerate exactly
|
|
2008
|
+
* the modules the type allows, and a module is added in one place.
|
|
2009
|
+
*/
|
|
2010
|
+
export declare const STORE_MODULE_KEYS: readonly ["attendance", "lots", "stocktake", "purchases", "loyalty", "surveys", "customerZones", "workshop", "appointments", "cash", "multiWarehouse", "quotes", "promotions", "marketing", "fiscalInvoicing", "customerAccounts"];
|
|
2011
|
+
/** Whether `value` names a module — narrows an untyped key (a request body, a stored row). */
|
|
2012
|
+
export declare const isStoreModuleKey: (value: unknown) => value is StoreModuleKey;
|
|
2013
|
+
/**
|
|
2014
|
+
* Whether `module` is on for a store whose `config.modules` is `modules`.
|
|
2015
|
+
* ⚠️ Absent is ON: only an explicit `false` turns a module off, so a missing
|
|
2016
|
+
* map, a missing key and `true` all answer `true`.
|
|
2017
|
+
*/
|
|
2018
|
+
export declare const isStoreModuleOn: (modules: StoreModules | null | undefined, module: StoreModuleKey) => boolean;
|
|
2019
|
+
/**
|
|
2020
|
+
* Every refusal code the store-module switches put on the wire, beyond the
|
|
2021
|
+
* platform-wide set (`VALIDATION_FAILED`, and `STORE_CONFIG_FORBIDDEN` for a
|
|
2022
|
+
* plain USER writing the privileged leaf):
|
|
2023
|
+
*
|
|
2024
|
+
* - `STORE_MODULE_UNKNOWN` (400) — `PATCH /store` named a key outside
|
|
2025
|
+
* `STORE_MODULE_KEYS`; `data.module` carries it.
|
|
2026
|
+
* - `STORE_MODULE_NOT_BOOLEAN` (400) — a module's value was not `true`/`false`.
|
|
2027
|
+
* - `STORE_MODULE_WAREHOUSES_ACTIVE` (409) — `multiWarehouse` off while more
|
|
2028
|
+
* than one depósito is active; `data.activeWarehouses` carries the count.
|
|
2029
|
+
* - `STORE_MODULE_TRANSFER_IN_FLIGHT` (409) — `multiWarehouse` off while a stock
|
|
2030
|
+
* transfer is in transit or partially received; `data.transferId` names one.
|
|
2031
|
+
* - `STORE_MODULE_CUSTOMER_BALANCES` (409) — `customerAccounts` off while a
|
|
2032
|
+
* customer carries a non-zero balance; `data.customerId` names one.
|
|
2033
|
+
* - `STORE_MODULE_BALANCE_CHECK_INCOMPLETE` (409) — the bounded balance read
|
|
2034
|
+
* stopped before it could prove every balance is zero. Retrying is harmless but
|
|
2035
|
+
* walks the same rows, so a very large customer book keeps answering it.
|
|
2036
|
+
* - `STORE_MODULE_DISABLED` (403) — a server-enforced module is off (storefront
|
|
2037
|
+
* self-booking, storefront survey); `data.module` names it.
|
|
2038
|
+
*/
|
|
2039
|
+
export declare const STORE_MODULE_ERROR_CODES: readonly ["STORE_MODULE_UNKNOWN", "STORE_MODULE_NOT_BOOLEAN", "STORE_MODULE_WAREHOUSES_ACTIVE", "STORE_MODULE_TRANSFER_IN_FLIGHT", "STORE_MODULE_CUSTOMER_BALANCES", "STORE_MODULE_BALANCE_CHECK_INCOMPLETE", "STORE_MODULE_DISABLED"];
|
|
2040
|
+
export type StoreModuleErrorCode = (typeof STORE_MODULE_ERROR_CODES)[number];
|
package/dist/store.js
CHANGED
|
@@ -15,3 +15,63 @@ export const CUSTOM_DOMAIN_SLOT_LIMIT = 2;
|
|
|
15
15
|
* `409 DOMAIN_ROW_LIMIT` with this value as `limit`.
|
|
16
16
|
*/
|
|
17
17
|
export const CUSTOM_DOMAIN_ROW_LIMIT = 10;
|
|
18
|
+
/**
|
|
19
|
+
* Every `StoreModuleKey`, in catalogue order — the ONE list. The type is derived
|
|
20
|
+
* from it, so the `PATCH /store` validator and every client enumerate exactly
|
|
21
|
+
* the modules the type allows, and a module is added in one place.
|
|
22
|
+
*/
|
|
23
|
+
export const STORE_MODULE_KEYS = [
|
|
24
|
+
'attendance',
|
|
25
|
+
'lots',
|
|
26
|
+
'stocktake',
|
|
27
|
+
'purchases',
|
|
28
|
+
'loyalty',
|
|
29
|
+
'surveys',
|
|
30
|
+
'customerZones',
|
|
31
|
+
'workshop',
|
|
32
|
+
'appointments',
|
|
33
|
+
'cash',
|
|
34
|
+
'multiWarehouse',
|
|
35
|
+
'quotes',
|
|
36
|
+
'promotions',
|
|
37
|
+
'marketing',
|
|
38
|
+
'fiscalInvoicing',
|
|
39
|
+
'customerAccounts',
|
|
40
|
+
];
|
|
41
|
+
/** Whether `value` names a module — narrows an untyped key (a request body, a stored row). */
|
|
42
|
+
export const isStoreModuleKey = (value) => typeof value === 'string' && STORE_MODULE_KEYS.includes(value);
|
|
43
|
+
/**
|
|
44
|
+
* Whether `module` is on for a store whose `config.modules` is `modules`.
|
|
45
|
+
* ⚠️ Absent is ON: only an explicit `false` turns a module off, so a missing
|
|
46
|
+
* map, a missing key and `true` all answer `true`.
|
|
47
|
+
*/
|
|
48
|
+
export const isStoreModuleOn = (modules, module) => modules?.[module] !== false;
|
|
49
|
+
/**
|
|
50
|
+
* Every refusal code the store-module switches put on the wire, beyond the
|
|
51
|
+
* platform-wide set (`VALIDATION_FAILED`, and `STORE_CONFIG_FORBIDDEN` for a
|
|
52
|
+
* plain USER writing the privileged leaf):
|
|
53
|
+
*
|
|
54
|
+
* - `STORE_MODULE_UNKNOWN` (400) — `PATCH /store` named a key outside
|
|
55
|
+
* `STORE_MODULE_KEYS`; `data.module` carries it.
|
|
56
|
+
* - `STORE_MODULE_NOT_BOOLEAN` (400) — a module's value was not `true`/`false`.
|
|
57
|
+
* - `STORE_MODULE_WAREHOUSES_ACTIVE` (409) — `multiWarehouse` off while more
|
|
58
|
+
* than one depósito is active; `data.activeWarehouses` carries the count.
|
|
59
|
+
* - `STORE_MODULE_TRANSFER_IN_FLIGHT` (409) — `multiWarehouse` off while a stock
|
|
60
|
+
* transfer is in transit or partially received; `data.transferId` names one.
|
|
61
|
+
* - `STORE_MODULE_CUSTOMER_BALANCES` (409) — `customerAccounts` off while a
|
|
62
|
+
* customer carries a non-zero balance; `data.customerId` names one.
|
|
63
|
+
* - `STORE_MODULE_BALANCE_CHECK_INCOMPLETE` (409) — the bounded balance read
|
|
64
|
+
* stopped before it could prove every balance is zero. Retrying is harmless but
|
|
65
|
+
* walks the same rows, so a very large customer book keeps answering it.
|
|
66
|
+
* - `STORE_MODULE_DISABLED` (403) — a server-enforced module is off (storefront
|
|
67
|
+
* self-booking, storefront survey); `data.module` names it.
|
|
68
|
+
*/
|
|
69
|
+
export const STORE_MODULE_ERROR_CODES = [
|
|
70
|
+
'STORE_MODULE_UNKNOWN',
|
|
71
|
+
'STORE_MODULE_NOT_BOOLEAN',
|
|
72
|
+
'STORE_MODULE_WAREHOUSES_ACTIVE',
|
|
73
|
+
'STORE_MODULE_TRANSFER_IN_FLIGHT',
|
|
74
|
+
'STORE_MODULE_CUSTOMER_BALANCES',
|
|
75
|
+
'STORE_MODULE_BALANCE_CHECK_INCOMPLETE',
|
|
76
|
+
'STORE_MODULE_DISABLED',
|
|
77
|
+
];
|
package/dist/subscription.d.ts
CHANGED
|
@@ -357,6 +357,12 @@ declare global {
|
|
|
357
357
|
tier: PaidPlanTier;
|
|
358
358
|
days: number;
|
|
359
359
|
};
|
|
360
|
+
/**
|
|
361
|
+
* The publication these plans are, from `POST /platform/billing/plans/publish`
|
|
362
|
+
* — so a consumer (the landing snapshot) can tell which version it rendered.
|
|
363
|
+
* `null` until the catalogue's first publication, or when the rows read are not one publication.
|
|
364
|
+
*/
|
|
365
|
+
publicationId: string | null;
|
|
360
366
|
}
|
|
361
367
|
/**
|
|
362
368
|
* One audit row per MANAGER-driven plan mutation (`POST` / `PATCH
|
|
@@ -879,10 +885,8 @@ declare global {
|
|
|
879
885
|
/** Screened operator reason (10-500 characters, no personal data); lands in each tier's audit entry. */
|
|
880
886
|
reason: string;
|
|
881
887
|
/**
|
|
882
|
-
*
|
|
883
|
-
*
|
|
884
|
-
* keys, not the tiers or values, so it proves the caller meant those keys;
|
|
885
|
-
* the dry run is where the tiers and the impact are reviewed.
|
|
888
|
+
* Accepted and NOT checked: a grant edit writes the draft, and the echo that
|
|
889
|
+
* gates what readers see is the publish's (`PlanCataloguePublishInput.confirm`).
|
|
886
890
|
*/
|
|
887
891
|
confirm?: string;
|
|
888
892
|
/** `true` writes nothing and returns the impact plus the `confirm` string. */
|
|
@@ -920,7 +924,9 @@ declare global {
|
|
|
920
924
|
* Stores on this tier, any status: those whose SUBSCRIPTION row is on it
|
|
921
925
|
* (`planTier-status`) plus, on `profesional` — the tier a store with no
|
|
922
926
|
* SUBSCRIPTION row resolves to — every store with no row. A lower bound
|
|
923
|
-
* when `truncated`.
|
|
927
|
+
* when `truncated`. ⚠️ Always `0` on a grant edit, which writes the draft
|
|
928
|
+
* only: the store counts and the impact are the publish dry run's
|
|
929
|
+
* (`PlanCataloguePublishTierResult`).
|
|
924
930
|
*/
|
|
925
931
|
subscribedStores: number;
|
|
926
932
|
/** Dry run only: per reduced key, the stores it bites. Empty when nothing on this tier is reduced. */
|
|
@@ -953,10 +959,174 @@ declare global {
|
|
|
953
959
|
dryRun: boolean;
|
|
954
960
|
/** `false` on a dry run and on an identical replay (no change, no write, no audit). */
|
|
955
961
|
written: boolean;
|
|
956
|
-
/** The comma-joined sorted changed keys
|
|
962
|
+
/** The comma-joined sorted changed keys. Informational on a draft edit — the publish computes its own. */
|
|
957
963
|
confirm: string;
|
|
958
964
|
tiers: PlanGrantsTierResult[];
|
|
965
|
+
/**
|
|
966
|
+
* The draft catalogue after the write. Grant edits land in the DRAFT and
|
|
967
|
+
* reach no reader until `POST /platform/billing/plans/publish`; absent on a
|
|
968
|
+
* dry run and on an identical replay.
|
|
969
|
+
*/
|
|
970
|
+
draft?: PlanCatalogueDraftSummary;
|
|
971
|
+
}
|
|
972
|
+
/** The template fields a draft carries per tier; provider ids and bookkeeping are never part of it. */
|
|
973
|
+
type PlanCatalogueTemplateField = 'name' | 'description' | 'displayOrder' | 'isActive' | 'isPopular' | 'color' | 'priceMonthlyCents' | 'priceAnnualCents' | 'currency';
|
|
974
|
+
/** One template field that differs between the published catalogue and the draft. `null` = absent. */
|
|
975
|
+
interface PlanCatalogueFieldChange {
|
|
976
|
+
field: PlanCatalogueTemplateField;
|
|
977
|
+
before: string | number | boolean | null;
|
|
978
|
+
after: string | number | boolean | null;
|
|
979
|
+
}
|
|
980
|
+
/** One tier the draft changes: its template fields and its effective grants, published → draft. */
|
|
981
|
+
interface PlanCatalogueTierDiff {
|
|
982
|
+
tier: PlanTier;
|
|
983
|
+
fields: PlanCatalogueFieldChange[];
|
|
984
|
+
changes: PlanGrantChange[];
|
|
985
|
+
}
|
|
986
|
+
/**
|
|
987
|
+
* The two revisions every draft mutation and publish is guarded on. `draftRevision`
|
|
988
|
+
* is `null` while no draft exists; `publishedRevision` is the current
|
|
989
|
+
* `publicationId`, `null` before the first publication. A request naming a stale
|
|
990
|
+
* pair is `409 PLAN_CATALOGUE_REVISION_CONFLICT` and writes nothing.
|
|
991
|
+
*/
|
|
992
|
+
interface PlanCatalogueRevisions {
|
|
993
|
+
draftRevision: string | null;
|
|
994
|
+
publishedRevision: string | null;
|
|
995
|
+
}
|
|
996
|
+
/** What a draft write answers alongside its own result. */
|
|
997
|
+
interface PlanCatalogueDraftSummary extends PlanCatalogueRevisions {
|
|
998
|
+
/** Whether the draft differs from the published catalogue at all. */
|
|
999
|
+
dirty: boolean;
|
|
1000
|
+
}
|
|
1001
|
+
/** `data` of `GET /platform/billing/plans/draft` and of the discard / restore mutations. */
|
|
1002
|
+
interface PlanCatalogueDraftResult extends PlanCatalogueDraftSummary {
|
|
1003
|
+
/** The published version number the draft would replace; `null` before the first publication. */
|
|
1004
|
+
publishedVersion: number | null;
|
|
1005
|
+
/** The publication the draft was restored from, until the next edit or publish. */
|
|
1006
|
+
restoredFrom: string | null;
|
|
1007
|
+
/**
|
|
1008
|
+
* Tiers whose published row changed since the draft was started (a direct
|
|
1009
|
+
* row write, or a publication racing the draft's first write). Non-empty means a publish is refused
|
|
1010
|
+
* `409 PLAN_CATALOGUE_DRAFT_STALE`: discard the draft, or restore a
|
|
1011
|
+
* publication into it.
|
|
1012
|
+
*/
|
|
1013
|
+
staleTiers: PlanTier[];
|
|
1014
|
+
/** Every operator who wrote this draft, first edit first. */
|
|
1015
|
+
editors: {
|
|
1016
|
+
userId: string;
|
|
1017
|
+
fullName: string;
|
|
1018
|
+
}[];
|
|
1019
|
+
/**
|
|
1020
|
+
* The draft rendered exactly as `GET /public/plans` would serve it once published. Its
|
|
1021
|
+
* `publicationId` is `null` while a draft exists (unpublished content is no publication; the
|
|
1022
|
+
* base it stands on is `publishedRevision`) and the published one when there is no draft.
|
|
1023
|
+
*/
|
|
1024
|
+
catalogue: PlanCatalogue;
|
|
1025
|
+
/** Per changed tier, published → draft. Empty when the draft is clean. */
|
|
1026
|
+
diff: PlanCatalogueTierDiff[];
|
|
1027
|
+
}
|
|
1028
|
+
/** Body of `POST /platform/billing/plans/draft/discard`. */
|
|
1029
|
+
interface PlanCatalogueDiscardInput {
|
|
1030
|
+
expectedDraftRevision: string | null;
|
|
1031
|
+
expectedPublishedRevision: string | null;
|
|
1032
|
+
}
|
|
1033
|
+
/** Body of `POST /platform/billing/plans/draft/restore`: copy a past publication into the draft. */
|
|
1034
|
+
interface PlanCatalogueRestoreInput extends PlanCatalogueDiscardInput {
|
|
1035
|
+
publicationId: string;
|
|
959
1036
|
}
|
|
1037
|
+
/** Body of `POST /platform/billing/plans/publish`. */
|
|
1038
|
+
interface PlanCataloguePublishInput extends PlanCatalogueDiscardInput {
|
|
1039
|
+
/** Idempotency key, a UUID: a retry with the same body answers the first result; a different body is `409 IDEMPOTENCY_CONFLICT`. */
|
|
1040
|
+
requestId: string;
|
|
1041
|
+
/** Screened operator reason (10-500 characters, no personal data); lands on the publication, the publication-level audit row, every changed tier's audit row and, on the first publish ever, version 1's `recordedReason`. */
|
|
1042
|
+
reason: string;
|
|
1043
|
+
/** Required on a live publish: the `confirm` string the dry run of the same draft returned. */
|
|
1044
|
+
confirm?: string;
|
|
1045
|
+
/** `true` writes nothing and returns the diff, the store counts, the impact and the `confirm` string. */
|
|
1046
|
+
dryRun?: boolean;
|
|
1047
|
+
}
|
|
1048
|
+
/** One changed tier in a publish result. */
|
|
1049
|
+
interface PlanCataloguePublishTierResult extends PlanCatalogueTierDiff {
|
|
1050
|
+
/** Stores on the tier, as `PlanGrantsTierResult.subscribedStores`. */
|
|
1051
|
+
subscribedStores: number;
|
|
1052
|
+
/** Dry run only: per reduced key, the stores it bites. */
|
|
1053
|
+
impact?: PlanGrantImpact[];
|
|
1054
|
+
/** As `PlanGrantsTierResult.truncated`, for the dry run's impact or the live follow-up. */
|
|
1055
|
+
truncated?: boolean;
|
|
1056
|
+
/** Live publish only: stores the `subscription` socket frame reached. */
|
|
1057
|
+
notifiedStores?: number;
|
|
1058
|
+
/** Live publish only, when `storefront` or `customDomain` changed: stores whose shop grace a reconcile settled. */
|
|
1059
|
+
reconciledStores?: number;
|
|
1060
|
+
/**
|
|
1061
|
+
* A paid tier whose price, currency or name changed, with a currency set on the draft being
|
|
1062
|
+
* published (never `basico`, never when that currency is absent): run the provider seeders
|
|
1063
|
+
* to mint its new prices.
|
|
1064
|
+
*/
|
|
1065
|
+
stripeSyncRequired: boolean;
|
|
1066
|
+
}
|
|
1067
|
+
/** `data` of `POST /platform/billing/plans/publish`. */
|
|
1068
|
+
interface PlanCataloguePublishResult {
|
|
1069
|
+
dryRun: boolean;
|
|
1070
|
+
written: boolean;
|
|
1071
|
+
/**
|
|
1072
|
+
* The comma-joined sorted changes a live publish must echo: each changed grant
|
|
1073
|
+
* key, and `<tier>.<field>` for each changed template field. Empty when only
|
|
1074
|
+
* the bootstrap would be written.
|
|
1075
|
+
*/
|
|
1076
|
+
confirm: string;
|
|
1077
|
+
/** The new current publication; `null` on a dry run. */
|
|
1078
|
+
publicationId: string | null;
|
|
1079
|
+
version: number | null;
|
|
1080
|
+
committedAt: string | null;
|
|
1081
|
+
/** `true` when this publish also recorded the pre-existing live catalogue as version 1. */
|
|
1082
|
+
bootstrapped: boolean;
|
|
1083
|
+
tiers: PlanCataloguePublishTierResult[];
|
|
1084
|
+
}
|
|
1085
|
+
/** One immutable publication in `GET /platform/billing/plans/publications`, newest first. */
|
|
1086
|
+
interface PlanCataloguePublicationEntry {
|
|
1087
|
+
publicationId: string;
|
|
1088
|
+
version: number;
|
|
1089
|
+
committedAt: string;
|
|
1090
|
+
actor: {
|
|
1091
|
+
userId: string;
|
|
1092
|
+
fullName: string;
|
|
1093
|
+
};
|
|
1094
|
+
reason: string;
|
|
1095
|
+
restoredFrom: string | null;
|
|
1096
|
+
/** Who wrote the draft this publication was made from; empty for the bootstrap (version 1). */
|
|
1097
|
+
draftEditors: {
|
|
1098
|
+
userId: string;
|
|
1099
|
+
fullName: string;
|
|
1100
|
+
}[];
|
|
1101
|
+
/**
|
|
1102
|
+
* Version 1 only: the operator whose publish captured the live rows, and
|
|
1103
|
+
* their reason — `actor` there is the system. `null` on every later
|
|
1104
|
+
* publication.
|
|
1105
|
+
*/
|
|
1106
|
+
recordedBy: {
|
|
1107
|
+
userId: string;
|
|
1108
|
+
fullName: string;
|
|
1109
|
+
} | null;
|
|
1110
|
+
recordedReason: string | null;
|
|
1111
|
+
/** The publication every reader serves now. */
|
|
1112
|
+
current: boolean;
|
|
1113
|
+
}
|
|
1114
|
+
interface PlanCataloguePublicationPage {
|
|
1115
|
+
items: PlanCataloguePublicationEntry[];
|
|
1116
|
+
cursor?: string;
|
|
1117
|
+
}
|
|
1118
|
+
/** `data` of a `409 PLAN_CATALOGUE_DRAFT_STALE`: the tiers whose published row changed since the draft started. */
|
|
1119
|
+
interface PlanCatalogueDraftStaleData {
|
|
1120
|
+
tiers: PlanTier[];
|
|
1121
|
+
}
|
|
1122
|
+
/** The `error` codes the plan catalogue draft / publish routes add. */
|
|
1123
|
+
type PlanCatalogueErrorCode = 'PLAN_CATALOGUE_REVISION_CONFLICT'
|
|
1124
|
+
/**
|
|
1125
|
+
* 409 · the publish commit was cancelled by a concurrent transaction
|
|
1126
|
+
* alone, on its attempt and its one retry. Nothing was written and no
|
|
1127
|
+
* revision moved: send the same request again.
|
|
1128
|
+
*/
|
|
1129
|
+
| 'PLAN_CATALOGUE_BUSY' | 'PLAN_CATALOGUE_NO_CHANGES' | 'PLAN_CATALOGUE_PUBLICATION_NOT_FOUND' | 'PLAN_CATALOGUE_REQUEST_EXPIRED' | 'PLAN_CATALOGUE_INVALID_CURSOR' | 'PLAN_CATALOGUE_DRAFT_STALE' | 'IDEMPOTENCY_CONFLICT';
|
|
960
1130
|
}
|
|
961
1131
|
export type BillingProviderName = SubscriptionProvider;
|
|
962
1132
|
export type InvoiceSummary = globalThis.InvoiceSummary;
|
|
@@ -968,6 +1138,10 @@ export declare const PLAN_TIERS: readonly ["basico", "emprendedor", "profesional
|
|
|
968
1138
|
* grace sweep's tier fan-out and the provider plan seeders all read it.
|
|
969
1139
|
*/
|
|
970
1140
|
export declare const PAID_PLAN_TIERS: readonly ["emprendedor", "profesional", "avanzado"];
|
|
1141
|
+
/** Every template field a plan catalogue draft carries, in the order a diff lists them. */
|
|
1142
|
+
export declare const PLAN_CATALOGUE_TEMPLATE_FIELDS: readonly ["name", "description", "displayOrder", "isActive", "isPopular", "color", "priceMonthlyCents", "priceAnnualCents", "currency"];
|
|
1143
|
+
/** Every `error` code the plan catalogue draft / publish routes add — the coverage test holds the handlers to it. */
|
|
1144
|
+
export declare const PLAN_CATALOGUE_ERROR_CODES: readonly ["PLAN_CATALOGUE_REVISION_CONFLICT", "PLAN_CATALOGUE_BUSY", "PLAN_CATALOGUE_NO_CHANGES", "PLAN_CATALOGUE_PUBLICATION_NOT_FOUND", "PLAN_CATALOGUE_REQUEST_EXPIRED", "PLAN_CATALOGUE_INVALID_CURSOR", "PLAN_CATALOGUE_DRAFT_STALE", "IDEMPOTENCY_CONFLICT"];
|
|
971
1145
|
/** Whether `value` names a paid tier — narrows an untyped read (a stored row, a global) to `PaidPlanTier`. */
|
|
972
1146
|
export declare const isPaidPlanTier: (value: unknown) => value is PaidPlanTier;
|
|
973
1147
|
/**
|
package/dist/subscription.js
CHANGED
|
@@ -53,6 +53,29 @@ export const PLAN_TIERS = exhaustiveTuple()(['basico', 'emprendedor', 'profesion
|
|
|
53
53
|
* grace sweep's tier fan-out and the provider plan seeders all read it.
|
|
54
54
|
*/
|
|
55
55
|
export const PAID_PLAN_TIERS = exhaustiveTuple()(['emprendedor', 'profesional', 'avanzado']);
|
|
56
|
+
/** Every template field a plan catalogue draft carries, in the order a diff lists them. */
|
|
57
|
+
export const PLAN_CATALOGUE_TEMPLATE_FIELDS = exhaustiveTuple()([
|
|
58
|
+
'name',
|
|
59
|
+
'description',
|
|
60
|
+
'displayOrder',
|
|
61
|
+
'isActive',
|
|
62
|
+
'isPopular',
|
|
63
|
+
'color',
|
|
64
|
+
'priceMonthlyCents',
|
|
65
|
+
'priceAnnualCents',
|
|
66
|
+
'currency',
|
|
67
|
+
]);
|
|
68
|
+
/** Every `error` code the plan catalogue draft / publish routes add — the coverage test holds the handlers to it. */
|
|
69
|
+
export const PLAN_CATALOGUE_ERROR_CODES = exhaustiveTuple()([
|
|
70
|
+
'PLAN_CATALOGUE_REVISION_CONFLICT',
|
|
71
|
+
'PLAN_CATALOGUE_BUSY',
|
|
72
|
+
'PLAN_CATALOGUE_NO_CHANGES',
|
|
73
|
+
'PLAN_CATALOGUE_PUBLICATION_NOT_FOUND',
|
|
74
|
+
'PLAN_CATALOGUE_REQUEST_EXPIRED',
|
|
75
|
+
'PLAN_CATALOGUE_INVALID_CURSOR',
|
|
76
|
+
'PLAN_CATALOGUE_DRAFT_STALE',
|
|
77
|
+
'IDEMPOTENCY_CONFLICT',
|
|
78
|
+
]);
|
|
56
79
|
/** Whether `value` names a paid tier — narrows an untyped read (a stored row, a global) to `PaidPlanTier`. */
|
|
57
80
|
export const isPaidPlanTier = (value) => typeof value === 'string' && PAID_PLAN_TIERS.includes(value);
|
|
58
81
|
/**
|