platform-types 1.10.700 → 1.10.701
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/cjs/subscription.js +69 -0
- package/dist/subscription.d.ts +134 -21
- package/dist/subscription.js +68 -1
- package/package.json +1 -1
package/dist/cjs/subscription.js
CHANGED
|
@@ -24,3 +24,72 @@
|
|
|
24
24
|
* enabled:false until they do.
|
|
25
25
|
*/
|
|
26
26
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.FEATURE_KEYS = exports.PLAN_TIERS = void 0;
|
|
28
|
+
/*
|
|
29
|
+
* Runtime tuples for the unions above.
|
|
30
|
+
*
|
|
31
|
+
* A union alone cannot be iterated, and any consumer that needs to enumerate
|
|
32
|
+
* every tier or key — zeroing a breakdown, fanning a query across tiers,
|
|
33
|
+
* rendering a pricing table's rows — otherwise hand-rolls its own copy that
|
|
34
|
+
* compiles fine while silently omitting a member. A missing member is not a
|
|
35
|
+
* visible break: it is a bucket that reads zero forever, or a row that never
|
|
36
|
+
* renders.
|
|
37
|
+
*
|
|
38
|
+
* ⚠️ `satisfies readonly PlanTier[]` alone does NOT catch that — it checks each
|
|
39
|
+
* element IS a tier, never that every tier is present. Hence `exhaustiveTuple`,
|
|
40
|
+
* whose second type parameter fails to resolve unless the tuple covers the
|
|
41
|
+
* union, making an omission a compile error at the tuple itself. Module-private
|
|
42
|
+
* on purpose: it is a type-level trick, not part of the published surface.
|
|
43
|
+
*/
|
|
44
|
+
const exhaustiveTuple = () => (tuple) => tuple;
|
|
45
|
+
/** Every plan tier, in rank order (lowest first). */
|
|
46
|
+
exports.PLAN_TIERS = exhaustiveTuple()(['basico', 'emprendedor', 'profesional', 'avanzado']);
|
|
47
|
+
/**
|
|
48
|
+
* Every gated feature key.
|
|
49
|
+
*
|
|
50
|
+
* ⚠️ Adding a member here is not the whole change, and `typecheck` is what
|
|
51
|
+
* stops it shipping half-done. In the api, a new key needs a grant in **every
|
|
52
|
+
* tier** of `PLAN_FEATURES` (`stacks/services/planFeatureMatrix.ts`): that
|
|
53
|
+
* constant is typed total over every `PlanTier` × `FeatureKey` cell, so a tier
|
|
54
|
+
* missing the new key's grant, or a grant of the wrong shape for the key's
|
|
55
|
+
* declared `type`, fails `typecheck` at the `PLAN_FEATURES` declaration
|
|
56
|
+
* itself. It also widens the api's per-store override key schema, so a new key
|
|
57
|
+
* immediately becomes a valid override target.
|
|
58
|
+
*
|
|
59
|
+
* ⚠️ **A new member also obliges an api PLATFORM-STACK deploy.** Entitlements
|
|
60
|
+
* resolve inside the Lambda authorizer, built in `PlatformStack`. Deploying only
|
|
61
|
+
* the handler stacks leaves a STALE authorizer running the previous matrix: the
|
|
62
|
+
* key is absent from the resolved map, where a boolean gate refuses but a
|
|
63
|
+
* metered / lifetime cap PASSES THROUGH — a new cap silently unbounded.
|
|
64
|
+
* Checklist: `docs/PLANS_AND_ENTITLEMENTS.md` in the api repo.
|
|
65
|
+
*/
|
|
66
|
+
exports.FEATURE_KEYS = [
|
|
67
|
+
'afipInvoicing',
|
|
68
|
+
'suppliers',
|
|
69
|
+
'advancedReports',
|
|
70
|
+
'cashManagement',
|
|
71
|
+
'importExport',
|
|
72
|
+
'domesticPayments',
|
|
73
|
+
'stripePayments',
|
|
74
|
+
'whatsappCommerce',
|
|
75
|
+
'aiFeatures',
|
|
76
|
+
'mobileApp',
|
|
77
|
+
'customBranding',
|
|
78
|
+
'customDomain',
|
|
79
|
+
'prioritySupport',
|
|
80
|
+
'advancedPricing',
|
|
81
|
+
'marketplaceChannels',
|
|
82
|
+
'storefront',
|
|
83
|
+
'loyalty',
|
|
84
|
+
'marketing',
|
|
85
|
+
'mandatory2fa',
|
|
86
|
+
'maxUsers',
|
|
87
|
+
'maxProducts',
|
|
88
|
+
'maxCustomers',
|
|
89
|
+
'maxWarehouses',
|
|
90
|
+
'priceListsMax',
|
|
91
|
+
'webhooks',
|
|
92
|
+
'maxOrdersMonth',
|
|
93
|
+
'maxInvoicesMonth',
|
|
94
|
+
'whatsappMessages',
|
|
95
|
+
];
|
package/dist/subscription.d.ts
CHANGED
|
@@ -62,9 +62,10 @@ declare global {
|
|
|
62
62
|
source?: 'plan' | 'override' | 'trial';
|
|
63
63
|
}
|
|
64
64
|
/**
|
|
65
|
-
* All gated features. Add new keys here when a new feature becomes gateable
|
|
66
|
-
*
|
|
67
|
-
*
|
|
65
|
+
* All gated features. Add new keys here when a new feature becomes gateable,
|
|
66
|
+
* and to the `FEATURE_KEYS` tuple below (`UncoveredFeatureKeys` fails
|
|
67
|
+
* `typecheck` naming the key until you do); the api's `PLAN_FEATURES` matrix
|
|
68
|
+
* must then grant it on every tier (typed total over `PlanTier` × `FeatureKey`).
|
|
68
69
|
*
|
|
69
70
|
* ⚠️ **`Record<FeatureKey, …>` is NOT the only construction a new member
|
|
70
71
|
* breaks, and searching for it alone will tell you a consumer is unaffected
|
|
@@ -148,28 +149,84 @@ declare global {
|
|
|
148
149
|
* booleans.
|
|
149
150
|
*/
|
|
150
151
|
type PlanFeatureStatus = 'live' | 'planned' | 'future' | 'service';
|
|
152
|
+
/** Singular/plural es-AR noun for a numeric/metered feature's count (e.g. `{ one: 'usuario', other: 'usuarios' }`). */
|
|
153
|
+
type PlanFeatureUnit = {
|
|
154
|
+
one: string;
|
|
155
|
+
other: string;
|
|
156
|
+
};
|
|
157
|
+
/**
|
|
158
|
+
* The window a limit counts over: `month` — a metered counter that resets
|
|
159
|
+
* monthly (e.g. orders); `active` — a numeric cap on rows that exist right
|
|
160
|
+
* now (e.g. products, users, depósitos — disabling one frees a slot).
|
|
161
|
+
*/
|
|
162
|
+
type PlanFeaturePeriod = 'month' | 'active';
|
|
151
163
|
/**
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
* unlimited).
|
|
164
|
+
* Section a feature row renders under on a pricing table. Each key's label
|
|
165
|
+
* and sort position travel as a {@link PlanFeatureGroup} in
|
|
166
|
+
* `PlanCatalogue.groups`, so a consumer never hard-codes either.
|
|
156
167
|
*/
|
|
157
|
-
|
|
168
|
+
type PlanFeatureGroupKey = 'limits' | 'billing' | 'channels' | 'operations' | 'growth' | 'enterprise';
|
|
169
|
+
interface PlanFeatureGroup {
|
|
170
|
+
key: PlanFeatureGroupKey;
|
|
171
|
+
/** User-facing Spanish heading. */
|
|
172
|
+
label: string;
|
|
173
|
+
/** Sort position among groups (ascending). */
|
|
174
|
+
order: number;
|
|
175
|
+
}
|
|
176
|
+
/** Fields every feature row carries, whatever its `type`. */
|
|
177
|
+
interface PlanFeatureBase {
|
|
158
178
|
key: FeatureKey;
|
|
159
|
-
type: EntitlementType;
|
|
160
179
|
status: PlanFeatureStatus;
|
|
180
|
+
/** Short user-facing Spanish name (the row's title on a pricing table). */
|
|
181
|
+
label: string;
|
|
161
182
|
/** User-facing Spanish description. */
|
|
162
183
|
description: string;
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
184
|
+
group: PlanFeatureGroupKey;
|
|
185
|
+
/** Sort position within `group` (ascending). `features[]` arrives already sorted by group order, then this. */
|
|
186
|
+
order: number;
|
|
187
|
+
/** `null` on boolean keys. */
|
|
188
|
+
unit: PlanFeatureUnit | null;
|
|
189
|
+
/** `null` on boolean keys. */
|
|
190
|
+
period: PlanFeaturePeriod | null;
|
|
191
|
+
/**
|
|
192
|
+
* The grant rendered server-side as an es-AR noun phrase, ready to print:
|
|
193
|
+
* `Ilimitado` for `-1`, `1 usuario`, `Hasta 2.000 pedidos por mes`,
|
|
194
|
+
* `Incluido` / `No incluido` for a boolean. Display copy only — compare
|
|
195
|
+
* grants through `enabled` / `limit`, never by parsing this.
|
|
196
|
+
*/
|
|
197
|
+
valueText: string;
|
|
167
198
|
}
|
|
168
199
|
/**
|
|
169
|
-
* A
|
|
170
|
-
* `
|
|
171
|
-
*
|
|
172
|
-
*
|
|
200
|
+
* A single feature row in a Plan's `features[]` array, discriminated on
|
|
201
|
+
* `type`: a boolean row carries `enabled` and no `limit` key; a
|
|
202
|
+
* numeric/metered row carries `limit` and no `enabled` key. `limit: -1` =
|
|
203
|
+
* unlimited.
|
|
204
|
+
*/
|
|
205
|
+
type PlanFeature = (PlanFeatureBase & {
|
|
206
|
+
type: 'boolean';
|
|
207
|
+
enabled: boolean;
|
|
208
|
+
}) | (PlanFeatureBase & {
|
|
209
|
+
type: 'numeric' | 'metered';
|
|
210
|
+
limit: number;
|
|
211
|
+
});
|
|
212
|
+
/**
|
|
213
|
+
* How a billing cycle of a plan can be bought:
|
|
214
|
+
*
|
|
215
|
+
* - `self` — self-serve checkout: the cycle has a charged price and the
|
|
216
|
+
* plan has a `currency`.
|
|
217
|
+
* - `sales` — the plan charges some cycle, but not this one self-serve
|
|
218
|
+
* (no price on it, or no `currency`); route to "Contactar ventas".
|
|
219
|
+
* - `none` — neither cycle is charged (the free tier); nothing to buy.
|
|
220
|
+
*/
|
|
221
|
+
type PlanCheckoutMode = 'self' | 'sales' | 'none';
|
|
222
|
+
/**
|
|
223
|
+
* A sellable plan in the catalog, exactly as `GET /subscription/plans` and
|
|
224
|
+
* `GET /public/plans` emit it — both build it with the same catalogue
|
|
225
|
+
* builder, so the two endpoints return identical plans. The template fields
|
|
226
|
+
* (copy, prices, flags) live in DynamoDB (`PLAN#{tier}` / `SK: PLAN`),
|
|
227
|
+
* administered via `POST /platform/billing/plans` +
|
|
228
|
+
* `PATCH /platform/billing/plans/{tier}`; `features` are code, rendered at
|
|
229
|
+
* response time.
|
|
173
230
|
*
|
|
174
231
|
* Prices are integers in the `currency` smallest unit (centavos for ARS,
|
|
175
232
|
* cents for USD). `null` = "Contactar ventas" (AVANZADO annual at launch
|
|
@@ -228,20 +285,51 @@ declare global {
|
|
|
228
285
|
*/
|
|
229
286
|
color: string | null;
|
|
230
287
|
/**
|
|
231
|
-
* Per-feature configuration. Every `FeatureKey` appears exactly once
|
|
232
|
-
*
|
|
288
|
+
* Per-feature configuration. Every `FeatureKey` appears exactly once,
|
|
289
|
+
* whatever its `status` — a `planned` / `future` key is sent too, so
|
|
290
|
+
* filter on `status` to decide what to advertise. Sorted by group order,
|
|
291
|
+
* then `order`. Boolean features carry `enabled`; numeric/metered carry
|
|
292
|
+
* `limit`.
|
|
233
293
|
*/
|
|
234
294
|
features: PlanFeature[];
|
|
235
295
|
/**
|
|
236
296
|
* Marketing-curated short bullets for the pricing card. Display order =
|
|
237
297
|
* array order; up to 6 entries, 80 chars each. Always present — empty array
|
|
238
298
|
* when unset (FE synthesizes a list from `features[]`). Lets marketing tweak
|
|
239
|
-
* copy via
|
|
299
|
+
* copy via `PATCH /platform/billing/plans/{tier}` without a redeploy;
|
|
300
|
+
* replaces the FE-only `BULLET_LIST_BY_TIER`.
|
|
240
301
|
*/
|
|
241
302
|
bullets: string[];
|
|
303
|
+
/**
|
|
304
|
+
* Keys worth calling out on this tier's card: highlight-eligible keys with
|
|
305
|
+
* status `live` or `service` whose grant improves on the next lower
|
|
306
|
+
* ACTIVE tier (by `displayOrder`; an `isActive: false` tier is skipped,
|
|
307
|
+
* as pricing pages hide it). The lowest active tier lists its own
|
|
308
|
+
* eligible keys. A `planned` / `future` key never appears. Each is a
|
|
309
|
+
* `features[]` key.
|
|
310
|
+
*/
|
|
311
|
+
highlights: FeatureKey[];
|
|
312
|
+
/** How each billing cycle can be bought — see {@link PlanCheckoutMode}. */
|
|
313
|
+
checkout: {
|
|
314
|
+
monthly: PlanCheckoutMode;
|
|
315
|
+
annual: PlanCheckoutMode;
|
|
316
|
+
};
|
|
317
|
+
/** Whether a subscription on this tier can be cancelled: `true` exactly when at least one cycle is charged. */
|
|
318
|
+
cancellable: boolean;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* `data` of `GET /public/plans` and `GET /subscription/plans` — both return
|
|
322
|
+
* the same `{ plans, groups }`: the plans plus the feature groups their rows
|
|
323
|
+
* render under.
|
|
324
|
+
*/
|
|
325
|
+
interface PlanCatalogue {
|
|
326
|
+
plans: Plan[];
|
|
327
|
+
/** Every group a `features[].group` can name, with its label and sort position. */
|
|
328
|
+
groups: PlanFeatureGroup[];
|
|
242
329
|
}
|
|
243
330
|
/**
|
|
244
|
-
* One audit row per
|
|
331
|
+
* One audit row per MANAGER-driven plan mutation (`POST` / `PATCH
|
|
332
|
+
* /platform/billing/plans`, `asManager`), returned by
|
|
245
333
|
* `GET /platform/billing/plans/{tier}/audit`. The store-subscription audit
|
|
246
334
|
* shares this storage shape but is read as `SubscriptionAuditEntry`.
|
|
247
335
|
* `before`/`after` carry only the fields that changed (diff slice).
|
|
@@ -648,3 +736,28 @@ declare global {
|
|
|
648
736
|
}
|
|
649
737
|
export type BillingProviderName = SubscriptionProvider;
|
|
650
738
|
export type InvoiceSummary = globalThis.InvoiceSummary;
|
|
739
|
+
/** Every plan tier, in rank order (lowest first). */
|
|
740
|
+
export declare const PLAN_TIERS: readonly ["basico", "emprendedor", "profesional", "avanzado"];
|
|
741
|
+
/**
|
|
742
|
+
* Every gated feature key.
|
|
743
|
+
*
|
|
744
|
+
* ⚠️ Adding a member here is not the whole change, and `typecheck` is what
|
|
745
|
+
* stops it shipping half-done. In the api, a new key needs a grant in **every
|
|
746
|
+
* tier** of `PLAN_FEATURES` (`stacks/services/planFeatureMatrix.ts`): that
|
|
747
|
+
* constant is typed total over every `PlanTier` × `FeatureKey` cell, so a tier
|
|
748
|
+
* missing the new key's grant, or a grant of the wrong shape for the key's
|
|
749
|
+
* declared `type`, fails `typecheck` at the `PLAN_FEATURES` declaration
|
|
750
|
+
* itself. It also widens the api's per-store override key schema, so a new key
|
|
751
|
+
* immediately becomes a valid override target.
|
|
752
|
+
*
|
|
753
|
+
* ⚠️ **A new member also obliges an api PLATFORM-STACK deploy.** Entitlements
|
|
754
|
+
* resolve inside the Lambda authorizer, built in `PlatformStack`. Deploying only
|
|
755
|
+
* the handler stacks leaves a STALE authorizer running the previous matrix: the
|
|
756
|
+
* key is absent from the resolved map, where a boolean gate refuses but a
|
|
757
|
+
* metered / lifetime cap PASSES THROUGH — a new cap silently unbounded.
|
|
758
|
+
* Checklist: `docs/PLANS_AND_ENTITLEMENTS.md` in the api repo.
|
|
759
|
+
*/
|
|
760
|
+
export declare const FEATURE_KEYS: readonly ["afipInvoicing", "suppliers", "advancedReports", "cashManagement", "importExport", "domesticPayments", "stripePayments", "whatsappCommerce", "aiFeatures", "mobileApp", "customBranding", "customDomain", "prioritySupport", "advancedPricing", "marketplaceChannels", "storefront", "loyalty", "marketing", "mandatory2fa", "maxUsers", "maxProducts", "maxCustomers", "maxWarehouses", "priceListsMax", "webhooks", "maxOrdersMonth", "maxInvoicesMonth", "whatsappMessages"];
|
|
761
|
+
type AssertNoUncoveredFeatureKey<T extends never> = T;
|
|
762
|
+
export type UncoveredFeatureKeys = AssertNoUncoveredFeatureKey<Exclude<FeatureKey, (typeof FEATURE_KEYS)[number]>>;
|
|
763
|
+
export {};
|
package/dist/subscription.js
CHANGED
|
@@ -22,4 +22,71 @@
|
|
|
22
22
|
* declared here even when their epics haven't shipped — the matrix can set
|
|
23
23
|
* enabled:false until they do.
|
|
24
24
|
*/
|
|
25
|
-
|
|
25
|
+
/*
|
|
26
|
+
* Runtime tuples for the unions above.
|
|
27
|
+
*
|
|
28
|
+
* A union alone cannot be iterated, and any consumer that needs to enumerate
|
|
29
|
+
* every tier or key — zeroing a breakdown, fanning a query across tiers,
|
|
30
|
+
* rendering a pricing table's rows — otherwise hand-rolls its own copy that
|
|
31
|
+
* compiles fine while silently omitting a member. A missing member is not a
|
|
32
|
+
* visible break: it is a bucket that reads zero forever, or a row that never
|
|
33
|
+
* renders.
|
|
34
|
+
*
|
|
35
|
+
* ⚠️ `satisfies readonly PlanTier[]` alone does NOT catch that — it checks each
|
|
36
|
+
* element IS a tier, never that every tier is present. Hence `exhaustiveTuple`,
|
|
37
|
+
* whose second type parameter fails to resolve unless the tuple covers the
|
|
38
|
+
* union, making an omission a compile error at the tuple itself. Module-private
|
|
39
|
+
* on purpose: it is a type-level trick, not part of the published surface.
|
|
40
|
+
*/
|
|
41
|
+
const exhaustiveTuple = () => (tuple) => tuple;
|
|
42
|
+
/** Every plan tier, in rank order (lowest first). */
|
|
43
|
+
export const PLAN_TIERS = exhaustiveTuple()(['basico', 'emprendedor', 'profesional', 'avanzado']);
|
|
44
|
+
/**
|
|
45
|
+
* Every gated feature key.
|
|
46
|
+
*
|
|
47
|
+
* ⚠️ Adding a member here is not the whole change, and `typecheck` is what
|
|
48
|
+
* stops it shipping half-done. In the api, a new key needs a grant in **every
|
|
49
|
+
* tier** of `PLAN_FEATURES` (`stacks/services/planFeatureMatrix.ts`): that
|
|
50
|
+
* constant is typed total over every `PlanTier` × `FeatureKey` cell, so a tier
|
|
51
|
+
* missing the new key's grant, or a grant of the wrong shape for the key's
|
|
52
|
+
* declared `type`, fails `typecheck` at the `PLAN_FEATURES` declaration
|
|
53
|
+
* itself. It also widens the api's per-store override key schema, so a new key
|
|
54
|
+
* immediately becomes a valid override target.
|
|
55
|
+
*
|
|
56
|
+
* ⚠️ **A new member also obliges an api PLATFORM-STACK deploy.** Entitlements
|
|
57
|
+
* resolve inside the Lambda authorizer, built in `PlatformStack`. Deploying only
|
|
58
|
+
* the handler stacks leaves a STALE authorizer running the previous matrix: the
|
|
59
|
+
* key is absent from the resolved map, where a boolean gate refuses but a
|
|
60
|
+
* metered / lifetime cap PASSES THROUGH — a new cap silently unbounded.
|
|
61
|
+
* Checklist: `docs/PLANS_AND_ENTITLEMENTS.md` in the api repo.
|
|
62
|
+
*/
|
|
63
|
+
export const FEATURE_KEYS = [
|
|
64
|
+
'afipInvoicing',
|
|
65
|
+
'suppliers',
|
|
66
|
+
'advancedReports',
|
|
67
|
+
'cashManagement',
|
|
68
|
+
'importExport',
|
|
69
|
+
'domesticPayments',
|
|
70
|
+
'stripePayments',
|
|
71
|
+
'whatsappCommerce',
|
|
72
|
+
'aiFeatures',
|
|
73
|
+
'mobileApp',
|
|
74
|
+
'customBranding',
|
|
75
|
+
'customDomain',
|
|
76
|
+
'prioritySupport',
|
|
77
|
+
'advancedPricing',
|
|
78
|
+
'marketplaceChannels',
|
|
79
|
+
'storefront',
|
|
80
|
+
'loyalty',
|
|
81
|
+
'marketing',
|
|
82
|
+
'mandatory2fa',
|
|
83
|
+
'maxUsers',
|
|
84
|
+
'maxProducts',
|
|
85
|
+
'maxCustomers',
|
|
86
|
+
'maxWarehouses',
|
|
87
|
+
'priceListsMax',
|
|
88
|
+
'webhooks',
|
|
89
|
+
'maxOrdersMonth',
|
|
90
|
+
'maxInvoicesMonth',
|
|
91
|
+
'whatsappMessages',
|
|
92
|
+
];
|