platform-types 1.10.705 → 1.10.706

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.
@@ -726,9 +726,10 @@ declare global {
726
726
  }
727
727
  /**
728
728
  * One tier's `SK: PLAN` template row, as assessed by
729
- * `report-plan-catalog-drift` (`POST /platform/operations`). Plan features
730
- * are code (`planFeatureMatrix.ts`) and cannot drift; the template row is
731
- * the only catalogue state a seeder/admin write can still leave stale.
729
+ * `report-plan-catalog-drift` (`POST /platform/operations`). Plan feature
730
+ * DEFAULTS are code (`planFeatureMatrix.ts`) and cannot drift; the template
731
+ * row — its live `grants` overlay included — is the only catalogue state a
732
+ * seeder/admin write can still leave stale.
732
733
  */
733
734
  interface TierCatalogDrift {
734
735
  tier: PlanTier;
@@ -742,6 +743,19 @@ declare global {
742
743
  * place to echo a catalogue's payment-provider IDs.
743
744
  */
744
745
  missingProviderIds: string[];
746
+ /**
747
+ * Keys in the template row's `grants` overlay that the api does not
748
+ * declare (retired or misspelt), sorted. Inert — every reader ignores them
749
+ * and the code default applies — but stored, so they are drift: a `null`
750
+ * for that key on `PATCH /platform/billing/plans/grants` removes them.
751
+ */
752
+ undeclaredGrantKeys: string[];
753
+ /**
754
+ * Declared keys whose overlay value has the wrong shape for their type
755
+ * (a `limit` on a boolean key, a fraction, `-2`), sorted. Ignored on read
756
+ * exactly like an undeclared key, and reported for the same reason.
757
+ */
758
+ malformedGrantKeys: string[];
745
759
  }
746
760
  /** One store holding at least one `OVERRIDE#` row under a key the api no longer declares. */
747
761
  interface OrphanOverrideStore {
@@ -788,7 +802,9 @@ declare global {
788
802
  interface PlanCatalogDriftReport {
789
803
  /**
790
804
  * True when ANY tier lacks a template row, a paid one is missing a provider
791
- * identifier, or any store holds an override under an undeclared key.
805
+ * identifier, a tier's `grants` overlay holds an undeclared key
806
+ * (`undeclaredGrantKeys`) or a wrong-shape value (`malformedGrantKeys`), or
807
+ * any store holds an override under an undeclared key.
792
808
  *
793
809
  * ⚠️ An UNBUILT roster (`orphanOverrides.rosterBuiltAt === null`) does not
794
810
  * flip this. A stage whose scan has never completed would otherwise answer
@@ -804,6 +820,112 @@ declare global {
804
820
  tiers: TierCatalogDrift[];
805
821
  orphanOverrides: OrphanOverrideDrift;
806
822
  }
823
+ /**
824
+ * One feature's grant on one tier, as `PATCH /platform/billing/plans/grants`
825
+ * takes and reports it: `{ enabled }` for a boolean key, `{ limit }` for a
826
+ * numeric or metered one (`-1` = unlimited).
827
+ */
828
+ type PlanGrantValue = {
829
+ enabled: boolean;
830
+ } | {
831
+ limit: number;
832
+ };
833
+ /**
834
+ * Body of `PATCH /platform/billing/plans/grants` (MANAGER). One request sets
835
+ * one or more keys on any tiers, atomically: `grants[key][tier]` is the new
836
+ * grant, or `null` to drop that tier's overlay entry (the code default
837
+ * applies again). A value equal to the code default is stored as no entry,
838
+ * so the overlay stays sparse. The final ladder of every changed key must
839
+ * rise with `displayOrder` (`FEATURE_LADDER_NON_MONOTONIC` otherwise).
840
+ */
841
+ interface PlanGrantsWriteRequest {
842
+ /**
843
+ * Keyed by feature key. A `string` key rather than `FeatureKey` because a
844
+ * `null` may name an undeclared key, to clear an inert overlay entry; a
845
+ * non-null value for one is refused (`PLAN_GRANT_UNKNOWN_KEY`).
846
+ */
847
+ grants: Record<string, Partial<Record<PlanTier, PlanGrantValue | null>>>;
848
+ /** Screened operator reason (10-500 characters, no personal data); lands in each tier's audit entry. */
849
+ reason: string;
850
+ /**
851
+ * Required on a live write: the comma-joined sorted keys the request
852
+ * changes — the string a dry run of the same body returns. It names the
853
+ * keys, not the tiers or values, so it proves the caller meant those keys;
854
+ * the dry run is where the tiers and the impact are reviewed.
855
+ */
856
+ confirm?: string;
857
+ /** `true` writes nothing and returns the impact plus the `confirm` string. */
858
+ dryRun?: boolean;
859
+ }
860
+ /** One key's effective grant on one tier, before and after the write. */
861
+ interface PlanGrantChange {
862
+ key: string;
863
+ /** `null` for an undeclared key — it has no effective grant on either side. */
864
+ before: PlanGrantValue | null;
865
+ after: PlanGrantValue | null;
866
+ }
867
+ /**
868
+ * Stores on a tier that a reduction would bite, for one key: they lose a
869
+ * boolean feature, or their current usage exceeds a lowered limit. Measured
870
+ * per store with its own overrides applied, so a store whose override keeps
871
+ * the old grant is not listed. A `readonly` / `canceled` store is never
872
+ * examined — its plan already lapsed, so the reduction takes nothing more.
873
+ */
874
+ interface PlanGrantImpact {
875
+ key: string;
876
+ storeIds: string[];
877
+ /**
878
+ * `false` for a lowered limit with no usage counter to compare against
879
+ * (`priceListsMax`): `storeIds` is then
880
+ * empty because nothing was measured, never because nothing is over.
881
+ */
882
+ measured: boolean;
883
+ }
884
+ /** One affected tier in a `PATCH /platform/billing/plans/grants` result. */
885
+ interface PlanGrantsTierResult {
886
+ tier: PlanTier;
887
+ changes: PlanGrantChange[];
888
+ /**
889
+ * Stores on this tier, any status: those whose SUBSCRIPTION row is on it
890
+ * (`planTier-status`) plus, on `profesional` — the tier a store with no
891
+ * SUBSCRIPTION row resolves to — every store with no row. A lower bound
892
+ * when `truncated`.
893
+ */
894
+ subscribedStores: number;
895
+ /** Dry run only: per reduced key, the stores it bites. Empty when nothing on this tier is reduced. */
896
+ impact?: PlanGrantImpact[];
897
+ /**
898
+ * Dry run: `impact` is a lower bound — more live stores than the walk
899
+ * examines (100), the request's time budget ran out, one store could not
900
+ * be read, or the tier's store list itself is short. Live write (present
901
+ * only when `true`): the follow-up did not reach every store — the budget
902
+ * ran out, a frame or grace reconcile failed, or the store list is short;
903
+ * a `PLAN_GRANTS_FANOUT_INCOMPLETE` error row carries the counts. On a
904
+ * `storefront` / `customDomain` change, every listed store it did not
905
+ * settle has a due-now grace entry the hourly storefront grace sweep
906
+ * reconciles (unless the row says some were not scheduled).
907
+ */
908
+ truncated?: boolean;
909
+ /** Live write only: how many stores the `subscription` socket frame was sent to. */
910
+ notifiedStores?: number;
911
+ /**
912
+ * Live write only, and only when the tier's `storefront` or `customDomain`
913
+ * changed: how many stores' shop grace a reconcile settled — written
914
+ * (a lost grant starts the 14-day grace; a regained one clears it) or
915
+ * already in line. A failed reconcile, a store gone, or a store the budget
916
+ * did not reach is not counted.
917
+ */
918
+ reconciledStores?: number;
919
+ }
920
+ /** `data` of `PATCH /platform/billing/plans/grants`. */
921
+ interface PlanGrantsWriteResult {
922
+ dryRun: boolean;
923
+ /** `false` on a dry run and on an identical replay (no change, no write, no audit). */
924
+ written: boolean;
925
+ /** The comma-joined sorted changed keys — what a live run must send as `confirm`. Empty when nothing changes. */
926
+ confirm: string;
927
+ tiers: PlanGrantsTierResult[];
928
+ }
807
929
  }
808
930
  export type BillingProviderName = SubscriptionProvider;
809
931
  export type InvoiceSummary = globalThis.InvoiceSummary;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "platform-types",
3
- "version": "1.10.705",
3
+ "version": "1.10.706",
4
4
  "description": "Shared wire and entity contracts for the platform.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",