@saasicat/core 1.0.0-rc.22 → 1.0.0-rc.24
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/README.md +1 -1
- package/dist/.build-stamp +1 -1
- package/dist/index.cjs +1323 -364
- package/dist/index.d.cts +1739 -133
- package/dist/index.d.ts +1739 -133
- package/dist/index.js +1264 -363
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -24,11 +24,17 @@ interface DateAtOrAfter {
|
|
|
24
24
|
interface DateAfter {
|
|
25
25
|
gt: Date;
|
|
26
26
|
}
|
|
27
|
-
/** `OR` block of the validity window; exactly one
|
|
27
|
+
/** `OR` block of the validity window; exactly one field per variant. */
|
|
28
28
|
type ValidityWindowClause = {
|
|
29
29
|
validFrom: DateAtOrBefore | null;
|
|
30
30
|
} | {
|
|
31
31
|
validUntil: DateAtOrAfter | null;
|
|
32
|
+
} | {
|
|
33
|
+
supersededAt: null;
|
|
34
|
+
} | {
|
|
35
|
+
validUntil: {
|
|
36
|
+
not: null;
|
|
37
|
+
};
|
|
32
38
|
};
|
|
33
39
|
/** Optional `OR` block for models with `endsAt` (precise admin termination). */
|
|
34
40
|
type EndsAtClause = {
|
|
@@ -60,6 +66,7 @@ interface ActivePlanVersionWhereWithEndsAt {
|
|
|
60
66
|
* `publishedAt IS NOT NULL`
|
|
61
67
|
* `(validFrom IS NULL OR validFrom <= asOf)`
|
|
62
68
|
* `(validUntil IS NULL OR validUntil >= startOfUtcDay(asOf))` // day-inclusive
|
|
69
|
+
* `(supersededAt IS NULL OR validUntil IS NOT NULL)` // superseded: only with a last day
|
|
63
70
|
* with `withEndsAt`: additionally `(endsAt IS NULL OR endsAt > asOf)`. // precise
|
|
64
71
|
*
|
|
65
72
|
* `planId` stays with the caller (repo-specific type). Matching Prisma
|
|
@@ -79,6 +86,22 @@ declare function buildActivePlanVersionWhere(asOf: Date, options: {
|
|
|
79
86
|
type ActiveVersionWhere = ActivePlanVersionWhere;
|
|
80
87
|
/** Model-neutral counterpart that additionally checks an `endsAt` timestamp. */
|
|
81
88
|
type ActiveVersionWhereWithEndsAt = ActivePlanVersionWhereWithEndsAt;
|
|
89
|
+
/** The dates of a version that decide whether it takes bookings, as a row carries them. */
|
|
90
|
+
interface VersionWindow {
|
|
91
|
+
validFrom?: string | Date | null;
|
|
92
|
+
validUntil?: string | Date | null;
|
|
93
|
+
endsAt?: string | Date | null;
|
|
94
|
+
supersededAt?: string | Date | null;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Whether a version that is published takes bookings at `asOf` — the same
|
|
98
|
+
* window {@link buildActivePlanVersionWhere} asks the database for, for a row
|
|
99
|
+
* already read: `validFrom` at or before `asOf`, `validUntil` not before the
|
|
100
|
+
* day of `asOf`, `endsAt` after `asOf`, and a superseded version only within
|
|
101
|
+
* a last day it carries. A date that is absent does not close the window.
|
|
102
|
+
* Whether the row is published is the caller's to know.
|
|
103
|
+
*/
|
|
104
|
+
declare function isVersionActiveAt(version: VersionWindow, asOf: Date): boolean;
|
|
82
105
|
/**
|
|
83
106
|
* Model-neutral alias for {@link buildActivePlanVersionWhere}. The original
|
|
84
107
|
* export remains available for backwards compatibility.
|
|
@@ -770,9 +793,18 @@ interface SelfServiceBlockedPlans {
|
|
|
770
793
|
* passed it in code" attached. The file is read at boot, so an edit lands on
|
|
771
794
|
* the next restart.
|
|
772
795
|
*/
|
|
796
|
+
/**
|
|
797
|
+
* Whether the operator may retire a plan version for the subscriptions already
|
|
798
|
+
* on it. It reaches contracts customers have made, so it rests on a clause in
|
|
799
|
+
* the operator's terms; `termsConfirmed` states that they carry it.
|
|
800
|
+
*/
|
|
801
|
+
interface OrderlyRetirementSettings {
|
|
802
|
+
termsConfirmed: boolean;
|
|
803
|
+
}
|
|
773
804
|
interface PlanCatalogTenantBilling {
|
|
774
805
|
cancellationNoticeDays: CancellationNoticePeriods;
|
|
775
806
|
selfServiceBlockedPlans: SelfServiceBlockedPlans;
|
|
807
|
+
orderlyRetirement: OrderlyRetirementSettings;
|
|
776
808
|
}
|
|
777
809
|
/**
|
|
778
810
|
* Who is told when the settings in the file change between two starts.
|
|
@@ -975,6 +1007,48 @@ interface PromoCodeValidationLog {
|
|
|
975
1007
|
createdAt: string;
|
|
976
1008
|
}
|
|
977
1009
|
|
|
1010
|
+
/**
|
|
1011
|
+
* A tenant's own limits beside its plan — a negotiated contract, a pilot.
|
|
1012
|
+
* `quotas[key]` replaces the plan's value for that quota, `-1` meaning
|
|
1013
|
+
* unlimited; `features` adds to the plan's. Stored as JSON in
|
|
1014
|
+
* `subscriptions.customLimits`.
|
|
1015
|
+
*/
|
|
1016
|
+
interface CustomLimits {
|
|
1017
|
+
quotas?: Record<QuotaKey, number>;
|
|
1018
|
+
features?: FeatureKey[];
|
|
1019
|
+
}
|
|
1020
|
+
/**
|
|
1021
|
+
* The keys a stored `customLimits` value is read by. The normative admin API
|
|
1022
|
+
* schema (`CustomLimits` in `@saasicat/spec`) is held to the same list.
|
|
1023
|
+
*/
|
|
1024
|
+
declare const CUSTOM_LIMITS_KEYS: readonly ["quotas", "features"];
|
|
1025
|
+
/** What a stored `customLimits` value gave, and what in it went unread. */
|
|
1026
|
+
interface ReadCustomLimits {
|
|
1027
|
+
limits: CustomLimits | null;
|
|
1028
|
+
/**
|
|
1029
|
+
* The parts of the stored value the platform does not read — a key it does
|
|
1030
|
+
* not know, or a `quotas`/`features` of the wrong kind. Empty when every
|
|
1031
|
+
* part was read.
|
|
1032
|
+
*/
|
|
1033
|
+
unread: string[];
|
|
1034
|
+
}
|
|
1035
|
+
/**
|
|
1036
|
+
* Reads a stored `customLimits` value the way the platform applies it.
|
|
1037
|
+
*
|
|
1038
|
+
* A shape the platform does not read is reported rather than refused: the
|
|
1039
|
+
* tenant keeps its plan's limits and goes on working, as a limit nothing can
|
|
1040
|
+
* count does not block anybody (`SC-ENTL-010`), and the caller says out loud
|
|
1041
|
+
* which limits were not applied. Each quota value goes through
|
|
1042
|
+
* `readQuotaValue`, the one reading of a quota in JSON.
|
|
1043
|
+
*/
|
|
1044
|
+
declare function readCustomLimits(value: unknown): ReadCustomLimits;
|
|
1045
|
+
/**
|
|
1046
|
+
* Reads stored limits for an adapter, and reports what went unread once per
|
|
1047
|
+
* subscription — every entitlement read passes through here, so reporting on
|
|
1048
|
+
* each would bury the one line an operator needs under thousands.
|
|
1049
|
+
*/
|
|
1050
|
+
declare function customLimitsReader(report: (line: string) => void): (subscriptionId: string, stored: unknown) => CustomLimits | null;
|
|
1051
|
+
|
|
978
1052
|
type SubscriptionStatus = 'TRIAL' | 'ACTIVE' | 'PAST_DUE' | 'CANCELED' | 'PENDING_SALES';
|
|
979
1053
|
interface Subscription {
|
|
980
1054
|
id: string;
|
|
@@ -984,8 +1058,8 @@ interface Subscription {
|
|
|
984
1058
|
planVersionId: string;
|
|
985
1059
|
billingCycle: BillingCycle;
|
|
986
1060
|
status: SubscriptionStatus;
|
|
987
|
-
/** Override per
|
|
988
|
-
customLimits?:
|
|
1061
|
+
/** Override per tenant; unset fields fall back to the PlanVersion. */
|
|
1062
|
+
customLimits?: CustomLimits | null;
|
|
989
1063
|
/** ENTERPRISE special contract. */
|
|
990
1064
|
customMonthlyNet?: number | null;
|
|
991
1065
|
isPilot: boolean;
|
|
@@ -996,15 +1070,7 @@ interface Subscription {
|
|
|
996
1070
|
canceledAt: string | null;
|
|
997
1071
|
currentPeriodStart: string | null;
|
|
998
1072
|
currentPeriodEnd: string | null;
|
|
999
|
-
/** Plan
|
|
1000
|
-
pendingPlanVersionId: string | null;
|
|
1001
|
-
pendingPlanVersionEffectiveAt: string | null;
|
|
1002
|
-
pendingPlanVersionAccepted: boolean;
|
|
1003
|
-
pendingPlanVersionAcceptedAt: string | null;
|
|
1004
|
-
pendingPlanVersionAcceptedByUserId: string | null;
|
|
1005
|
-
pendingPlanVersionNotifiedAt: string | null;
|
|
1006
|
-
pendingPlanVersionReminderSentAt: string | null;
|
|
1007
|
-
/** Plan change at period end (orthogonal to pendingPlanVersionId). */
|
|
1073
|
+
/** Plan change at period end. */
|
|
1008
1074
|
pendingPlanId: PlanId | null;
|
|
1009
1075
|
pendingBillingCycle: BillingCycle | null;
|
|
1010
1076
|
pendingEffectiveAt: string | null;
|
|
@@ -1067,7 +1133,7 @@ interface VersionedEntityBase {
|
|
|
1067
1133
|
* has become part of the contract. Optional for backwards-compat reasons;
|
|
1068
1134
|
* the helper defensively interprets `undefined` as `>0` (= frozen). How the
|
|
1069
1135
|
* adapter counts depends on the version type: PlanVersion via
|
|
1070
|
-
* `Subscription.planVersionId` (+ `
|
|
1136
|
+
* `Subscription.planVersionId` (+ `pendingChangeVersionId`), BundleVersion
|
|
1071
1137
|
* via the respective app-specific Subscription→Bundle binding.
|
|
1072
1138
|
*/
|
|
1073
1139
|
subscriptionCount?: number;
|
|
@@ -1514,7 +1580,7 @@ interface AdminManifest {
|
|
|
1514
1580
|
actions?: AuditActionDef[];
|
|
1515
1581
|
};
|
|
1516
1582
|
}
|
|
1517
|
-
type StandardPageKey = 'dashboard' | 'tenants' | 'subscriptions' | 'promoCodes' | 'plans' | 'audit' | 'users' | 'pilots' | 'discovery' | 'bundles' | 'marketingCatalog' | 'platformEmail' | 'platformEmailHistory' | 'settings';
|
|
1583
|
+
type StandardPageKey = 'dashboard' | 'tenants' | 'subscriptions' | 'promoCodes' | 'plans' | 'audit' | 'users' | 'pilots' | 'discovery' | 'bundles' | 'marketingCatalog' | 'platformEmail' | 'platformEmailHistory' | 'settings' | 'maintenance';
|
|
1518
1584
|
interface StandardPageDef {
|
|
1519
1585
|
enabled: boolean;
|
|
1520
1586
|
requiredCapability?: CapabilityKey;
|
|
@@ -1627,7 +1693,13 @@ interface AuditQuery {
|
|
|
1627
1693
|
entity?: string;
|
|
1628
1694
|
entityId?: string;
|
|
1629
1695
|
action?: string;
|
|
1630
|
-
/**
|
|
1696
|
+
/**
|
|
1697
|
+
* A tag, matched exactly, or a pattern with `*` at its start, its end or
|
|
1698
|
+
* both, matched without regard to case: `cli:*` is every entry from the
|
|
1699
|
+
* command line, `*:ops@example.com:*` every entry of one person, whatever
|
|
1700
|
+
* they acted through. Everything between the stars is literal. A tag reads
|
|
1701
|
+
* `<source>:<email>:<context>`.
|
|
1702
|
+
*/
|
|
1631
1703
|
actorTag?: string;
|
|
1632
1704
|
from?: string;
|
|
1633
1705
|
to?: string;
|
|
@@ -1780,6 +1852,23 @@ interface PromotionOnPrice {
|
|
|
1780
1852
|
*/
|
|
1781
1853
|
declare function promotionOnPrice(promotions: PromotionRow[], targetKey: string, locale: string, cycle: 'monthly' | 'yearly', basePrice: number | null, today?: Date, targetType?: PromotionTargetType): PromotionOnPrice | null;
|
|
1782
1854
|
|
|
1855
|
+
/** An amount as written, to the cent. */
|
|
1856
|
+
declare function roundToCents(amount: number): number;
|
|
1857
|
+
/** The terms added as written, exactly, and rounded once to the cent. */
|
|
1858
|
+
declare function sumToCents(...terms: number[]): number;
|
|
1859
|
+
/** The amount in whole cents, rounded once. */
|
|
1860
|
+
declare function toCents(amount: number): number;
|
|
1861
|
+
/** `percent` % of `amount`, to the cent — the discount a percentage takes off. */
|
|
1862
|
+
declare function percentOf(amount: number, percent: number): number;
|
|
1863
|
+
/** `amount × part / whole`, to the cent — a share of a period, say. */
|
|
1864
|
+
declare function prorate(amount: number, part: number, whole: number): number;
|
|
1865
|
+
/** Gross from net at a tax rate in per cent: net × (100 + rate) / 100. */
|
|
1866
|
+
declare function grossFromNet(net: number, vatRate: number): number;
|
|
1867
|
+
/** Net from gross at a tax rate in per cent: gross × 100 / (100 + rate). */
|
|
1868
|
+
declare function netFromGross(gross: number, vatRate: number): number;
|
|
1869
|
+
/** The tax a gross amount includes at a rate in per cent: gross × rate / (100 + rate). */
|
|
1870
|
+
declare function computeIncludedVat(gross: number, vatRate: number): number;
|
|
1871
|
+
|
|
1783
1872
|
type CheckoutOfferLineItemKind = 'plan' | 'bundle' | 'discount';
|
|
1784
1873
|
/** Frozen billable line item in the offer. */
|
|
1785
1874
|
interface CheckoutOfferLineItem {
|
|
@@ -2303,6 +2392,79 @@ declare function classifyPlanDiff(oldV: PlanVersionFields, newV: PlanVersionFiel
|
|
|
2303
2392
|
*/
|
|
2304
2393
|
declare function classifyBundleVersionDiff(oldV: BundleVersionFields, newV: BundleVersionFields): DiffResult;
|
|
2305
2394
|
|
|
2395
|
+
/**
|
|
2396
|
+
* - `improvement` — nothing dearer in any rhythm, no feature missing, no quota
|
|
2397
|
+
* lower. Taken at once and free, the term kept.
|
|
2398
|
+
* - `more-for-more` — nothing missing or lower, but dearer in at least one
|
|
2399
|
+
* rhythm. Taken like an upgrade: at once, the difference prorated. The rule
|
|
2400
|
+
* reads every rhythm, so in the subscriber's own the difference can be zero
|
|
2401
|
+
* or below — monthly 49 to 45 with yearly 490 to 500 is more for more for a
|
|
2402
|
+
* monthly subscriber too.
|
|
2403
|
+
* - `takes-something-away` — a feature missing or a quota lower, whatever the
|
|
2404
|
+
* price. Taken like a downgrade: at the end of the running term, and only
|
|
2405
|
+
* when the subscriber asks for it.
|
|
2406
|
+
* - `same` — the two agree on everything compared: there is nothing to offer.
|
|
2407
|
+
*/
|
|
2408
|
+
type VersionOfferClass = 'improvement' | 'more-for-more' | 'takes-something-away' | 'same';
|
|
2409
|
+
/**
|
|
2410
|
+
* A version as the comparison reads it. A price may be absent: that is a
|
|
2411
|
+
* rhythm the version is not sold in, and a rhythm that stops being sold counts
|
|
2412
|
+
* against the candidate like a price that went up.
|
|
2413
|
+
*/
|
|
2414
|
+
type VersionOfferFields = BundleVersionFields;
|
|
2415
|
+
interface VersionOffer {
|
|
2416
|
+
readonly class: VersionOfferClass;
|
|
2417
|
+
/** Every difference, bound to candidate, as the catalogue's diff states it. */
|
|
2418
|
+
readonly changes: readonly VersionChange[];
|
|
2419
|
+
}
|
|
2420
|
+
/** One version as a subscriber compares it. A price of null is a rhythm it is not sold in. */
|
|
2421
|
+
interface VersionOfferSide {
|
|
2422
|
+
readonly planVersionId: string;
|
|
2423
|
+
readonly version: number;
|
|
2424
|
+
readonly features: readonly string[];
|
|
2425
|
+
readonly quotas: Readonly<Record<string, number>>;
|
|
2426
|
+
readonly monthlyNet: number | null;
|
|
2427
|
+
readonly yearlyNet: number | null;
|
|
2428
|
+
/** The last day it is sold on, where a successor closes its window — ISO, the whole day included. */
|
|
2429
|
+
readonly validUntil: string | null;
|
|
2430
|
+
/** When an operator ended it, where one did — ISO; from then it is not sold. */
|
|
2431
|
+
readonly endsAt: string | null;
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* A newer version of the subscriber's plan, offered: the version bound and the
|
|
2435
|
+
* one offered side by side, what kind of offer it is, and when a switch taken
|
|
2436
|
+
* now would take effect — at once, or, for one that takes something away, at
|
|
2437
|
+
* the end of the running term. `GET billing/version-offer` answers with it.
|
|
2438
|
+
*/
|
|
2439
|
+
interface VersionOfferView {
|
|
2440
|
+
readonly plan: string;
|
|
2441
|
+
readonly bound: VersionOfferSide;
|
|
2442
|
+
readonly offered: VersionOfferSide;
|
|
2443
|
+
readonly class: Exclude<VersionOfferClass, 'same'>;
|
|
2444
|
+
readonly changes: readonly VersionChange[];
|
|
2445
|
+
/** ISO instant. */
|
|
2446
|
+
readonly takesEffectAt: string;
|
|
2447
|
+
}
|
|
2448
|
+
/**
|
|
2449
|
+
* What taking an offer did: the version left and the one taken, and whether it
|
|
2450
|
+
* applied at once or waits for `takesEffectAt`. `POST billing/version-offer/accept`
|
|
2451
|
+
* answers with it.
|
|
2452
|
+
*/
|
|
2453
|
+
interface VersionSwitchResult {
|
|
2454
|
+
readonly class: Exclude<VersionOfferClass, 'same'>;
|
|
2455
|
+
readonly fromPlanVersionId: string;
|
|
2456
|
+
readonly planVersionId: string;
|
|
2457
|
+
readonly immediate: boolean;
|
|
2458
|
+
/** ISO instant. */
|
|
2459
|
+
readonly takesEffectAt: string;
|
|
2460
|
+
}
|
|
2461
|
+
/**
|
|
2462
|
+
* Classifies `candidate` against `bound`. The comparison is the catalogue's
|
|
2463
|
+
* own diff — prices with a rhythm that may be absent, as a bundle version's
|
|
2464
|
+
* are — so an offer and a published version describe their changes alike.
|
|
2465
|
+
*/
|
|
2466
|
+
declare function classifyVersionOffer(bound: VersionOfferFields, candidate: VersionOfferFields): VersionOffer;
|
|
2467
|
+
|
|
2306
2468
|
interface PromoPreviewRequest {
|
|
2307
2469
|
/** Promo code (case-insensitive, normalized to uppercase in the service). */
|
|
2308
2470
|
code: string;
|
|
@@ -2443,6 +2605,560 @@ interface SettingsDifference {
|
|
|
2443
2605
|
after: unknown;
|
|
2444
2606
|
}
|
|
2445
2607
|
|
|
2608
|
+
/** One window, as a store reads it back. */
|
|
2609
|
+
interface MaintenanceWindowRecord {
|
|
2610
|
+
id: string;
|
|
2611
|
+
/** The announced start; null for a window locked without being announced first. */
|
|
2612
|
+
startsAt: Date | null;
|
|
2613
|
+
/** The announced, expected end; null where nobody said. */
|
|
2614
|
+
endsAt: Date | null;
|
|
2615
|
+
/** The operator's words to the tenants, shown as written; null for none. */
|
|
2616
|
+
message: string | null;
|
|
2617
|
+
/** When the window was recorded — announced, or locked at once. */
|
|
2618
|
+
createdAt: Date;
|
|
2619
|
+
/** Who recorded it, as the audit log tags an actor. */
|
|
2620
|
+
createdBy: string;
|
|
2621
|
+
/** When the lock began; null while the window is only announced. */
|
|
2622
|
+
lockedAt: Date | null;
|
|
2623
|
+
lockedBy: string | null;
|
|
2624
|
+
/** When the window was over — unlocked, or cancelled before it locked. */
|
|
2625
|
+
endedAt: Date | null;
|
|
2626
|
+
endedBy: string | null;
|
|
2627
|
+
}
|
|
2628
|
+
/** A window to record: it is open, so it has not ended. */
|
|
2629
|
+
type NewMaintenanceWindow = Omit<MaintenanceWindowRecord, 'id' | 'endedAt' | 'endedBy'>;
|
|
2630
|
+
/**
|
|
2631
|
+
* Where an open window stands. A write names the stage it expects, so that it
|
|
2632
|
+
* cannot move a window that moved on in the meantime — one that another
|
|
2633
|
+
* operator locked, unlocked or cancelled a moment earlier.
|
|
2634
|
+
*/
|
|
2635
|
+
type MaintenanceWindowStage = 'announced' | 'locked';
|
|
2636
|
+
/** What a write may change about an open window. */
|
|
2637
|
+
type MaintenanceWindowChanges = Partial<Pick<MaintenanceWindowRecord, 'startsAt' | 'endsAt' | 'message' | 'lockedAt' | 'lockedBy' | 'endedAt' | 'endedBy'>>;
|
|
2638
|
+
/**
|
|
2639
|
+
* What became of a window, read off its record. `cancelled` is a window that
|
|
2640
|
+
* ended without ever locking anybody out.
|
|
2641
|
+
*/
|
|
2642
|
+
type MaintenanceWindowStatus = 'announced' | 'locked' | 'ended' | 'cancelled';
|
|
2643
|
+
/**
|
|
2644
|
+
* What SaaSiCat tells the application about a window, so that it can write to
|
|
2645
|
+
* its own users — in its own words, from its own sender, in their language.
|
|
2646
|
+
* The lock itself is not among them: tenants see it in the application.
|
|
2647
|
+
*/
|
|
2648
|
+
type MaintenanceWindowEvent = {
|
|
2649
|
+
kind: 'announced';
|
|
2650
|
+
window: MaintenanceWindowRecord;
|
|
2651
|
+
} | {
|
|
2652
|
+
kind: 'rescheduled';
|
|
2653
|
+
window: MaintenanceWindowRecord;
|
|
2654
|
+
/** The window as it was announced before this change. */
|
|
2655
|
+
previous: MaintenanceWindowRecord;
|
|
2656
|
+
} | {
|
|
2657
|
+
kind: 'cancelled';
|
|
2658
|
+
window: MaintenanceWindowRecord;
|
|
2659
|
+
};
|
|
2660
|
+
/** The longest message a window carries; the operator's words, not a document. */
|
|
2661
|
+
declare const MAINTENANCE_MESSAGE_MAX_LENGTH = 500;
|
|
2662
|
+
/**
|
|
2663
|
+
* How long a process may go on reading a lock state it read before. Every
|
|
2664
|
+
* request asks, so each process keeps the answer this long rather than asking
|
|
2665
|
+
* the database per request; the command that locks waits this long before it
|
|
2666
|
+
* returns, so that every process has seen the lock by then.
|
|
2667
|
+
*
|
|
2668
|
+
* Part of the contract between two versions of an application: the command
|
|
2669
|
+
* that locks comes from the release being deployed, while the processes it
|
|
2670
|
+
* waits for may still run the one before. It is safe only while the figure it
|
|
2671
|
+
* waits by is at least theirs, so a later release may raise it and never lower
|
|
2672
|
+
* it.
|
|
2673
|
+
*/
|
|
2674
|
+
declare const MAINTENANCE_STATE_MAX_AGE_SECONDS = 5;
|
|
2675
|
+
/**
|
|
2676
|
+
* The manifest capability that announces the maintenance screen. The platform
|
|
2677
|
+
* sets it where it keeps maintenance windows, and the administration offers the
|
|
2678
|
+
* screen — and its lock banner — only where it is set.
|
|
2679
|
+
*/
|
|
2680
|
+
declare const MAINTENANCE_CAPABILITY = "maintenance.manage";
|
|
2681
|
+
/**
|
|
2682
|
+
* What a tenant's page is told: nothing, a window ahead, or a lock. Dates are
|
|
2683
|
+
* ISO strings, and `overrun` is the server's answer rather than the browser's,
|
|
2684
|
+
* whose clock is not the one the window was announced by.
|
|
2685
|
+
*/
|
|
2686
|
+
type MaintenanceStatusView = {
|
|
2687
|
+
state: 'none';
|
|
2688
|
+
} | {
|
|
2689
|
+
state: 'announced';
|
|
2690
|
+
startsAt: string;
|
|
2691
|
+
endsAt: string;
|
|
2692
|
+
message: string | null;
|
|
2693
|
+
} | {
|
|
2694
|
+
state: 'locked';
|
|
2695
|
+
lockedAt: string;
|
|
2696
|
+
/** The announced end; null where nobody said. */
|
|
2697
|
+
endsAt: string | null;
|
|
2698
|
+
message: string | null;
|
|
2699
|
+
/** The announced end has passed, and the lock still holds. */
|
|
2700
|
+
overrun: boolean;
|
|
2701
|
+
};
|
|
2702
|
+
/** A window as the administration shows it. */
|
|
2703
|
+
interface MaintenanceWindowView {
|
|
2704
|
+
id: string;
|
|
2705
|
+
status: MaintenanceWindowStatus;
|
|
2706
|
+
startsAt: string | null;
|
|
2707
|
+
endsAt: string | null;
|
|
2708
|
+
message: string | null;
|
|
2709
|
+
createdAt: string;
|
|
2710
|
+
createdBy: string;
|
|
2711
|
+
lockedAt: string | null;
|
|
2712
|
+
lockedBy: string | null;
|
|
2713
|
+
endedAt: string | null;
|
|
2714
|
+
endedBy: string | null;
|
|
2715
|
+
/** Locked, and past its announced end. */
|
|
2716
|
+
overrun: boolean;
|
|
2717
|
+
/** Announced, never locked, and past its announced end: tenants no longer see it. */
|
|
2718
|
+
lapsed: boolean;
|
|
2719
|
+
}
|
|
2720
|
+
/** `GET /admin/maintenance`: the open window, if any, and the ones before it. */
|
|
2721
|
+
interface MaintenanceOverview {
|
|
2722
|
+
open: MaintenanceWindowView | null;
|
|
2723
|
+
/** Newest first, the open one included. */
|
|
2724
|
+
recent: MaintenanceWindowView[];
|
|
2725
|
+
/** How long a lock takes to reach every process. */
|
|
2726
|
+
takesEffectWithinSeconds: number;
|
|
2727
|
+
}
|
|
2728
|
+
/** `POST /admin/maintenance/lock`: the locked window, and whether it was locked before. */
|
|
2729
|
+
interface MaintenanceLockView {
|
|
2730
|
+
window: MaintenanceWindowView;
|
|
2731
|
+
/** The lock already held; nothing was changed. */
|
|
2732
|
+
alreadyLocked: boolean;
|
|
2733
|
+
/** How long the lock takes to reach every process. */
|
|
2734
|
+
takesEffectWithinSeconds: number;
|
|
2735
|
+
}
|
|
2736
|
+
/** `POST /admin/maintenance/unlock`: the window it ended, or the open one it left alone. */
|
|
2737
|
+
interface MaintenanceUnlockView {
|
|
2738
|
+
window: MaintenanceWindowView | null;
|
|
2739
|
+
/** Whether a lock held and was ended by this call. */
|
|
2740
|
+
wasLocked: boolean;
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
/** What the switch costs, per period of the subscriber's rhythm. */
|
|
2744
|
+
interface RetirementSwitchTerms {
|
|
2745
|
+
/** The replacement's net price. */
|
|
2746
|
+
readonly priceNet: number;
|
|
2747
|
+
/**
|
|
2748
|
+
* Where the replacement costs more: the price the subscriber goes on paying,
|
|
2749
|
+
* the difference that is held, and the last day it is held — the day before
|
|
2750
|
+
* the date they were told. Null where it costs the same or less: its price
|
|
2751
|
+
* then applies from the subscriber's next period.
|
|
2752
|
+
*/
|
|
2753
|
+
readonly held: {
|
|
2754
|
+
readonly priceNet: number;
|
|
2755
|
+
readonly amountNet: number;
|
|
2756
|
+
readonly lastDay: string;
|
|
2757
|
+
} | null;
|
|
2758
|
+
}
|
|
2759
|
+
/**
|
|
2760
|
+
* What switching to the replacement now costs in `billingCycle`, or null where
|
|
2761
|
+
* the replacement has no price in it.
|
|
2762
|
+
*/
|
|
2763
|
+
declare function retirementSwitchTerms(notice: Pick<VersionRetiredNotice, 'retired' | 'replacement' | 'lastDayToCancel'>, billingCycle: string): RetirementSwitchTerms | null;
|
|
2764
|
+
|
|
2765
|
+
/** A version, as an announcement names it. */
|
|
2766
|
+
interface RetiredVersionRef {
|
|
2767
|
+
readonly planVersionId: string;
|
|
2768
|
+
readonly planKey: string;
|
|
2769
|
+
readonly version: number;
|
|
2770
|
+
}
|
|
2771
|
+
/** An announcement as it is kept: one per retirement, whoever it reaches. */
|
|
2772
|
+
interface VersionRetirementRecord {
|
|
2773
|
+
readonly id: string;
|
|
2774
|
+
/** The version retired. */
|
|
2775
|
+
readonly retired: RetiredVersionRef;
|
|
2776
|
+
/** The version its subscriptions continue on, named by the operator. */
|
|
2777
|
+
readonly replacement: RetiredVersionRef;
|
|
2778
|
+
readonly announcedAt: Date;
|
|
2779
|
+
/** Who announced it — an actor tag, as the audit log writes it. */
|
|
2780
|
+
readonly announcedBy: string;
|
|
2781
|
+
}
|
|
2782
|
+
type NewVersionRetirement = Omit<VersionRetirementRecord, 'id'>;
|
|
2783
|
+
/**
|
|
2784
|
+
* The manifest capability that announces retiring a version. The platform sets
|
|
2785
|
+
* it where it serves the routes, and the admin UI offers the action only where
|
|
2786
|
+
* it is set. Whether the operator's terms allow it is a blocker the preview
|
|
2787
|
+
* reports, so an operator who has not confirmed them learns what is missing.
|
|
2788
|
+
*/
|
|
2789
|
+
declare const VERSION_RETIREMENT_CAPABILITY = "planVersions.retire";
|
|
2790
|
+
/**
|
|
2791
|
+
* One of the two versions of a retirement, as the subscriber compares them:
|
|
2792
|
+
* price in each rhythm, quotas and features, with the plan it belongs to — the
|
|
2793
|
+
* replacement may be a version of another plan.
|
|
2794
|
+
*/
|
|
2795
|
+
interface RetirementSide extends VersionOfferSide {
|
|
2796
|
+
readonly planKey: string;
|
|
2797
|
+
}
|
|
2798
|
+
/**
|
|
2799
|
+
* A plan version a subscription is on is being retired, and the subscription
|
|
2800
|
+
* continues on the named replacement from its effective date. Sent once per
|
|
2801
|
+
* subscription and retirement, when the retirement is announced, and kept as
|
|
2802
|
+
* it was sent: the record shows what the subscriber was told, prices included.
|
|
2803
|
+
*/
|
|
2804
|
+
interface VersionRetiredNotice {
|
|
2805
|
+
readonly kind: 'version-retired';
|
|
2806
|
+
readonly tenantId: string;
|
|
2807
|
+
readonly subscriptionId: string;
|
|
2808
|
+
readonly retirementId: string;
|
|
2809
|
+
readonly retired: RetirementSide;
|
|
2810
|
+
readonly replacement: RetirementSide;
|
|
2811
|
+
/** Every difference, retired to replacement, as the catalogue's diff states it. */
|
|
2812
|
+
readonly changes: readonly VersionChange[];
|
|
2813
|
+
/**
|
|
2814
|
+
* The rhythm the subscription is billed in when the retirement takes
|
|
2815
|
+
* effect — a change of rhythm scheduled by then included — which says
|
|
2816
|
+
* which of the two prices applies.
|
|
2817
|
+
*/
|
|
2818
|
+
readonly billingCycle: string;
|
|
2819
|
+
/** ISO 8601. */
|
|
2820
|
+
readonly effectiveAt: string;
|
|
2821
|
+
/** ISO date (`YYYY-MM-DD`), UTC. */
|
|
2822
|
+
readonly lastDayToCancel: string;
|
|
2823
|
+
}
|
|
2824
|
+
/**
|
|
2825
|
+
* The one reminder of a retirement, where staying put costs the subscription
|
|
2826
|
+
* something (`SC-SUB-034`): sent 14 days before the retirement takes effect,
|
|
2827
|
+
* once per subscription and retired version. It says again what the
|
|
2828
|
+
* retirement notice said, and what a switch taken now would cost. Its
|
|
2829
|
+
* `billingCycle` is still the rhythm billed at the date, read again from the
|
|
2830
|
+
* subscription as it stands when the reminder is sent: a change of rhythm
|
|
2831
|
+
* scheduled since the announcement is in it.
|
|
2832
|
+
*/
|
|
2833
|
+
interface VersionRetirementReminder extends Omit<VersionRetiredNotice, 'kind'> {
|
|
2834
|
+
readonly kind: 'version-retirement-reminder';
|
|
2835
|
+
/**
|
|
2836
|
+
* What switching to the replacement now costs in the subscription's rhythm
|
|
2837
|
+
* (`SC-SUB-032`), or null where it cannot switch now: in a trial, with a
|
|
2838
|
+
* change scheduled, or where either plan is held for a special contract.
|
|
2839
|
+
*/
|
|
2840
|
+
readonly switchTerms: RetirementSwitchTerms | null;
|
|
2841
|
+
}
|
|
2842
|
+
/**
|
|
2843
|
+
* Why a retirement does not reach a subscription on the version:
|
|
2844
|
+
*
|
|
2845
|
+
* - `ended` — the subscription is over.
|
|
2846
|
+
* - `cancelled-before` — its cancellation lands by the effective date.
|
|
2847
|
+
* - `changes-before` — a scheduled change moves it to another plan, or to
|
|
2848
|
+
* another version of this one, by then.
|
|
2849
|
+
* - `no-term` — it carries no date a term can be counted from.
|
|
2850
|
+
* - `already-told` — an earlier announcement of this version reached it, and
|
|
2851
|
+
* stands.
|
|
2852
|
+
*/
|
|
2853
|
+
type RetirementSkipReason = 'ended' | 'cancelled-before' | 'changes-before' | 'no-term' | 'already-told';
|
|
2854
|
+
/** A refusal as the preview reports it and the announcement throws it. */
|
|
2855
|
+
interface RetirementBlocker {
|
|
2856
|
+
readonly code: string;
|
|
2857
|
+
readonly message: string;
|
|
2858
|
+
readonly params: Record<string, string | number>;
|
|
2859
|
+
}
|
|
2860
|
+
/** A subscription a retirement reaches, with what it means there. */
|
|
2861
|
+
interface RetirementReachedRow {
|
|
2862
|
+
readonly tenantId: string;
|
|
2863
|
+
readonly subscriptionId: string;
|
|
2864
|
+
readonly status: string;
|
|
2865
|
+
/** The rhythm it is billed in when the retirement takes effect. */
|
|
2866
|
+
readonly billingCycle: string;
|
|
2867
|
+
/** ISO 8601. */
|
|
2868
|
+
readonly effectiveAt: string;
|
|
2869
|
+
/** ISO date, UTC. */
|
|
2870
|
+
readonly lastDayToCancel: string;
|
|
2871
|
+
/** Reached by another retirement within the last twelve months: the announcement waits. */
|
|
2872
|
+
readonly reachedRecently: boolean;
|
|
2873
|
+
}
|
|
2874
|
+
/** A subscription on the version a retirement does not reach, and why. */
|
|
2875
|
+
interface RetirementSkippedRow {
|
|
2876
|
+
readonly tenantId: string;
|
|
2877
|
+
readonly subscriptionId: string;
|
|
2878
|
+
readonly reason: RetirementSkipReason;
|
|
2879
|
+
}
|
|
2880
|
+
/** What announcing a retirement now would do. */
|
|
2881
|
+
interface RetirementPreview {
|
|
2882
|
+
readonly retired: RetirementSide;
|
|
2883
|
+
readonly replacement: RetirementSide;
|
|
2884
|
+
/** Every difference, retired to replacement, as the subscribers will be told it. */
|
|
2885
|
+
readonly changes: readonly VersionChange[];
|
|
2886
|
+
/** ISO 8601: the moment it is computed for. */
|
|
2887
|
+
readonly asOf: string;
|
|
2888
|
+
readonly reached: readonly RetirementReachedRow[];
|
|
2889
|
+
readonly skipped: readonly RetirementSkippedRow[];
|
|
2890
|
+
/** Empty where it may be announced as it stands. */
|
|
2891
|
+
readonly blockers: readonly RetirementBlocker[];
|
|
2892
|
+
}
|
|
2893
|
+
/** What an announcement did. */
|
|
2894
|
+
interface RetirementAnnounced {
|
|
2895
|
+
readonly retirement: VersionRetirementRecord;
|
|
2896
|
+
/** Notices sent now; the rest are sent by the next run. */
|
|
2897
|
+
readonly told: number;
|
|
2898
|
+
readonly failed: number;
|
|
2899
|
+
}
|
|
2900
|
+
/**
|
|
2901
|
+
* How far a retirement has come, counted over the subscriptions it reached
|
|
2902
|
+
* (`SC-SUB-033`).
|
|
2903
|
+
*/
|
|
2904
|
+
interface RetirementProgress {
|
|
2905
|
+
/** Off the retired version: moved at their date, switched early, or changed on their own. */
|
|
2906
|
+
readonly moved: number;
|
|
2907
|
+
/** Still on the retired version, before their date. */
|
|
2908
|
+
readonly waiting: number;
|
|
2909
|
+
/** Still on the retired version after their date: the run has not moved them yet, or cannot. */
|
|
2910
|
+
readonly overdue: number;
|
|
2911
|
+
/** Still on the retired version, and ended by their date: there is nothing to move. */
|
|
2912
|
+
readonly ended: number;
|
|
2913
|
+
/**
|
|
2914
|
+
* Still on the retired version, and not told yet: their notice has reached
|
|
2915
|
+
* nobody, so their date is not set and nothing moves them (`SC-SUB-036`).
|
|
2916
|
+
*/
|
|
2917
|
+
readonly notTold: number;
|
|
2918
|
+
/**
|
|
2919
|
+
* Reminded 14 days before their date (`SC-SUB-034`) — counted beside the
|
|
2920
|
+
* four above, not instead of one: a subscription reminded moves later.
|
|
2921
|
+
*/
|
|
2922
|
+
readonly reminded: number;
|
|
2923
|
+
}
|
|
2924
|
+
/** An announcement as the administration lists it, with how far it has come. */
|
|
2925
|
+
interface VersionRetirementView extends VersionRetirementRecord {
|
|
2926
|
+
readonly progress: RetirementProgress;
|
|
2927
|
+
}
|
|
2928
|
+
/** What one run of the moves at the date did. */
|
|
2929
|
+
interface RetirementMoveRun {
|
|
2930
|
+
/** Subscriptions moved onto their replacement, with the contract the move writes. */
|
|
2931
|
+
readonly moved: number;
|
|
2932
|
+
/** Moves that could not be made, and are tried again by the next run. */
|
|
2933
|
+
readonly failed: number;
|
|
2934
|
+
}
|
|
2935
|
+
/** What switching to the replacement before the date did (`SC-SUB-032`). */
|
|
2936
|
+
interface RetirementSwitchResult {
|
|
2937
|
+
readonly fromPlanVersionId: string;
|
|
2938
|
+
readonly planVersionId: string;
|
|
2939
|
+
/** ISO date of the last day the price is held, or null where none is. */
|
|
2940
|
+
readonly heldUntilDay: string | null;
|
|
2941
|
+
}
|
|
2942
|
+
|
|
2943
|
+
/** What a notice is about. */
|
|
2944
|
+
type SubscriptionNoticeKind = 'version-offered' | 'version-retired' | 'version-retirement-reminder';
|
|
2945
|
+
/** Which notice: there is one per subscription, kind and subject. */
|
|
2946
|
+
interface SubscriptionNoticeKey {
|
|
2947
|
+
readonly tenantId: string;
|
|
2948
|
+
readonly subscriptionId: string;
|
|
2949
|
+
readonly kind: SubscriptionNoticeKind;
|
|
2950
|
+
/**
|
|
2951
|
+
* What it is about. For `version-offered`, the id of the version offered;
|
|
2952
|
+
* for `version-retired`, the id of the version retired — so a subscription
|
|
2953
|
+
* is told of a version's retirement once, whichever announcement it came
|
|
2954
|
+
* with. The announcement is in the notice as `retirementId`. For
|
|
2955
|
+
* `version-retirement-reminder`, the id of the version retired as well: a
|
|
2956
|
+
* subscription is reminded of a version's retirement once.
|
|
2957
|
+
*/
|
|
2958
|
+
readonly subject: string;
|
|
2959
|
+
}
|
|
2960
|
+
/** Who a notice went to and how, in the application's own terms. */
|
|
2961
|
+
interface SubscriptionNoticeDelivery {
|
|
2962
|
+
/** The addresses, or user ids, it was sent to. Empty where nobody could be told. */
|
|
2963
|
+
readonly recipients: readonly string[];
|
|
2964
|
+
/** The way it went — `email`, `in-app`, whatever the application calls it. */
|
|
2965
|
+
readonly channel: string;
|
|
2966
|
+
}
|
|
2967
|
+
/** A notice as it is kept. */
|
|
2968
|
+
interface SubscriptionNoticeRecord extends SubscriptionNoticeKey {
|
|
2969
|
+
readonly id: string;
|
|
2970
|
+
/** The notice as it was last handed to the application: a `SubscriptionNotice`. */
|
|
2971
|
+
readonly content: unknown;
|
|
2972
|
+
readonly createdAt: Date;
|
|
2973
|
+
/**
|
|
2974
|
+
* When a run took it on to deliver it. Null where no run holds it — before
|
|
2975
|
+
* the first attempt, and again after an attempt that failed.
|
|
2976
|
+
*/
|
|
2977
|
+
readonly claimedAt: Date | null;
|
|
2978
|
+
/** When the application confirmed it sent it; null until then. */
|
|
2979
|
+
readonly deliveredAt: Date | null;
|
|
2980
|
+
/** Who it went to and how; set together with `deliveredAt`. */
|
|
2981
|
+
readonly delivery: SubscriptionNoticeDelivery | null;
|
|
2982
|
+
}
|
|
2983
|
+
/**
|
|
2984
|
+
* A newer version of the subscription's plan is now offered to it. Sent once
|
|
2985
|
+
* per version, when the offer appears beside the plan — the notice and the
|
|
2986
|
+
* offer say the same thing.
|
|
2987
|
+
*/
|
|
2988
|
+
interface VersionOfferedNotice {
|
|
2989
|
+
readonly kind: 'version-offered';
|
|
2990
|
+
readonly tenantId: string;
|
|
2991
|
+
readonly subscriptionId: string;
|
|
2992
|
+
/** The offer as `GET billing/version-offer` answers it at the moment the notice is due. */
|
|
2993
|
+
readonly offer: VersionOfferView;
|
|
2994
|
+
}
|
|
2995
|
+
/** A notice handed to the application to send. */
|
|
2996
|
+
type SubscriptionNotice = VersionOfferedNotice | VersionRetiredNotice | VersionRetirementReminder;
|
|
2997
|
+
|
|
2998
|
+
/**
|
|
2999
|
+
* A `subscription_notices` row as either adapter reads it back. The two JSON
|
|
3000
|
+
* columns are `unknown`: the database holds whatever was written to them.
|
|
3001
|
+
*/
|
|
3002
|
+
interface CanonicalSubscriptionNoticeRow {
|
|
3003
|
+
id: string;
|
|
3004
|
+
tenantId: string;
|
|
3005
|
+
subscriptionId: string;
|
|
3006
|
+
kind: string;
|
|
3007
|
+
subject: string;
|
|
3008
|
+
content: unknown;
|
|
3009
|
+
createdAt: Date;
|
|
3010
|
+
claimedAt: Date | null;
|
|
3011
|
+
deliveredAt: Date | null;
|
|
3012
|
+
recipients: unknown;
|
|
3013
|
+
channel: string | null;
|
|
3014
|
+
}
|
|
3015
|
+
/**
|
|
3016
|
+
* Reads a row back as a record, naming each column rather than spreading the
|
|
3017
|
+
* row. The kind and the delivery are checked rather than cast: the record is
|
|
3018
|
+
* what a subscriber is later shown they were told, and a value nobody can read
|
|
3019
|
+
* must stop at the read and name its row.
|
|
3020
|
+
*/
|
|
3021
|
+
declare function toSubscriptionNoticeRecord(row: CanonicalSubscriptionNoticeRow): SubscriptionNoticeRecord;
|
|
3022
|
+
|
|
3023
|
+
/** The dates of a version that decide its state, as a row carries them. */
|
|
3024
|
+
interface VersionSaleDates extends VersionWindow {
|
|
3025
|
+
readonly publishedAt?: string | Date | null;
|
|
3026
|
+
}
|
|
3027
|
+
/**
|
|
3028
|
+
* Where a version stands. A day is an ISO date (`YYYY-MM-DD`, UTC):
|
|
3029
|
+
* - `scheduled` — published and not on sale yet; `from` is its first day.
|
|
3030
|
+
* - `on-sale` — on sale now; `until` is its last day, where one is known.
|
|
3031
|
+
* - `off-sale` — no longer on sale; `since` is its first day off sale, where
|
|
3032
|
+
* one is known — a version superseded without a last day has none.
|
|
3033
|
+
*/
|
|
3034
|
+
type VersionSale = {
|
|
3035
|
+
readonly kind: 'draft';
|
|
3036
|
+
} | {
|
|
3037
|
+
readonly kind: 'scheduled';
|
|
3038
|
+
readonly from: string;
|
|
3039
|
+
} | {
|
|
3040
|
+
readonly kind: 'on-sale';
|
|
3041
|
+
readonly until: string | null;
|
|
3042
|
+
} | {
|
|
3043
|
+
readonly kind: 'off-sale';
|
|
3044
|
+
readonly since: string | null;
|
|
3045
|
+
};
|
|
3046
|
+
type VersionSaleKind = VersionSale['kind'];
|
|
3047
|
+
/** The state of `version` at `now`. */
|
|
3048
|
+
declare function versionSale(version: VersionSaleDates, now: Date): VersionSale;
|
|
3049
|
+
/**
|
|
3050
|
+
* The version on sale at `now` among one plan's or add-on's versions, in the
|
|
3051
|
+
* order the platform picks it: the latest `validFrom`, a version without one
|
|
3052
|
+
* last, then the highest number.
|
|
3053
|
+
*/
|
|
3054
|
+
declare function versionOnSale<V extends VersionSaleDates & {
|
|
3055
|
+
readonly version?: number;
|
|
3056
|
+
}>(versions: readonly V[], now: Date): V | null;
|
|
3057
|
+
/**
|
|
3058
|
+
* What a listing shows for a plan or add-on: the version on sale, otherwise
|
|
3059
|
+
* the next one scheduled. A draft is not shown by this.
|
|
3060
|
+
*/
|
|
3061
|
+
declare function versionOnSaleOrNext<V extends VersionSaleDates & {
|
|
3062
|
+
readonly version?: number;
|
|
3063
|
+
}>(versions: readonly V[], now: Date): V | null;
|
|
3064
|
+
|
|
3065
|
+
/** A `version_retirements` row as either adapter reads it back. */
|
|
3066
|
+
interface CanonicalVersionRetirementRow {
|
|
3067
|
+
id: string;
|
|
3068
|
+
retiredPlanVersionId: string;
|
|
3069
|
+
retiredPlanKey: string;
|
|
3070
|
+
retiredVersion: number;
|
|
3071
|
+
replacementPlanVersionId: string;
|
|
3072
|
+
replacementPlanKey: string;
|
|
3073
|
+
replacementVersion: number;
|
|
3074
|
+
announcedAt: Date;
|
|
3075
|
+
announcedBy: string;
|
|
3076
|
+
}
|
|
3077
|
+
/** Reads a row back as a record, naming each column rather than spreading the row. */
|
|
3078
|
+
declare function toVersionRetirementRecord(row: CanonicalVersionRetirementRow): VersionRetirementRecord;
|
|
3079
|
+
|
|
3080
|
+
/** A scheduled change as a subscription row holds it. */
|
|
3081
|
+
interface ScheduledChangeColumns {
|
|
3082
|
+
readonly pendingPlan: string | null;
|
|
3083
|
+
readonly pendingBillingCycle: string | null;
|
|
3084
|
+
readonly pendingEffectiveAt: Date | null;
|
|
3085
|
+
readonly pendingChangeVersionId: string | null;
|
|
3086
|
+
}
|
|
3087
|
+
/** No change scheduled: what a plan change writes where it does not keep one. */
|
|
3088
|
+
declare const NO_SCHEDULED_CHANGE: ScheduledChangeColumns;
|
|
3089
|
+
/**
|
|
3090
|
+
* The scheduled-change columns a plan change writes onto `current`: all
|
|
3091
|
+
* cleared, unless the write keeps the change. A kept change is left as it is,
|
|
3092
|
+
* with one exception: a change that only moves the rhythm on the plan being
|
|
3093
|
+
* left — the plan it was scheduled on, no version named — follows the
|
|
3094
|
+
* subscription to its new plan. Recorded as it was, it would take the
|
|
3095
|
+
* subscription back to the plan it left when it comes due.
|
|
3096
|
+
*/
|
|
3097
|
+
declare function scheduledChangeAfterWrite(current: {
|
|
3098
|
+
readonly plan: string;
|
|
3099
|
+
} & ScheduledChangeColumns, input: {
|
|
3100
|
+
readonly planId: string;
|
|
3101
|
+
readonly keepsPendingChange?: boolean;
|
|
3102
|
+
}): Partial<ScheduledChangeColumns>;
|
|
3103
|
+
|
|
3104
|
+
/** How many days before a retirement takes effect its reminder is due. */
|
|
3105
|
+
declare const RETIREMENT_REMINDER_LEAD_DAYS = 14;
|
|
3106
|
+
/**
|
|
3107
|
+
* When the reminder of a retirement is due: 14 days before it takes effect, at
|
|
3108
|
+
* the same time of day. UTC has no change of clocks, so that is the effective
|
|
3109
|
+
* day less 14 calendar days.
|
|
3110
|
+
*/
|
|
3111
|
+
declare function retirementReminderDueAt(notice: Pick<VersionRetiredNotice, 'effectiveAt'>): Date;
|
|
3112
|
+
/**
|
|
3113
|
+
* Whether the reminder is due at `now`: from its day until the retirement
|
|
3114
|
+
* takes effect. A run that did not happen on the day is caught up by the next
|
|
3115
|
+
* one before the date; after it there is nothing left to remind of.
|
|
3116
|
+
*/
|
|
3117
|
+
declare function retirementReminderIsDue(notice: Pick<VersionRetiredNotice, 'effectiveAt'>, now: Date): boolean;
|
|
3118
|
+
/**
|
|
3119
|
+
* Whether staying put costs the subscription something when the retirement
|
|
3120
|
+
* takes effect (D9): the replacement takes a feature or a quota away, or is
|
|
3121
|
+
* dearer in `billingCycle`, the rhythm it is billed in then — or not sold in
|
|
3122
|
+
* it. A price that rises only in another rhythm costs it nothing.
|
|
3123
|
+
*/
|
|
3124
|
+
declare function retirementCostsTheSubscription(notice: Pick<VersionRetiredNotice, 'retired' | 'replacement' | 'changes' | 'lastDayToCancel'>, billingCycle: string): boolean;
|
|
3125
|
+
|
|
3126
|
+
/** A `maintenance_windows` row as either adapter reads it back. */
|
|
3127
|
+
type CanonicalMaintenanceWindowRow = MaintenanceWindowRecord;
|
|
3128
|
+
/**
|
|
3129
|
+
* Reads a row back as a record, naming each column rather than spreading the
|
|
3130
|
+
* row: a column a later release adds is not handed to the platform by accident,
|
|
3131
|
+
* and a version reading the table a later release extended reads what it knows.
|
|
3132
|
+
*/
|
|
3133
|
+
declare function toMaintenanceWindowRecord(row: CanonicalMaintenanceWindowRow): MaintenanceWindowRecord;
|
|
3134
|
+
|
|
3135
|
+
/** What became of a window. */
|
|
3136
|
+
declare function maintenanceWindowStatusOf(window: MaintenanceWindowRecord): MaintenanceWindowStatus;
|
|
3137
|
+
/** Whether the lock still holds after the end it announced. */
|
|
3138
|
+
declare function isMaintenanceOverrun(window: MaintenanceWindowRecord, now: Date): boolean;
|
|
3139
|
+
/**
|
|
3140
|
+
* Whether an announcement has lapsed: never locked, and its announced end has
|
|
3141
|
+
* passed. Tenants are no longer shown it — past information is noise — while
|
|
3142
|
+
* the operator is, because it still stands in the way of the next one.
|
|
3143
|
+
*/
|
|
3144
|
+
declare function isMaintenanceAnnouncementLapsed(window: MaintenanceWindowRecord, now: Date): boolean;
|
|
3145
|
+
/** What a tenant's page is told, given the open window — or none. */
|
|
3146
|
+
declare function maintenanceStatusOf(open: MaintenanceWindowRecord | null, now: Date): MaintenanceStatusView;
|
|
3147
|
+
/** A window as the administration shows it. */
|
|
3148
|
+
declare function maintenanceWindowViewOf(window: MaintenanceWindowRecord, now: Date): MaintenanceWindowView;
|
|
3149
|
+
/**
|
|
3150
|
+
* Seconds until the announced end, for the `Retry-After` of a refused request.
|
|
3151
|
+
* Never less than one: a client told zero would retry at once, in a loop.
|
|
3152
|
+
*/
|
|
3153
|
+
declare function maintenanceRetryAfterSeconds(window: MaintenanceWindowRecord, now: Date): number;
|
|
3154
|
+
|
|
3155
|
+
/**
|
|
3156
|
+
* The moment an ISO 8601 date and time names, provided it states its zone —
|
|
3157
|
+
* `2026-10-02T22:00+02:00` or `2026-10-02T20:00Z`. Null for anything else: a
|
|
3158
|
+
* date without a time, a time without a zone, or text that is not a date.
|
|
3159
|
+
*/
|
|
3160
|
+
declare function parseZonedInstant(text: string): Date | null;
|
|
3161
|
+
|
|
2446
3162
|
/**
|
|
2447
3163
|
* The top-level blocks of `config/saas.yaml` that are the catalogue rather than
|
|
2448
3164
|
* the configuration, and the format marker.
|
|
@@ -2555,11 +3271,8 @@ interface PlanVersionRow extends VersionedEntityBase {
|
|
|
2555
3271
|
* `endsAt` is user-initiated: `POST /admin/catalog/plan-versions/:id/terminate`
|
|
2556
3272
|
* sets the field. When `endsAt < NOW()` the version is no longer live for
|
|
2557
3273
|
* new bookings — existing subscriptions (P1) stay bound.
|
|
2558
|
-
*
|
|
2559
|
-
* Optional, because consumer backends add the column additively — if it
|
|
2560
|
-
* is missing, there is no end date.
|
|
2561
3274
|
*/
|
|
2562
|
-
endsAt
|
|
3275
|
+
endsAt: string | null;
|
|
2563
3276
|
/** @deprecated Read from `quotas['users']` once available. */
|
|
2564
3277
|
maxUsers?: number;
|
|
2565
3278
|
/** @deprecated Legacy field; read from `quotas['vehicles']`. */
|
|
@@ -2624,12 +3337,12 @@ interface PlanCatalogReadSnapshot {
|
|
|
2624
3337
|
/** Plan stems (deletedAt IS NULL). */
|
|
2625
3338
|
plans: PlanRow[];
|
|
2626
3339
|
/**
|
|
2627
|
-
*
|
|
2628
|
-
*
|
|
2629
|
-
*
|
|
2630
|
-
*
|
|
3340
|
+
* Per `planId` (= planKey) the version on sale at the moment the snapshot
|
|
3341
|
+
* was asked for — the rule of `PlanRepository.findActivePlanVersion`, so
|
|
3342
|
+
* the catalogue names the version a booking made at that moment binds.
|
|
3343
|
+
* A plan with nothing on sale is taken over without pricing or quotas.
|
|
2631
3344
|
*/
|
|
2632
|
-
|
|
3345
|
+
versionsOnSale: PlanVersionRow[];
|
|
2633
3346
|
/** Feature catalog entries (deletedAt IS NULL). */
|
|
2634
3347
|
featureEntries: FeatureCatalogEntryRow[];
|
|
2635
3348
|
}
|
|
@@ -2638,7 +3351,8 @@ interface PlanCatalogReadSnapshot {
|
|
|
2638
3351
|
* implement it against their Prisma tables.
|
|
2639
3352
|
*/
|
|
2640
3353
|
interface PlanCatalogReadSink {
|
|
2641
|
-
|
|
3354
|
+
/** The catalogue as it stands at `asOf`. */
|
|
3355
|
+
loadSnapshot(asOf: Date): Promise<PlanCatalogReadSnapshot>;
|
|
2642
3356
|
}
|
|
2643
3357
|
|
|
2644
3358
|
/**
|
|
@@ -2897,13 +3611,34 @@ interface EmailPort {
|
|
|
2897
3611
|
}
|
|
2898
3612
|
/** Adapter for MFA secret persistence. */
|
|
2899
3613
|
interface MfaPort {
|
|
2900
|
-
/**
|
|
3614
|
+
/**
|
|
3615
|
+
* Returns the stored secret or null. What is stored is the value the
|
|
3616
|
+
* platform handed to `setSecret`: sealed by the installation's
|
|
3617
|
+
* `SecretSealer`, and opened by the platform, not here.
|
|
3618
|
+
*/
|
|
2901
3619
|
getSecret(userId: string): Promise<string | null>;
|
|
2902
|
-
/** Persists or deletes (null) the
|
|
3620
|
+
/** Persists or deletes (null) the sealed secret, as it is given. */
|
|
2903
3621
|
setSecret(userId: string, secret: string | null): Promise<void>;
|
|
2904
3622
|
/** The platform calls this during the mfa-setup command. */
|
|
2905
3623
|
isEnabled(userId: string): Promise<boolean>;
|
|
2906
3624
|
}
|
|
3625
|
+
/**
|
|
3626
|
+
* Seals a secret before it is stored and opens it after it is read.
|
|
3627
|
+
*
|
|
3628
|
+
* The TOTP secret of a SuperAdmin is the second factor of the accounts that can
|
|
3629
|
+
* change every tenant's plan, codes and contracts. Stored as it is, whoever
|
|
3630
|
+
* holds a dump, a backup or a replica holds it too, and the second factor adds
|
|
3631
|
+
* nothing against them. The key stays with the installation — in its
|
|
3632
|
+
* configuration, not in the database the sealed value lives in.
|
|
3633
|
+
*
|
|
3634
|
+
* `open` refuses what it did not seal: a value from another key, a format it
|
|
3635
|
+
* does not know, a secret stored before sealing. The platform then treats the
|
|
3636
|
+
* code as wrong and the administrator enrols again.
|
|
3637
|
+
*/
|
|
3638
|
+
interface SecretSealer {
|
|
3639
|
+
seal(plain: string): Promise<string>;
|
|
3640
|
+
open(sealed: string): Promise<string>;
|
|
3641
|
+
}
|
|
2907
3642
|
/**
|
|
2908
3643
|
* Opaque transaction context. The consumer determines the concrete type
|
|
2909
3644
|
* (e.g. `Prisma.TransactionClient`). Platform code only passes it
|
|
@@ -3034,8 +3769,18 @@ interface PromoCodeRedemptionListItem extends PromoCodeRedemptionRecord {
|
|
|
3034
3769
|
*/
|
|
3035
3770
|
interface PromoCodeRepository {
|
|
3036
3771
|
findById(id: string): Promise<PromoCodeRecord | null>;
|
|
3772
|
+
/**
|
|
3773
|
+
* The code with this name, deleted ones included: a deleted code keeps its
|
|
3774
|
+
* name (`SC-PROMO-028`), so the platform's duplicate check has to see it.
|
|
3775
|
+
* Every caller that redeems or previews checks `deletedAt` itself.
|
|
3776
|
+
*/
|
|
3037
3777
|
findByCode(code: string, tx?: TransactionContext): Promise<PromoCodeRecord | null>;
|
|
3038
3778
|
findMany(filter: PromoCodeFilter): Promise<PromoCodeRecord[]>;
|
|
3779
|
+
/**
|
|
3780
|
+
* Refuses a name that is taken — by a live or a deleted code — with
|
|
3781
|
+
* `promoCodeTaken`: two creates can pass the platform's duplicate check
|
|
3782
|
+
* together, and the second one's answer is the refusal, not a driver error.
|
|
3783
|
+
*/
|
|
3039
3784
|
create(data: CreatePromoCodeData): Promise<PromoCodeRecord>;
|
|
3040
3785
|
update(id: string, data: UpdatePromoCodeData): Promise<PromoCodeRecord>;
|
|
3041
3786
|
softDelete(id: string): Promise<void>;
|
|
@@ -3057,7 +3802,8 @@ interface PromoCodeRepository {
|
|
|
3057
3802
|
releaseSlot(id: string, tx?: TransactionContext): Promise<void>;
|
|
3058
3803
|
/**
|
|
3059
3804
|
* Bulk-expire cron: sets all codes with `validUntil < now` and status
|
|
3060
|
-
* ACTIVE/PAUSED to EXPIRED
|
|
3805
|
+
* ACTIVE/PAUSED to EXPIRED, leaving deleted codes as they were — a write
|
|
3806
|
+
* to a row the operator removed. Returns: number of updated rows.
|
|
3061
3807
|
*/
|
|
3062
3808
|
expireDueCodes(now: Date): Promise<number>;
|
|
3063
3809
|
}
|
|
@@ -3157,7 +3903,14 @@ interface PromoCodeHoldRepository {
|
|
|
3157
3903
|
interface PromoCodeRedemptionRepository {
|
|
3158
3904
|
findBySubscription(subscriptionId: string, tx?: TransactionContext): Promise<PromoCodeRedemptionRecord | null>;
|
|
3159
3905
|
create(data: Omit<PromoCodeRedemptionRecord, 'id' | 'redeemedAt' | 'status' | 'reversedAt'>, tx?: TransactionContext): Promise<PromoCodeRedemptionRecord>;
|
|
3160
|
-
|
|
3906
|
+
/**
|
|
3907
|
+
* Marks the redemption reversed while it is not reversed yet, in one
|
|
3908
|
+
* conditional statement, and answers with it; `null` where it already was.
|
|
3909
|
+
* Two reversals of one redemption at the same moment then find one winner,
|
|
3910
|
+
* and only the winner gives the slot back — without the claim both would,
|
|
3911
|
+
* and a limited code would gain a slot it never issued.
|
|
3912
|
+
*/
|
|
3913
|
+
setReversed(id: string, tx?: TransactionContext): Promise<PromoCodeRedemptionRecord | null>;
|
|
3161
3914
|
countByPromoCode(promoCodeId: string, status?: PromoCodeRedemptionStatus): Promise<number>;
|
|
3162
3915
|
listByPromoCode(promoCodeId: string): Promise<PromoCodeRedemptionListItem[]>;
|
|
3163
3916
|
expireDueRedemptions(now: Date): Promise<number>;
|
|
@@ -3356,8 +4109,21 @@ interface CreateSubscriptionContractData {
|
|
|
3356
4109
|
/** What a repository writes: the contract as asked for, with the parties the platform copied. */
|
|
3357
4110
|
interface NewSubscriptionContractData extends CreateSubscriptionContractData {
|
|
3358
4111
|
parties: SubscriptionContractParties;
|
|
4112
|
+
/**
|
|
4113
|
+
* The parties are a copy the migration made rather than what was agreed —
|
|
4114
|
+
* set where a successor takes them over from a contract that says so, so
|
|
4115
|
+
* that the copy is not passed off as agreed one contract later. Absent
|
|
4116
|
+
* means `false`.
|
|
4117
|
+
*/
|
|
4118
|
+
partiesMigrated?: boolean;
|
|
3359
4119
|
}
|
|
3360
4120
|
interface TerminateSubscriptionContractData {
|
|
4121
|
+
/**
|
|
4122
|
+
* The tenant the caller read the contract under. The write matches it as
|
|
4123
|
+
* well as the id, so an id that reaches the call by mistake cannot end
|
|
4124
|
+
* another tenant's contract, whether or not a row policy would stop it.
|
|
4125
|
+
*/
|
|
4126
|
+
tenantId: string;
|
|
3361
4127
|
effectiveUntil: Date;
|
|
3362
4128
|
/**
|
|
3363
4129
|
* The terminal status, or `null` to end the contract by date alone.
|
|
@@ -3374,6 +4140,25 @@ interface TerminateSubscriptionContractData {
|
|
|
3374
4140
|
*/
|
|
3375
4141
|
status: Extract<SubscriptionContractStatus, 'terminated' | 'superseded'> | null;
|
|
3376
4142
|
}
|
|
4143
|
+
/**
|
|
4144
|
+
* Ends a contract because a successor takes its place — on the condition that
|
|
4145
|
+
* it is still as the caller read it.
|
|
4146
|
+
*/
|
|
4147
|
+
interface SupersedeSubscriptionContractData {
|
|
4148
|
+
/**
|
|
4149
|
+
* The tenant the caller read the contract under. The write matches it as
|
|
4150
|
+
* well as the id, so an id that reaches the call by mistake cannot end
|
|
4151
|
+
* another tenant's contract, whether or not a row policy would stop it.
|
|
4152
|
+
*/
|
|
4153
|
+
tenantId: string;
|
|
4154
|
+
/** When the successor takes over; written as the contract's `effectiveUntil`. */
|
|
4155
|
+
at: Date;
|
|
4156
|
+
/**
|
|
4157
|
+
* The `effectiveUntil` the caller read. A contract whose end moved since —
|
|
4158
|
+
* a cancellation capped it, or ended it — is not superseded.
|
|
4159
|
+
*/
|
|
4160
|
+
readEffectiveUntil: Date | null;
|
|
4161
|
+
}
|
|
3377
4162
|
interface SubscriptionContractFilter {
|
|
3378
4163
|
tenantId?: string;
|
|
3379
4164
|
status?: SubscriptionContractStatus;
|
|
@@ -3663,10 +4448,7 @@ interface SubscriptionRecord {
|
|
|
3663
4448
|
trialEntitlementPlan?: string | null;
|
|
3664
4449
|
pendingPlan?: string | null;
|
|
3665
4450
|
pendingEffectiveAt?: Date | null;
|
|
3666
|
-
customLimits?:
|
|
3667
|
-
quotas?: Record<string, number>;
|
|
3668
|
-
features?: string[];
|
|
3669
|
-
} | null;
|
|
4451
|
+
customLimits?: CustomLimits | null;
|
|
3670
4452
|
planVersionId: string;
|
|
3671
4453
|
planVersion: PlanVersionRecord;
|
|
3672
4454
|
/**
|
|
@@ -3710,7 +4492,8 @@ interface SubscriptionRepository {
|
|
|
3710
4492
|
findByTenantIdLocked(tenantId: string, tx: TransactionContext): Promise<SubscriptionRecord | null>;
|
|
3711
4493
|
/**
|
|
3712
4494
|
* Counts subscriptions that bind a specific PlanVersion — both
|
|
3713
|
-
* via the active `planVersionId` and via the scheduled
|
|
4495
|
+
* via the active `planVersionId` and via the version a scheduled change will
|
|
4496
|
+
* bind (`pendingChangeVersionId`).
|
|
3714
4497
|
* Needed by the `PlanVersionsService` for the editability decision:
|
|
3715
4498
|
* a published-but-future PlanVersion stays correctable only as long
|
|
3716
4499
|
* as no booking references it.
|
|
@@ -3720,6 +4503,14 @@ interface SubscriptionRepository {
|
|
|
3720
4503
|
* frozen (fail-closed). Implementation hint: count in a single
|
|
3721
4504
|
* COUNT(*) over the subscription table with an OR over the two
|
|
3722
4505
|
* FK columns — not in two separate queries, to avoid race conditions.
|
|
4506
|
+
*
|
|
4507
|
+
* Counts across every tenant. The platform calls it inside
|
|
4508
|
+
* `RlsBypassPort`; an implementation on a tenant-scoped client has to see
|
|
4509
|
+
* every tenant's rows there. Whether the frame lifts the policy for this
|
|
4510
|
+
* query is up to the application's bypass and the database layer behind it
|
|
4511
|
+
* — one that lifts only reads such as `find*` leaves a `count` filtered, and
|
|
4512
|
+
* then the implementation lifts the policy itself. A subscriber hidden from
|
|
4513
|
+
* the count counts as nobody, which opens the version for editing.
|
|
3723
4514
|
*/
|
|
3724
4515
|
countByPlanVersionId?(planVersionId: string): Promise<number>;
|
|
3725
4516
|
/**
|
|
@@ -3739,6 +4530,9 @@ interface SubscriptionRepository {
|
|
|
3739
4530
|
*
|
|
3740
4531
|
* Optional — if not implemented, the service defensively treats the
|
|
3741
4532
|
* version as frozen (fail-closed).
|
|
4533
|
+
*
|
|
4534
|
+
* Counts across every tenant, inside `RlsBypassPort`, and has to see every
|
|
4535
|
+
* tenant's rows there, as `countByPlanVersionId` does.
|
|
3742
4536
|
*/
|
|
3743
4537
|
countByBundleVersionId?(bundleVersionId: string): Promise<number>;
|
|
3744
4538
|
/**
|
|
@@ -3749,8 +4543,9 @@ interface SubscriptionRepository {
|
|
|
3749
4543
|
* (subscriptions on superseded versions are included).
|
|
3750
4544
|
*
|
|
3751
4545
|
* Returns a map `planKey → count`; plans without an active subscription
|
|
3752
|
-
* are missing (UI defaults to 0). Platform-wide count across all tenants
|
|
3753
|
-
*
|
|
4546
|
+
* are missing (UI defaults to 0). Platform-wide count across all tenants:
|
|
4547
|
+
* the platform calls it inside `RlsBypassPort`, and an implementation has to
|
|
4548
|
+
* see every tenant's rows there, as for `countByPlanVersionId`.
|
|
3754
4549
|
*
|
|
3755
4550
|
* Optional — if not implemented, the tenant column stays 0.
|
|
3756
4551
|
*/
|
|
@@ -3826,6 +4621,22 @@ interface SubscriptionContractRepository {
|
|
|
3826
4621
|
*/
|
|
3827
4622
|
findByOriginalOfferId(offerId: string, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
|
|
3828
4623
|
terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
|
|
4624
|
+
/**
|
|
4625
|
+
* Ends a contract at `data.at` with the status `superseded`, where it is
|
|
4626
|
+
* still as the caller read it: `active` or `scheduled`, and ending when it
|
|
4627
|
+
* ended then. `null`, with nothing written, where it has moved since —
|
|
4628
|
+
* another successor took its place, or a cancellation capped or ended it.
|
|
4629
|
+
*
|
|
4630
|
+
* The condition belongs to the write rather than to a read before it. Two
|
|
4631
|
+
* callers superseding one contract at once — a plan change and an
|
|
4632
|
+
* operator's refresh, say — then end with one successor: the second write
|
|
4633
|
+
* finds the status the first one left and changes nothing, where a read
|
|
4634
|
+
* followed by a plain update would give the tenant two contracts in force.
|
|
4635
|
+
*
|
|
4636
|
+
* With `tx`, written on that transaction and undone with it, so that the
|
|
4637
|
+
* successor written beside it lands with it or not at all.
|
|
4638
|
+
*/
|
|
4639
|
+
supersede(contractId: string, data: SupersedeSubscriptionContractData, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
|
|
3829
4640
|
/**
|
|
3830
4641
|
* The contracts concluded and not yet over, with the issuer each was
|
|
3831
4642
|
* concluded under: how many there are, and the first `limit` of them,
|
|
@@ -3848,8 +4659,8 @@ interface SubscriptionContractRepository {
|
|
|
3848
4659
|
*
|
|
3849
4660
|
* Platform-wide: unlike every other read here it is anchored by no tenant,
|
|
3850
4661
|
* no contract and no offer, and a start makes it before anything is served.
|
|
3851
|
-
* An implementation on a tenant-scoped client
|
|
3852
|
-
* `countActiveByPlanKey`
|
|
4662
|
+
* An implementation on a tenant-scoped client counts inside the bypass
|
|
4663
|
+
* frame, as `countActiveByPlanKey` does — the platform wraps the call in
|
|
3853
4664
|
* `RlsBypassPort`, and one that answers with the caller's tenant scope
|
|
3854
4665
|
* instead returns nothing at a boot, where there is no tenant. The
|
|
3855
4666
|
* persistence contract runs with no policy forced, so it cannot catch that
|
|
@@ -3926,7 +4737,7 @@ interface SubscriberLedgerRepository {
|
|
|
3926
4737
|
*
|
|
3927
4738
|
* The platform controller `GET /billing/usage` maps this form 1:1 into the
|
|
3928
4739
|
* response body. The consumer adapter loads from its own subscription
|
|
3929
|
-
* table (Prisma include planVersion
|
|
4740
|
+
* table (Prisma include planVersion).
|
|
3930
4741
|
*/
|
|
3931
4742
|
interface SubscriptionUsageRecord {
|
|
3932
4743
|
/**
|
|
@@ -3985,6 +4796,17 @@ interface SubscriptionUsageRecord {
|
|
|
3985
4796
|
pendingPlan: string | null;
|
|
3986
4797
|
pendingBillingCycle: string | null;
|
|
3987
4798
|
pendingEffectiveAt: Date | null;
|
|
4799
|
+
/**
|
|
4800
|
+
* The version a scheduled change binds when it lands, where it names one —
|
|
4801
|
+
* a newer version taken for the end of the term, or the version a change
|
|
4802
|
+
* to another plan was quoted at. Read where it matters whether the
|
|
4803
|
+
* subscription stays on its version: a change on the same plan in the same
|
|
4804
|
+
* rhythm is otherwise indistinguishable from staying put.
|
|
4805
|
+
*
|
|
4806
|
+
* Optional, because an adapter written before it does not pass it through;
|
|
4807
|
+
* both shipped adapters do.
|
|
4808
|
+
*/
|
|
4809
|
+
pendingChangeVersionId?: string | null;
|
|
3988
4810
|
planVersion: {
|
|
3989
4811
|
id: string;
|
|
3990
4812
|
planId: string;
|
|
@@ -3993,18 +4815,6 @@ interface SubscriptionUsageRecord {
|
|
|
3993
4815
|
supersededAt: Date | null;
|
|
3994
4816
|
changeNote: string | null;
|
|
3995
4817
|
};
|
|
3996
|
-
pendingPlanVersion: {
|
|
3997
|
-
id: string;
|
|
3998
|
-
planId: string;
|
|
3999
|
-
version: number;
|
|
4000
|
-
nonRegressive: boolean;
|
|
4001
|
-
changeNote: string | null;
|
|
4002
|
-
/** Catalog diff form from version-publish; free-form JSON structure. */
|
|
4003
|
-
publishedChanges: unknown;
|
|
4004
|
-
} | null;
|
|
4005
|
-
pendingPlanVersionEffectiveAt: Date | null;
|
|
4006
|
-
pendingPlanVersionAccepted: boolean;
|
|
4007
|
-
pendingPlanVersionAcceptedAt: Date | null;
|
|
4008
4818
|
/**
|
|
4009
4819
|
* P11.4: frozen package snapshot from the
|
|
4010
4820
|
* `CheckoutOffer` that was activated during onboarding. Read-only —
|
|
@@ -4025,8 +4835,34 @@ interface SubscriptionUsageRecord {
|
|
|
4025
4835
|
* Read adapter for the UI/display form of a subscription. Used by
|
|
4026
4836
|
* `TenantBillingController.getUsage`.
|
|
4027
4837
|
*/
|
|
4838
|
+
/** A subscription read across tenants, with the tenant it belongs to. */
|
|
4839
|
+
interface TenantSubscriptionUsage {
|
|
4840
|
+
readonly tenantId: string;
|
|
4841
|
+
readonly subscription: SubscriptionUsageRecord & {
|
|
4842
|
+
readonly id: string;
|
|
4843
|
+
};
|
|
4844
|
+
}
|
|
4028
4845
|
interface SubscriptionUsagePort {
|
|
4029
4846
|
findForTenant(tenantId: string): Promise<SubscriptionUsageRecord | null>;
|
|
4847
|
+
/**
|
|
4848
|
+
* Every subscription of `planKey`, in every tenant, bound to a version of
|
|
4849
|
+
* that plan numbered below `version`. The platform reads it to find the
|
|
4850
|
+
* subscriptions a newer version is offered to, inside the RLS bypass.
|
|
4851
|
+
*
|
|
4852
|
+
* Optional, so a port written before it keeps working; an application that
|
|
4853
|
+
* turns version notices on over a port without it is refused at start-up.
|
|
4854
|
+
*/
|
|
4855
|
+
listBoundToEarlierVersions?(planKey: string, version: number): Promise<TenantSubscriptionUsage[]>;
|
|
4856
|
+
/**
|
|
4857
|
+
* Every subscription, in every tenant, bound to the plan version
|
|
4858
|
+
* `planVersionId`, whatever its status. The platform reads it to find the
|
|
4859
|
+
* subscriptions a retirement reaches, inside the RLS bypass, and decides
|
|
4860
|
+
* itself which of them are still running.
|
|
4861
|
+
*
|
|
4862
|
+
* Optional, so a port written before it keeps working; a retirement over a
|
|
4863
|
+
* port without it is refused at start-up.
|
|
4864
|
+
*/
|
|
4865
|
+
listBoundToVersion?(planVersionId: string): Promise<TenantSubscriptionUsage[]>;
|
|
4030
4866
|
}
|
|
4031
4867
|
/**
|
|
4032
4868
|
* Returns the current usage for all quotaKeys of a tenant declared via
|
|
@@ -4072,14 +4908,98 @@ interface ImmediatePlanChangeInput {
|
|
|
4072
4908
|
* no cancellation, and loses against one that has acquired one.
|
|
4073
4909
|
*/
|
|
4074
4910
|
expectedCanceledAt: Date | null;
|
|
4911
|
+
/**
|
|
4912
|
+
* Whether a change that leaves the plan as it is keeps the plan version
|
|
4913
|
+
* the subscription is bound to.
|
|
4914
|
+
*
|
|
4915
|
+
* A scheduled change that only moves the rhythm passes `true`: the
|
|
4916
|
+
* subscriber agreed to the version they are on, and moving them to a newer
|
|
4917
|
+
* one is theirs to decide, by taking it when it is offered. A sale passes
|
|
4918
|
+
* `false` — a change of plan, or onboarding, where the customer chose at
|
|
4919
|
+
* the version in effect — and the write binds the version of `planId` in effect at
|
|
4920
|
+
* `periodStart`. Where `planId` is another plan than the one bound, the
|
|
4921
|
+
* version in effect is bound either way, and so it is where the
|
|
4922
|
+
* subscription is bound to no version at all: it has none to keep.
|
|
4923
|
+
*/
|
|
4924
|
+
keepsBoundVersion: boolean;
|
|
4925
|
+
/**
|
|
4926
|
+
* The version of `planId` the change was quoted at: a scheduled change to
|
|
4927
|
+
* another plan passes the version its preview showed when it was
|
|
4928
|
+
* scheduled, recorded as `pendingChangeVersionId`. The write binds it
|
|
4929
|
+
* rather than the version in effect, so a version published in between
|
|
4930
|
+
* does not reach the customer by a change they already agreed to. `null`
|
|
4931
|
+
* binds the version in effect — a sale, onboarding, and a change quoted
|
|
4932
|
+
* where no repository reads versions. A version kept by
|
|
4933
|
+
* `keepsBoundVersion` wins over it.
|
|
4934
|
+
*/
|
|
4935
|
+
quotedPlanVersionId: string | null;
|
|
4936
|
+
/**
|
|
4937
|
+
* `true`: bind `quotedPlanVersionId` or nothing. Where that version no
|
|
4938
|
+
* longer takes bookings by `periodStart` (or now), the write claims nothing
|
|
4939
|
+
* and answers `claimed: false`, rather than binding the version in effect.
|
|
4940
|
+
* A switch to a version offered passes it: the subscriber agreed to that
|
|
4941
|
+
* version, and what the switch answers and records names it. Left out, a
|
|
4942
|
+
* version that stopped taking bookings gives way to the one in effect.
|
|
4943
|
+
*/
|
|
4944
|
+
quotedVersionOnly?: boolean;
|
|
4945
|
+
/**
|
|
4946
|
+
* The version the caller read the subscription bound to, where its
|
|
4947
|
+
* decision rests on it: the write claims the row only while that binding
|
|
4948
|
+
* still holds. A switch to a version offered passes it — it writes back the
|
|
4949
|
+
* plan it read, and a change made in between would otherwise be undone.
|
|
4950
|
+
* `null` claims a row bound to no version. Left out, the binding is not
|
|
4951
|
+
* claimed — and a write that binds no version (`bindsPlanVersion: false`)
|
|
4952
|
+
* has none to claim.
|
|
4953
|
+
*/
|
|
4954
|
+
expectedPlanVersionId?: string | null;
|
|
4955
|
+
/**
|
|
4956
|
+
* `true`: the change the subscription has scheduled survives the write. A
|
|
4957
|
+
* retirement's move passes it — the change is the subscriber's own, and the
|
|
4958
|
+
* move is not. One that only moves the rhythm on the plan being left follows
|
|
4959
|
+
* the subscription to `planId` (`scheduledChangeAfterWrite`). The write then
|
|
4960
|
+
* claims the row only while the scheduled change is still the one it read.
|
|
4961
|
+
* Left out, the write clears it: a change the subscriber makes replaces the
|
|
4962
|
+
* one they scheduled before.
|
|
4963
|
+
*/
|
|
4964
|
+
keepsPendingChange?: boolean;
|
|
4965
|
+
/**
|
|
4966
|
+
* `true`: the write puts back a binding the subscription held a moment
|
|
4967
|
+
* before, so `quotedPlanVersionId` counts whether or not it still takes
|
|
4968
|
+
* bookings — it has to be a version of `planId`, nothing more. A
|
|
4969
|
+
* retirement's move or switch passes it to bind the subscription back to
|
|
4970
|
+
* the version retired, where the contract that has to come with the move
|
|
4971
|
+
* could not be written: that version is off sale, often by its own end, and
|
|
4972
|
+
* undoing a move is not a booking (`SC-PLAN-016` asks only of one). Left
|
|
4973
|
+
* out, a version that no longer takes bookings is not bound.
|
|
4974
|
+
*/
|
|
4975
|
+
restoresQuotedVersion?: boolean;
|
|
4075
4976
|
}
|
|
4076
4977
|
/** Input for `schedulePlanChange` (change at period end). */
|
|
4077
4978
|
interface ScheduledPlanChangeInput {
|
|
4078
4979
|
pendingPlan: string;
|
|
4079
4980
|
pendingBillingCycle: string;
|
|
4080
4981
|
pendingEffectiveAt: Date;
|
|
4982
|
+
/**
|
|
4983
|
+
* The version of `pendingPlan` the preview quoted, where the change does
|
|
4984
|
+
* not keep the version bound — a change to another plan, or one on a
|
|
4985
|
+
* subscription bound to none; stored as `pendingChangeVersionId` and bound
|
|
4986
|
+
* when the change comes due. `null` where the plan stays on a bound
|
|
4987
|
+
* version — the version bound then is kept, whatever it is by that day — or
|
|
4988
|
+
* where no repository reads versions.
|
|
4989
|
+
*/
|
|
4990
|
+
pendingChangeVersionId: string | null;
|
|
4081
4991
|
/** See `ImmediatePlanChangeInput.expectedCanceledAt`. */
|
|
4082
4992
|
expectedCanceledAt: Date | null;
|
|
4993
|
+
/** See `ImmediatePlanChangeInput.expectedPlanVersionId`. */
|
|
4994
|
+
expectedPlanVersionId?: string | null;
|
|
4995
|
+
/**
|
|
4996
|
+
* The change the caller read as scheduled, where its decision rests on it —
|
|
4997
|
+
* `null` for nothing scheduled. The write claims the row only while that
|
|
4998
|
+
* still holds. A switch to a version offered passes `null`: an offer is
|
|
4999
|
+
* made only while nothing is scheduled, and a change scheduled in between
|
|
5000
|
+
* would otherwise be written over. Left out, it is not claimed.
|
|
5001
|
+
*/
|
|
5002
|
+
expectedPendingPlan?: string | null;
|
|
4083
5003
|
}
|
|
4084
5004
|
/**
|
|
4085
5005
|
* Input for `applyOnboardingSelection`. Plan-change fields that the
|
|
@@ -4174,24 +5094,17 @@ interface TenantSubscriptionWritePort {
|
|
|
4174
5094
|
changePlanImmediate(tenantId: string, input: ImmediatePlanChangeInput): Promise<{
|
|
4175
5095
|
plan: string;
|
|
4176
5096
|
billingCycle: string;
|
|
4177
|
-
/**
|
|
5097
|
+
/**
|
|
5098
|
+
* False when what the caller claimed moved since it read it — the
|
|
5099
|
+
* cancellation, and the binding where it passed one — or when the
|
|
5100
|
+
* version it required no longer takes bookings.
|
|
5101
|
+
*/
|
|
4178
5102
|
claimed: boolean;
|
|
4179
5103
|
}>;
|
|
4180
5104
|
/** Change at period end: set pending fields. */
|
|
4181
5105
|
schedulePlanChange(tenantId: string, input: ScheduledPlanChangeInput): Promise<{
|
|
4182
5106
|
claimed: boolean;
|
|
4183
5107
|
}>;
|
|
4184
|
-
/**
|
|
4185
|
-
* Marks the pending PlanVersion as accepted. Idempotent — a duplicate
|
|
4186
|
-
* accept is a no-op. Returns `alreadyAccepted: true` if the status was
|
|
4187
|
-
* already set.
|
|
4188
|
-
*/
|
|
4189
|
-
acceptPendingPlanVersion(tenantId: string, userId: string, now: Date): Promise<{
|
|
4190
|
-
accepted: boolean;
|
|
4191
|
-
acceptedAt: Date | null;
|
|
4192
|
-
effectiveAt: Date | null;
|
|
4193
|
-
alreadyAccepted: boolean;
|
|
4194
|
-
}>;
|
|
4195
5108
|
/**
|
|
4196
5109
|
* Record a cancellation. The dates are decided above this port.
|
|
4197
5110
|
*
|
|
@@ -4233,30 +5146,22 @@ interface TenantSubscriptionWritePort {
|
|
|
4233
5146
|
/** Read adapter for PlanVersions. */
|
|
4234
5147
|
interface PlanVersionRepository {
|
|
4235
5148
|
/**
|
|
4236
|
-
*
|
|
4237
|
-
*
|
|
4238
|
-
* transaction.
|
|
4239
|
-
*
|
|
4240
|
-
* Note: ignores `validFrom`/`validUntil`. For time-aware
|
|
4241
|
-
* resolution (onboarding, plan fallback for TRIAL) use `findActive`.
|
|
4242
|
-
*
|
|
4243
|
-
* A plan key no plan has finds `null`, not an error.
|
|
4244
|
-
*/
|
|
4245
|
-
findLatestLive(planId: string, tx?: TransactionContext): Promise<PlanVersionRecord | null>;
|
|
4246
|
-
/**
|
|
4247
|
-
* PlanVersion of a plan active at `asOf`:
|
|
5149
|
+
* The version of a plan on sale at `asOf` — what a booking made then
|
|
5150
|
+
* binds — by the same rule as `PlanRepository.findActivePlanVersion`:
|
|
4248
5151
|
* `publishedAt IS NOT NULL`
|
|
4249
5152
|
* `(validFrom IS NULL OR validFrom <= asOf)`
|
|
4250
5153
|
* `(validUntil IS NULL OR validUntil >= startOfUtcDay(asOf))`
|
|
5154
|
+
* `(endsAt IS NULL OR endsAt > asOf)`
|
|
4251
5155
|
*
|
|
4252
5156
|
* `validUntil` is day-inclusive. If multiple versions match, adapters
|
|
4253
|
-
* return the highest `validFrom`,
|
|
4254
|
-
*
|
|
4255
|
-
*
|
|
5157
|
+
* return the highest `validFrom`, ordering null start dates last, then the
|
|
5158
|
+
* highest version. Adapters build the WHERE with
|
|
5159
|
+
* `buildActivePlanVersionWhere(asOf, { withEndsAt: true })`. Optionally
|
|
5160
|
+
* within a transaction.
|
|
4256
5161
|
*
|
|
4257
5162
|
* A plan key no plan has finds `null`, not an error.
|
|
4258
5163
|
*/
|
|
4259
|
-
findActive
|
|
5164
|
+
findActive(planId: string, asOf?: Date, tx?: TransactionContext): Promise<PlanVersionRecord | null>;
|
|
4260
5165
|
}
|
|
4261
5166
|
|
|
4262
5167
|
/** Aggregate snapshot of subscriptions, orchestrated by `AdminStatsService`. */
|
|
@@ -4275,6 +5180,11 @@ interface SubscriptionStatsSnapshot {
|
|
|
4275
5180
|
/**
|
|
4276
5181
|
* Stats adapter for subscriptions. Consumers implement this based on their
|
|
4277
5182
|
* Prisma `subscription.groupBy(...)` / `count(...)` calls.
|
|
5183
|
+
*
|
|
5184
|
+
* The figures span every tenant: the platform reads them, together with the
|
|
5185
|
+
* promo code and audit figures, inside `RlsBypassPort`, and an implementation
|
|
5186
|
+
* has to see every tenant's rows there — as for
|
|
5187
|
+
* `SubscriptionRepository.countByPlanVersionId`.
|
|
4278
5188
|
*/
|
|
4279
5189
|
interface SubscriptionStatsPort {
|
|
4280
5190
|
getStats(): Promise<SubscriptionStatsSnapshot>;
|
|
@@ -4321,6 +5231,19 @@ interface AdminActor {
|
|
|
4321
5231
|
source: 'web' | 'cli';
|
|
4322
5232
|
context: string;
|
|
4323
5233
|
}
|
|
5234
|
+
/**
|
|
5235
|
+
* A platform job acting on its own schedule — no person behind it, so no user:
|
|
5236
|
+
* the canonical `audit_logs.userId` is nullable for exactly this. `context`
|
|
5237
|
+
* names the job, and the actor tag reads `job:platform:<job>`.
|
|
5238
|
+
*/
|
|
5239
|
+
interface PlatformJobActor {
|
|
5240
|
+
userId: null;
|
|
5241
|
+
email: 'platform';
|
|
5242
|
+
source: 'job';
|
|
5243
|
+
context: string;
|
|
5244
|
+
}
|
|
5245
|
+
/** Whoever an audit entry names: a person, from the web or the CLI, or a platform job. */
|
|
5246
|
+
type AuditActor = AdminActor | PlatformJobActor;
|
|
4324
5247
|
/**
|
|
4325
5248
|
* Audit adapter: platform services write to the audit log through this
|
|
4326
5249
|
* interface. The consumer implementation persists the records (e.g.
|
|
@@ -4332,7 +5255,7 @@ interface AdminActor {
|
|
|
4332
5255
|
*/
|
|
4333
5256
|
interface AuditPort {
|
|
4334
5257
|
write(input: {
|
|
4335
|
-
actor:
|
|
5258
|
+
actor: AuditActor;
|
|
4336
5259
|
entity: string;
|
|
4337
5260
|
entityId: string;
|
|
4338
5261
|
action: string;
|
|
@@ -4475,6 +5398,14 @@ interface ManifestAccessPort {
|
|
|
4475
5398
|
* good at boot as it is in a request.
|
|
4476
5399
|
*/
|
|
4477
5400
|
interface RlsBypassPort {
|
|
5401
|
+
/**
|
|
5402
|
+
* Runs `fn` with the policy lifted. Where the installation keeps more than
|
|
5403
|
+
* the flag in the frame — the user, the tenant, an audit actor — the bypass
|
|
5404
|
+
* frame carries it over rather than replacing it: an operator's route runs
|
|
5405
|
+
* inside it, and what the request's own frame held is still read there.
|
|
5406
|
+
* `store.run({ ...store.getStore(), bypassRls: true }, fn)` rather than
|
|
5407
|
+
* `store.run({ bypassRls: true }, fn)`.
|
|
5408
|
+
*/
|
|
4478
5409
|
runWithBypass<T>(fn: () => Promise<T>): Promise<T>;
|
|
4479
5410
|
}
|
|
4480
5411
|
|
|
@@ -4535,37 +5466,41 @@ interface PlanRepository {
|
|
|
4535
5466
|
findVersionById?(versionId: string): Promise<PlanVersionRow | null>;
|
|
4536
5467
|
findCurrentDraft?(planKey: string): Promise<PlanVersionRow | null>;
|
|
4537
5468
|
/**
|
|
4538
|
-
*
|
|
5469
|
+
* The newest published version of a plan:
|
|
4539
5470
|
* `publishedAt IS NOT NULL AND supersededAt IS NULL`.
|
|
4540
5471
|
*
|
|
4541
|
-
*
|
|
4542
|
-
*
|
|
4543
|
-
*
|
|
4544
|
-
*
|
|
4545
|
-
* the version *active at a point in time*.
|
|
5472
|
+
* The version a publish chains to, not the version on sale: a successor
|
|
5473
|
+
* published today with a start next month is the newest at once, and its
|
|
5474
|
+
* predecessor goes on selling until then. What is on sale — for a booking,
|
|
5475
|
+
* a price, a catalogue, an offer — is `findActivePlanVersion`.
|
|
4546
5476
|
*/
|
|
4547
5477
|
findLatestLivePlanVersion?(planKey: string, tx?: TransactionContext): Promise<PlanVersionRow | null>;
|
|
4548
5478
|
/**
|
|
4549
|
-
*
|
|
5479
|
+
* The version of a plan on sale at `asOf` — the one a booking made then
|
|
5480
|
+
* binds:
|
|
4550
5481
|
* `publishedAt IS NOT NULL`
|
|
4551
5482
|
* `(validFrom IS NULL OR validFrom <= asOf)`
|
|
4552
5483
|
* `(validUntil IS NULL OR validUntil >= startOfUtcDay(asOf))` — day-inclusive
|
|
5484
|
+
* `(endsAt IS NULL OR endsAt > asOf)`
|
|
4553
5485
|
*
|
|
4554
|
-
* `validFrom IS NULL` is treated like "valid since forever" so that
|
|
4555
|
-
* without a start date
|
|
4556
|
-
*
|
|
4557
|
-
*
|
|
4558
|
-
* Adapters build the WHERE via
|
|
5486
|
+
* `validFrom IS NULL` is treated like "valid since forever" so that a
|
|
5487
|
+
* version published without a start date does not fall out of the
|
|
5488
|
+
* catalogue. `validUntil` is day-inclusive (calendar day): the version is
|
|
5489
|
+
* valid until the end of its validUntil day, not just until midnight.
|
|
5490
|
+
* Adapters build the WHERE via
|
|
5491
|
+
* `buildActivePlanVersionWhere(asOf, { withEndsAt: true })`.
|
|
4559
5492
|
*
|
|
4560
5493
|
* If multiple match: the one with the highest `validFrom` (= the
|
|
4561
|
-
* "last active"). Adapters must request
|
|
4562
|
-
* null start date remains a genuine fallback.
|
|
4563
|
-
* time.
|
|
5494
|
+
* "last active"), then the highest version. Adapters must request
|
|
5495
|
+
* `NULLS LAST` explicitly so a null start date remains a genuine fallback.
|
|
5496
|
+
* Default `asOf` is the call time.
|
|
4564
5497
|
*
|
|
4565
|
-
*
|
|
4566
|
-
*
|
|
4567
|
-
*
|
|
4568
|
-
*
|
|
5498
|
+
* Every read of what is on sale goes through this — the catalogue, the
|
|
5499
|
+
* plan-change preview, checkout, the public marketing catalogue, every
|
|
5500
|
+
* booking and the offer to existing subscriptions — so all of them name
|
|
5501
|
+
* the same version at the same moment. Existing subscriptions stay on
|
|
5502
|
+
* their bound `planVersionId`. A repository that reads versions and
|
|
5503
|
+
* leaves this out is refused at start-up.
|
|
4569
5504
|
*/
|
|
4570
5505
|
findActivePlanVersion?(planKey: string, asOf?: Date, tx?: TransactionContext): Promise<PlanVersionRow | null>;
|
|
4571
5506
|
/**
|
|
@@ -4663,27 +5598,30 @@ interface BundleRepository {
|
|
|
4663
5598
|
findVersionById(versionId: string, tx?: TransactionContext): Promise<BundleVersionRow | null>;
|
|
4664
5599
|
findCurrentDraft(bundleId: string): Promise<BundleVersionRow | null>;
|
|
4665
5600
|
/**
|
|
4666
|
-
*
|
|
5601
|
+
* The newest published BundleVersion of a bundle:
|
|
4667
5602
|
* `publishedAt IS NOT NULL AND supersededAt IS NULL`.
|
|
4668
5603
|
*
|
|
4669
|
-
*
|
|
4670
|
-
*
|
|
5604
|
+
* The version a publish chains to, not the version on sale: a successor
|
|
5605
|
+
* published today with a start next month is the newest at once, and its
|
|
5606
|
+
* predecessor goes on selling until then. What is on sale — for a booking,
|
|
5607
|
+
* a catalogue, an upsell — is `findActiveBundleVersion`.
|
|
4671
5608
|
*/
|
|
4672
5609
|
findLatestLive(bundleId: string, tx?: TransactionContext): Promise<BundleVersionRow | null>;
|
|
4673
5610
|
/**
|
|
4674
|
-
* BundleVersion
|
|
5611
|
+
* The BundleVersion on sale at `asOf` — the one a booking made then may
|
|
5612
|
+
* take:
|
|
4675
5613
|
* `publishedAt IS NOT NULL`
|
|
4676
5614
|
* `(validFrom IS NULL OR validFrom <= asOf)`
|
|
4677
5615
|
* `(validUntil IS NULL OR validUntil >= startOfUtcDay(asOf))`
|
|
5616
|
+
* `(supersededAt IS NULL OR validUntil IS NOT NULL)`
|
|
4678
5617
|
*
|
|
4679
|
-
* Both boundaries are inclusive
|
|
4680
|
-
*
|
|
4681
|
-
*
|
|
4682
|
-
*
|
|
4683
|
-
*
|
|
4684
|
-
* can omit the capability and consumers can fall back explicitly.
|
|
5618
|
+
* Both boundaries are inclusive, and a superseded version sells only
|
|
5619
|
+
* within a last day it carries — the rule of `buildActiveVersionWhere`.
|
|
5620
|
+
* If multiple versions match, adapters return the highest `validFrom`,
|
|
5621
|
+
* then the highest `version`; a null `validFrom` sorts last. Default
|
|
5622
|
+
* `asOf` is the call time.
|
|
4685
5623
|
*/
|
|
4686
|
-
findActiveBundleVersion
|
|
5624
|
+
findActiveBundleVersion(bundleId: string, asOf?: Date, tx?: TransactionContext): Promise<BundleVersionRow | null>;
|
|
4687
5625
|
/**
|
|
4688
5626
|
* Creates a new draft version (`publishedAt = null`). Throws if
|
|
4689
5627
|
* a draft already exists (partial unique index violation).
|
|
@@ -5174,6 +6112,135 @@ interface AppliedSettingsPort {
|
|
|
5174
6112
|
acknowledgeChange(id: string, acknowledgedBy: string, acknowledgedAt: Date): Promise<SettingsChangeRecord | null>;
|
|
5175
6113
|
}
|
|
5176
6114
|
|
|
6115
|
+
/**
|
|
6116
|
+
* Keeps the maintenance windows, in the application's own database.
|
|
6117
|
+
*
|
|
6118
|
+
* Every running version of the application reads this table while the lock
|
|
6119
|
+
* holds — the one being replaced as well as the one replacing it — so its shape
|
|
6120
|
+
* is part of the contract between two releases: it gains columns, and never in
|
|
6121
|
+
* a deploy the lock protects.
|
|
6122
|
+
*
|
|
6123
|
+
* An adapter translates. It does not decide whether a window may be locked or
|
|
6124
|
+
* moved; it makes each write conditional on what the caller read, so that two
|
|
6125
|
+
* operators acting at once cannot both succeed.
|
|
6126
|
+
*/
|
|
6127
|
+
interface MaintenanceWindowPort {
|
|
6128
|
+
/** The open window — announced or locked, not yet over — or null. There is at most one. */
|
|
6129
|
+
findOpen(): Promise<MaintenanceWindowRecord | null>;
|
|
6130
|
+
/** The most recently recorded windows first, open or over; at most `limit` of them. */
|
|
6131
|
+
listRecent(limit: number): Promise<MaintenanceWindowRecord[]>;
|
|
6132
|
+
/**
|
|
6133
|
+
* Records a new open window and returns it as stored — the id is the
|
|
6134
|
+
* adapter's to assign. Returns null where a window is already open: the
|
|
6135
|
+
* database holds an installation to one, so of two concurrent calls exactly
|
|
6136
|
+
* one lands.
|
|
6137
|
+
*/
|
|
6138
|
+
open(window: NewMaintenanceWindow): Promise<MaintenanceWindowRecord | null>;
|
|
6139
|
+
/**
|
|
6140
|
+
* Applies `changes` to window `id`, provided it is still open and at
|
|
6141
|
+
* `stage`. Returns the window as stored, or null where it is not: it ended,
|
|
6142
|
+
* it was locked in the meantime, or no window has that id.
|
|
6143
|
+
*/
|
|
6144
|
+
update(id: string, stage: MaintenanceWindowStage, changes: MaintenanceWindowChanges): Promise<MaintenanceWindowRecord | null>;
|
|
6145
|
+
}
|
|
6146
|
+
/**
|
|
6147
|
+
* Hears when a window is announced, moved or cancelled, so the application can
|
|
6148
|
+
* write to its users. Optional: without it tenants learn of a window from the
|
|
6149
|
+
* banner alone.
|
|
6150
|
+
*
|
|
6151
|
+
* Called after the change is recorded, and never waited on by the operator: a
|
|
6152
|
+
* notification that fails is logged, and the window stands as recorded.
|
|
6153
|
+
*/
|
|
6154
|
+
interface MaintenanceNotificationPort {
|
|
6155
|
+
windowChanged(event: MaintenanceWindowEvent): Promise<void>;
|
|
6156
|
+
}
|
|
6157
|
+
|
|
6158
|
+
/** A notice to record before anybody is told: its key and what it says. */
|
|
6159
|
+
interface NoticeToRecord extends SubscriptionNoticeKey {
|
|
6160
|
+
readonly content: unknown;
|
|
6161
|
+
}
|
|
6162
|
+
/**
|
|
6163
|
+
* Keeps the record of every notice sent to a subscriber: one per subscription,
|
|
6164
|
+
* kind and subject, with when and to whom it went.
|
|
6165
|
+
*
|
|
6166
|
+
* Delivery takes three writes so that a notice is sent once even where several
|
|
6167
|
+
* instances run the same job: a run claims the notice, the application sends
|
|
6168
|
+
* it, and the run confirms it — or releases it where the sending failed, for the
|
|
6169
|
+
* next run to try again. Each write is conditional on what the caller read; an
|
|
6170
|
+
* adapter translates and does not decide.
|
|
6171
|
+
*/
|
|
6172
|
+
interface SubscriptionNoticeRepository {
|
|
6173
|
+
/**
|
|
6174
|
+
* Records the notice named by `key` where it is not recorded yet, and
|
|
6175
|
+
* claims it for this run: where it is not delivered and no run holds it,
|
|
6176
|
+
* or the run that holds it took it on before `staleBefore`. A claim stores
|
|
6177
|
+
* `content` as what the notice says. Returns the notice as claimed, or null
|
|
6178
|
+
* where it is delivered or another run holds a fresh claim — of two
|
|
6179
|
+
* concurrent calls exactly one claims it.
|
|
6180
|
+
*/
|
|
6181
|
+
claim(key: SubscriptionNoticeKey, content: unknown, now: Date, staleBefore: Date): Promise<SubscriptionNoticeRecord | null>;
|
|
6182
|
+
/**
|
|
6183
|
+
* Records the notice `id` as delivered, provided it is still held by the
|
|
6184
|
+
* claim taken at `claimedAt` and not delivered. Returns false where it is
|
|
6185
|
+
* not: the claim went stale and another run took the notice on.
|
|
6186
|
+
*/
|
|
6187
|
+
confirm(id: string, claimedAt: Date, delivery: SubscriptionNoticeDelivery, now: Date): Promise<boolean>;
|
|
6188
|
+
/**
|
|
6189
|
+
* Lets go of the claim taken at `claimedAt`, so the next run tries again.
|
|
6190
|
+
* Does nothing where the notice is delivered or held by another claim.
|
|
6191
|
+
*/
|
|
6192
|
+
release(id: string, claimedAt: Date): Promise<void>;
|
|
6193
|
+
/** The subscriptions a notice of `kind` about `subject` has been delivered to. */
|
|
6194
|
+
listDeliveredSubscriptionIds(kind: SubscriptionNoticeKind, subject: string): Promise<string[]>;
|
|
6195
|
+
/** Every notice of one subscription, the most recently recorded first. */
|
|
6196
|
+
listForSubscription(subscriptionId: string): Promise<SubscriptionNoticeRecord[]>;
|
|
6197
|
+
/**
|
|
6198
|
+
* Records each notice where it is not recorded yet, unclaimed and not
|
|
6199
|
+
* delivered — in the caller's transaction where one is given, so a notice
|
|
6200
|
+
* exists exactly when what it tells of does. A notice already recorded
|
|
6201
|
+
* under the same key is left as it is and not counted: the answer is how
|
|
6202
|
+
* many were recorded now, so a caller can tell that another got there
|
|
6203
|
+
* first — under a transaction running beside it as well.
|
|
6204
|
+
*/
|
|
6205
|
+
record(notices: readonly NoticeToRecord[], now: Date, tx?: TransactionContext): Promise<number>;
|
|
6206
|
+
/** Every notice of `kind` recorded at or after `since`, the most recent first. */
|
|
6207
|
+
listOfKindSince(kind: SubscriptionNoticeKind, since: Date): Promise<SubscriptionNoticeRecord[]>;
|
|
6208
|
+
/**
|
|
6209
|
+
* The notices of `kind` that are not delivered and that no run holds — never
|
|
6210
|
+
* claimed, released, or claimed before `staleBefore` — the oldest first.
|
|
6211
|
+
*/
|
|
6212
|
+
listUndelivered(kind: SubscriptionNoticeKind, staleBefore: Date): Promise<SubscriptionNoticeRecord[]>;
|
|
6213
|
+
}
|
|
6214
|
+
/**
|
|
6215
|
+
* Sends a notice to the administrators of the tenant it is for, in the
|
|
6216
|
+
* application's words and through its channels. The platform decides when a
|
|
6217
|
+
* notice is due; who the administrators are, what the message says and how it
|
|
6218
|
+
* travels are the application's.
|
|
6219
|
+
*
|
|
6220
|
+
* Resolve with who it went to and how — the platform keeps that as the record.
|
|
6221
|
+
* Throw where it could not be sent and should be tried again: the claim is
|
|
6222
|
+
* released and the next run sends it. Resolving with no recipients records that
|
|
6223
|
+
* nobody could be told, and the notice is not tried again — except a
|
|
6224
|
+
* retirement's notice (`version-retired`), which nobody was told of: it is tried
|
|
6225
|
+
* again by every run until somebody is, and its date counts from then.
|
|
6226
|
+
*/
|
|
6227
|
+
interface SubscriptionNoticePort {
|
|
6228
|
+
deliver(notice: SubscriptionNotice): Promise<SubscriptionNoticeDelivery>;
|
|
6229
|
+
}
|
|
6230
|
+
|
|
6231
|
+
/**
|
|
6232
|
+
* Keeps every retirement announcement: which version, which replacement, when
|
|
6233
|
+
* and by whom. What it means for each subscription it reaches is kept beside it
|
|
6234
|
+
* as a notice of kind `version-retired`, written in the same transaction.
|
|
6235
|
+
*/
|
|
6236
|
+
interface VersionRetirementRepository {
|
|
6237
|
+
/** Records an announcement, in the caller's transaction where one is given. */
|
|
6238
|
+
create(data: NewVersionRetirement, tx?: TransactionContext): Promise<VersionRetirementRecord>;
|
|
6239
|
+
/** Every announcement, the most recent first. */
|
|
6240
|
+
list(): Promise<VersionRetirementRecord[]>;
|
|
6241
|
+
findById(id: string): Promise<VersionRetirementRecord | null>;
|
|
6242
|
+
}
|
|
6243
|
+
|
|
5177
6244
|
/** Class reference usable as a DI token (e.g. the consumer's `PrismaService`). */
|
|
5178
6245
|
type PersistenceClassRef = abstract new (...args: never[]) => unknown;
|
|
5179
6246
|
/** DI token forms a persistence bundle may reference in `inject`. */
|
|
@@ -5211,9 +6278,11 @@ interface PersistenceCapabilities {
|
|
|
5211
6278
|
*/
|
|
5212
6279
|
pessimisticLocking: boolean;
|
|
5213
6280
|
/**
|
|
5214
|
-
* The adapter stack integrates with Postgres row-level security
|
|
5215
|
-
* `RlsBypassPort` frame
|
|
5216
|
-
*
|
|
6281
|
+
* The adapter stack integrates with Postgres row-level security: the
|
|
6282
|
+
* `RlsBypassPort` frame lifts the installation's policies for what the
|
|
6283
|
+
* platform does across tenants, reads and writes alike. Informational —
|
|
6284
|
+
* nothing in the platform reads it, and the policies themselves remain
|
|
6285
|
+
* the installation's.
|
|
5217
6286
|
*/
|
|
5218
6287
|
rowLevelSecurity: boolean;
|
|
5219
6288
|
/** Advisory-lock support (`pg_advisory_*`). No platform path requires it today. */
|
|
@@ -5221,7 +6290,12 @@ interface PersistenceCapabilities {
|
|
|
5221
6290
|
}
|
|
5222
6291
|
/** Always-required slice: admin surface + transactions. */
|
|
5223
6292
|
interface SaaSiCatPersistenceCore {
|
|
5224
|
-
|
|
6293
|
+
/**
|
|
6294
|
+
* Absent where the schema leaves the SuperAdmin MFA table out
|
|
6295
|
+
* (`notAdopted: ['SuperAdminMfa']`); the application then passes its own
|
|
6296
|
+
* `MfaPort` in `adapters`, and a start without one is refused.
|
|
6297
|
+
*/
|
|
6298
|
+
mfa?: PersistenceProvider<MfaPort>;
|
|
5225
6299
|
audit: PersistenceProvider<AuditPort>;
|
|
5226
6300
|
rlsBypass: PersistenceProvider<RlsBypassPort>;
|
|
5227
6301
|
transactionRunner: PersistenceProvider<TransactionRunner>;
|
|
@@ -5237,6 +6311,13 @@ interface SaaSiCatPersistenceCore {
|
|
|
5237
6311
|
* platform says once at boot that it is not recording.
|
|
5238
6312
|
*/
|
|
5239
6313
|
appliedSettings?: PersistenceProvider<AppliedSettingsPort>;
|
|
6314
|
+
/**
|
|
6315
|
+
* Where maintenance windows are kept (`maintenance` in
|
|
6316
|
+
* `SaaSiCatModule.forRoot`). Optional so an adapter written before it
|
|
6317
|
+
* existed keeps working; an installation that turns maintenance on without
|
|
6318
|
+
* one is refused at start-up.
|
|
6319
|
+
*/
|
|
6320
|
+
maintenanceWindows?: PersistenceProvider<MaintenanceWindowPort>;
|
|
5240
6321
|
}
|
|
5241
6322
|
/** Repositories for the entitlement/contract loop (`EntitlementModule`). */
|
|
5242
6323
|
interface SaaSiCatPersistenceEntitlement {
|
|
@@ -5272,6 +6353,18 @@ interface SaaSiCatPersistenceTenantBilling {
|
|
|
5272
6353
|
subscriptionUsagePort: PersistenceProvider<SubscriptionUsagePort>;
|
|
5273
6354
|
subscriptionWritePort: PersistenceProvider<TenantSubscriptionWritePort>;
|
|
5274
6355
|
usageSnapshotPort?: PersistenceProvider<UsageSnapshotPort>;
|
|
6356
|
+
/**
|
|
6357
|
+
* The record of what each subscriber was told (`tenantBilling.versionNotices`).
|
|
6358
|
+
* Optional so an adapter written before it keeps working; an installation
|
|
6359
|
+
* that turns notices on without one is refused at start-up.
|
|
6360
|
+
*/
|
|
6361
|
+
subscriptionNotices?: PersistenceProvider<SubscriptionNoticeRepository>;
|
|
6362
|
+
/**
|
|
6363
|
+
* The record of every retirement announcement. Optional so an adapter
|
|
6364
|
+
* written before it keeps working; an installation that lets an operator
|
|
6365
|
+
* retire versions without one is refused at start-up.
|
|
6366
|
+
*/
|
|
6367
|
+
versionRetirements?: PersistenceProvider<VersionRetirementRepository>;
|
|
5275
6368
|
}
|
|
5276
6369
|
/**
|
|
5277
6370
|
* The record of payment gateway callbacks and the payment methods they confirm
|
|
@@ -5386,10 +6479,41 @@ declare const CATALOG_ERROR_CODES: {
|
|
|
5386
6479
|
readonly PLAN_TERMINATE_INVALID_DATE: "PLAN_TERMINATE_INVALID_DATE";
|
|
5387
6480
|
readonly PLAN_TERMINATE_DATE_NOT_FUTURE: "PLAN_TERMINATE_DATE_NOT_FUTURE";
|
|
5388
6481
|
readonly PLAN_TERMINATE_NOT_IMPLEMENTED: "PLAN_TERMINATE_NOT_IMPLEMENTED";
|
|
6482
|
+
/**
|
|
6483
|
+
* Subscriptions told of a retirement still move onto this version, and
|
|
6484
|
+
* nothing moves onto a version that has ended. Carries the version, its
|
|
6485
|
+
* plan key and the first day it may end: the day after the last move.
|
|
6486
|
+
*/
|
|
6487
|
+
readonly PLAN_TERMINATE_BEFORE_RETIREMENT_MOVES: "PLAN_TERMINATE_BEFORE_RETIREMENT_MOVES";
|
|
6488
|
+
/**
|
|
6489
|
+
* Subscriptions told of a retirement are past their date and still to be
|
|
6490
|
+
* moved onto this version — a move the platform could not make yet — so it
|
|
6491
|
+
* cannot end until they have moved. Carries how many, the version and its
|
|
6492
|
+
* plan key.
|
|
6493
|
+
*/
|
|
6494
|
+
readonly PLAN_TERMINATE_WHILE_MOVES_OVERDUE: "PLAN_TERMINATE_WHILE_MOVES_OVERDUE";
|
|
6495
|
+
/**
|
|
6496
|
+
* Subscriptions on a retired version have not yet been told of their move
|
|
6497
|
+
* onto this version — their notice has reached nobody, so their date is not
|
|
6498
|
+
* set — and it cannot end until they have been. Carries how many, the
|
|
6499
|
+
* version and its plan key.
|
|
6500
|
+
*/
|
|
6501
|
+
readonly PLAN_TERMINATE_WHILE_NOTICES_UNDELIVERED: "PLAN_TERMINATE_WHILE_NOTICES_UNDELIVERED";
|
|
5389
6502
|
readonly BUNDLE_VERSION_ALREADY_PUBLISHED: "BUNDLE_VERSION_ALREADY_PUBLISHED";
|
|
5390
6503
|
readonly BUNDLE_VERSION_NOT_EDITABLE: "BUNDLE_VERSION_NOT_EDITABLE";
|
|
5391
6504
|
readonly BUNDLE_VERSION_NOT_PUBLISHED: "BUNDLE_VERSION_NOT_PUBLISHED";
|
|
5392
6505
|
readonly BUNDLE_VERSION_SUPERSEDED: "BUNDLE_VERSION_SUPERSEDED";
|
|
6506
|
+
/**
|
|
6507
|
+
* The bundle version is published, and its window has not opened: it goes
|
|
6508
|
+
* on sale on `validFrom`, and until then its predecessor is the one sold.
|
|
6509
|
+
*/
|
|
6510
|
+
readonly BUNDLE_VERSION_NOT_YET_ON_SALE: "BUNDLE_VERSION_NOT_YET_ON_SALE";
|
|
6511
|
+
/**
|
|
6512
|
+
* The add-on itself has been deleted from the catalogue. Deleting it leaves
|
|
6513
|
+
* its versions' dates as they were, so the version asked for can still be
|
|
6514
|
+
* inside its window; it is not on offer all the same.
|
|
6515
|
+
*/
|
|
6516
|
+
readonly BUNDLE_DELETED: "BUNDLE_DELETED";
|
|
5393
6517
|
readonly BUNDLE_VERSION_REGRESSION: "BUNDLE_VERSION_REGRESSION";
|
|
5394
6518
|
readonly BUNDLE_VERSION_ZERO_PRICE: "BUNDLE_VERSION_ZERO_PRICE";
|
|
5395
6519
|
readonly BUNDLE_VERSION_NO_PRICE: "BUNDLE_VERSION_NO_PRICE";
|
|
@@ -5446,6 +6570,22 @@ declare const BILLING_ERROR_CODES: {
|
|
|
5446
6570
|
readonly BUNDLE_NOT_SELF_SERVICE: "BUNDLE_NOT_SELF_SERVICE";
|
|
5447
6571
|
readonly BUNDLE_CYCLE_EXCEEDS_PLAN: "BUNDLE_CYCLE_EXCEEDS_PLAN";
|
|
5448
6572
|
readonly BUNDLE_NOT_PRICED_FOR_THIS_PLAN: "BUNDLE_NOT_PRICED_FOR_THIS_PLAN";
|
|
6573
|
+
/**
|
|
6574
|
+
* The bundle cannot run on a plan the subscription is already set to move
|
|
6575
|
+
* to — by a scheduled change, or by a retirement it has been told of — and
|
|
6576
|
+
* the booking would still be running then: that plan does not book it, or
|
|
6577
|
+
* has no price for it. Carries that plan's key, the rhythm it is billed in
|
|
6578
|
+
* there, and the day the move takes effect from, which can lie in the past
|
|
6579
|
+
* while the move has not run yet.
|
|
6580
|
+
*/
|
|
6581
|
+
readonly BUNDLE_CANNOT_RUN_ON_UPCOMING_PLAN: "BUNDLE_CANNOT_RUN_ON_UPCOMING_PLAN";
|
|
6582
|
+
/**
|
|
6583
|
+
* As `BUNDLE_CANNOT_RUN_ON_UPCOMING_PLAN`, where only the rhythm stands in
|
|
6584
|
+
* the way: a yearly bundle, and the subscription billed monthly from the
|
|
6585
|
+
* day of the move — a switch of rhythm on the plan it keeps, for one, where
|
|
6586
|
+
* naming the plan would point at the one it is already on. Same values.
|
|
6587
|
+
*/
|
|
6588
|
+
readonly BUNDLE_CANNOT_RUN_ON_UPCOMING_CYCLE: "BUNDLE_CANNOT_RUN_ON_UPCOMING_CYCLE";
|
|
5449
6589
|
readonly SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED: "SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED";
|
|
5450
6590
|
readonly SUBSCRIPTION_BUNDLE_NOT_CANCELLED: "SUBSCRIPTION_BUNDLE_NOT_CANCELLED";
|
|
5451
6591
|
readonly SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE: "SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE";
|
|
@@ -5464,6 +6604,12 @@ declare const BILLING_ERROR_CODES: {
|
|
|
5464
6604
|
* in it: a plan without a yearly price is a monthly plan.
|
|
5465
6605
|
*/
|
|
5466
6606
|
readonly PLAN_NOT_SOLD_IN_CYCLE: "PLAN_NOT_SOLD_IN_CYCLE";
|
|
6607
|
+
/**
|
|
6608
|
+
* The subscription is bound to a plan version the plan repository does not
|
|
6609
|
+
* find, or finds as a version of another plan. What the subscription pays
|
|
6610
|
+
* cannot be read, so no change is quoted until the binding is repaired.
|
|
6611
|
+
*/
|
|
6612
|
+
readonly BOUND_PLAN_VERSION_UNREADABLE: "BOUND_PLAN_VERSION_UNREADABLE";
|
|
5467
6613
|
/** Plan change refused. Carries `blockers[]` with their own codes. */
|
|
5468
6614
|
readonly PLAN_CHANGE_BLOCKED: "PLAN_CHANGE_BLOCKED";
|
|
5469
6615
|
/**
|
|
@@ -5486,6 +6632,102 @@ declare const BILLING_ERROR_CODES: {
|
|
|
5486
6632
|
* Carries the recomputed dates, so the page can re-ask instead of guessing.
|
|
5487
6633
|
*/
|
|
5488
6634
|
readonly CANCELLATION_TERMS_CHANGED: "CANCELLATION_TERMS_CHANGED";
|
|
6635
|
+
/**
|
|
6636
|
+
* The version the caller asked to switch to is no longer the one offered —
|
|
6637
|
+
* another is on sale, the subscription moved, or there is no offer. Nothing
|
|
6638
|
+
* was switched. Carries the current `offer`, or `null`, so the page can show
|
|
6639
|
+
* it instead of guessing.
|
|
6640
|
+
*/
|
|
6641
|
+
readonly VERSION_OFFER_CHANGED: "VERSION_OFFER_CHANGED";
|
|
6642
|
+
/**
|
|
6643
|
+
* The version a change to another plan named is not the one on sale when
|
|
6644
|
+
* the change was submitted: its preview was shown at another moment.
|
|
6645
|
+
* Nothing was changed. Carries the current `preview`, so the page shows
|
|
6646
|
+
* what the change binds now instead of what it would have.
|
|
6647
|
+
*/
|
|
6648
|
+
readonly PLAN_CHANGE_QUOTE_CHANGED: "PLAN_CHANGE_QUOTE_CHANGED";
|
|
6649
|
+
/**
|
|
6650
|
+
* A change to another plan named no version, where its preview names one:
|
|
6651
|
+
* nothing says which price and terms the customer was shown, so nothing
|
|
6652
|
+
* is changed.
|
|
6653
|
+
*/
|
|
6654
|
+
readonly PLAN_CHANGE_VERSION_NOT_NAMED: "PLAN_CHANGE_VERSION_NOT_NAMED";
|
|
6655
|
+
/**
|
|
6656
|
+
* A version that takes something away takes effect when the term ends, and
|
|
6657
|
+
* the subscription's cancellation lands no later: the switch would never
|
|
6658
|
+
* happen, so it is refused rather than recorded. Carries both dates.
|
|
6659
|
+
*/
|
|
6660
|
+
readonly VERSION_SWITCH_AFTER_CANCELLATION: "VERSION_SWITCH_AFTER_CANCELLATION";
|
|
6661
|
+
/**
|
|
6662
|
+
* A version that takes something away takes effect when the term ends, and
|
|
6663
|
+
* it stops being sold before then — by its window or because an operator
|
|
6664
|
+
* ended it — so it could not be bound when the change comes due. Refused
|
|
6665
|
+
* rather than recorded; carries the dates.
|
|
6666
|
+
*/
|
|
6667
|
+
readonly VERSION_ENDS_BEFORE_SWITCH: "VERSION_ENDS_BEFORE_SWITCH";
|
|
6668
|
+
/**
|
|
6669
|
+
* The operator's terms are not confirmed to carry the clause a retirement
|
|
6670
|
+
* rests on (`tenantBilling.orderlyRetirement.termsConfirmed` in
|
|
6671
|
+
* `config/saas.yaml`), so none is accepted.
|
|
6672
|
+
*/
|
|
6673
|
+
readonly RETIREMENT_TERMS_NOT_CONFIRMED: "RETIREMENT_TERMS_NOT_CONFIRMED";
|
|
6674
|
+
/**
|
|
6675
|
+
* The version is still on sale: a subscription booked after the
|
|
6676
|
+
* announcement would be on it without having been told. Carries the plan
|
|
6677
|
+
* key and the version.
|
|
6678
|
+
*/
|
|
6679
|
+
readonly RETIREMENT_VERSION_ON_SALE: "RETIREMENT_VERSION_ON_SALE";
|
|
6680
|
+
/** The replacement is not on sale, so nobody can continue on it. Carries plan key and version. */
|
|
6681
|
+
readonly RETIREMENT_REPLACEMENT_NOT_ON_SALE: "RETIREMENT_REPLACEMENT_NOT_ON_SALE";
|
|
6682
|
+
/**
|
|
6683
|
+
* The replacement has no price in the rhythm some of the subscriptions it
|
|
6684
|
+
* reaches are billed in, so they cannot continue on it. Carries how many,
|
|
6685
|
+
* and the replacement's plan key and version.
|
|
6686
|
+
*/
|
|
6687
|
+
readonly RETIREMENT_REPLACEMENT_NOT_SOLD_IN_RHYTHM: "RETIREMENT_REPLACEMENT_NOT_SOLD_IN_RHYTHM";
|
|
6688
|
+
/**
|
|
6689
|
+
* Some of the subscriptions the retirement reaches hold an add-on that
|
|
6690
|
+
* cannot run on the replacement's plan, so they cannot continue on it.
|
|
6691
|
+
* Carries how many, and the replacement's plan key and version.
|
|
6692
|
+
*/
|
|
6693
|
+
readonly RETIREMENT_REPLACEMENT_CANNOT_CARRY_BUNDLES: "RETIREMENT_REPLACEMENT_CANNOT_CARRY_BUNDLES";
|
|
6694
|
+
/** The replacement named is the version being retired. */
|
|
6695
|
+
readonly RETIREMENT_REPLACEMENT_IS_RETIRED: "RETIREMENT_REPLACEMENT_IS_RETIRED";
|
|
6696
|
+
/** No running subscription is on the version: there is nobody to tell. Carries plan key and version. */
|
|
6697
|
+
readonly RETIREMENT_NOTHING_AFFECTED: "RETIREMENT_NOTHING_AFFECTED";
|
|
6698
|
+
/**
|
|
6699
|
+
* Some of the subscriptions it reaches were reached by a retirement within
|
|
6700
|
+
* the last twelve months, and a subscription is reached at most once in that
|
|
6701
|
+
* time. Carries how many and which.
|
|
6702
|
+
*/
|
|
6703
|
+
readonly RETIREMENT_WITHIN_TWELVE_MONTHS: "RETIREMENT_WITHIN_TWELVE_MONTHS";
|
|
6704
|
+
/**
|
|
6705
|
+
* The subscriptions the retirement reaches, or their dates, changed since
|
|
6706
|
+
* the preview the operator confirmed. Carries the preview as it stands.
|
|
6707
|
+
*/
|
|
6708
|
+
readonly RETIREMENT_PREVIEW_CHANGED: "RETIREMENT_PREVIEW_CHANGED";
|
|
6709
|
+
/** No retirement of the subscription's version waits for its date: there is nothing to switch to. */
|
|
6710
|
+
readonly RETIREMENT_SWITCH_NOT_PENDING: "RETIREMENT_SWITCH_NOT_PENDING";
|
|
6711
|
+
/** The switch opens once the trial has converted: a trial has no contract to hold the price on. */
|
|
6712
|
+
readonly RETIREMENT_SWITCH_IN_TRIAL: "RETIREMENT_SWITCH_IN_TRIAL";
|
|
6713
|
+
/**
|
|
6714
|
+
* An add-on running today cannot run beside the replacement's plan, which
|
|
6715
|
+
* the switch would move the subscription onto today. Carries the add-on,
|
|
6716
|
+
* the plan and the earliest day the booking can end. Its own code rather
|
|
6717
|
+
* than a plan change's: the switch has no other plan to choose and no day
|
|
6718
|
+
* to pick, so the way past it is the add-on ending.
|
|
6719
|
+
*/
|
|
6720
|
+
readonly RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW: "RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW";
|
|
6721
|
+
/**
|
|
6722
|
+
* The subscription takes no switch now: a change is scheduled, it has
|
|
6723
|
+
* ended, or its plan is held for a special contract.
|
|
6724
|
+
*/
|
|
6725
|
+
readonly RETIREMENT_SWITCH_NOT_OPEN: "RETIREMENT_SWITCH_NOT_OPEN";
|
|
6726
|
+
/**
|
|
6727
|
+
* The version named is not the replacement the retirement names. Carries
|
|
6728
|
+
* the retirement as it now stands.
|
|
6729
|
+
*/
|
|
6730
|
+
readonly RETIREMENT_SWITCH_CHANGED: "RETIREMENT_SWITCH_CHANGED";
|
|
5489
6731
|
/** The subscription has ended; its plan can no longer be changed. */
|
|
5490
6732
|
readonly SUBSCRIPTION_ENDED: "SUBSCRIPTION_ENDED";
|
|
5491
6733
|
/** An active special contract blocks self-service plan changes. */
|
|
@@ -5503,14 +6745,23 @@ declare const BILLING_ERROR_CODES: {
|
|
|
5503
6745
|
readonly CANCELLATION_LOCKS_THE_CYCLE: "CANCELLATION_LOCKS_THE_CYCLE";
|
|
5504
6746
|
/**
|
|
5505
6747
|
* A bundle the tenant already holds runs past the cycle they are moving to.
|
|
6748
|
+
* Carries the bundle, the earliest day the booking can end, and the two
|
|
6749
|
+
* rhythms.
|
|
5506
6750
|
*
|
|
5507
6751
|
* Its own code rather than `BUNDLE_CYCLE_EXCEEDS_PLAN`, which states the
|
|
5508
6752
|
* same rule about a booking that has not been made yet. The two need
|
|
5509
6753
|
* different sentences: this one can name the day the obstacle lifts and
|
|
5510
|
-
* tell the reader to
|
|
5511
|
-
*
|
|
6754
|
+
* tell the reader how to get past it, and that advice is wrong for someone
|
|
6755
|
+
* who is only about to book. One template cannot serve both.
|
|
5512
6756
|
*/
|
|
5513
6757
|
readonly BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE: "BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE";
|
|
6758
|
+
/**
|
|
6759
|
+
* A bundle the tenant already holds cannot run on the plan they are moving
|
|
6760
|
+
* to: that plan may not book it, or it has no price there in the rhythm
|
|
6761
|
+
* the booking is billed in. Carries the bundle, the plan and the earliest
|
|
6762
|
+
* day the booking can end.
|
|
6763
|
+
*/
|
|
6764
|
+
readonly BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN: "BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN";
|
|
5514
6765
|
/**
|
|
5515
6766
|
* Features of the previewed bundle are already covered by the plan or by
|
|
5516
6767
|
* another booked bundle. A warning rather than a blocker: paying twice is
|
|
@@ -5532,7 +6783,6 @@ declare const BILLING_ERROR_CODES: {
|
|
|
5532
6783
|
* tenant reads and therefore needs a shipped text for.
|
|
5533
6784
|
*/
|
|
5534
6785
|
readonly BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED: "BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED";
|
|
5535
|
-
readonly NO_PENDING_PLAN_VERSION: "NO_PENDING_PLAN_VERSION";
|
|
5536
6786
|
readonly ONBOARDING_CREATE_FAILED: "ONBOARDING_CREATE_FAILED";
|
|
5537
6787
|
readonly BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS: "BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS";
|
|
5538
6788
|
/**
|
|
@@ -5584,6 +6834,14 @@ declare const CONTRACT_ERROR_CODES: {
|
|
|
5584
6834
|
readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
|
|
5585
6835
|
readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
|
|
5586
6836
|
readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
|
|
6837
|
+
/**
|
|
6838
|
+
* A successor would run beside another contract of the tenant: the
|
|
6839
|
+
* contract in force moved while it was being written — another successor
|
|
6840
|
+
* took its place, or a cancellation capped it — and kept moving on a
|
|
6841
|
+
* second attempt, or a contract begins after the moment the successor
|
|
6842
|
+
* would take effect. Nothing was written.
|
|
6843
|
+
*/
|
|
6844
|
+
readonly SUBSCRIPTION_CONTRACT_CHANGED: "SUBSCRIPTION_CONTRACT_CHANGED";
|
|
5587
6845
|
};
|
|
5588
6846
|
type ContractErrorCode = (typeof CONTRACT_ERROR_CODES)[keyof typeof CONTRACT_ERROR_CODES];
|
|
5589
6847
|
/** The parties contracts are concluded with (`SubscriberService`), and their absence. */
|
|
@@ -5707,6 +6965,26 @@ declare const SETTINGS_ERROR_CODES: {
|
|
|
5707
6965
|
readonly SETTINGS_CHANGE_NOT_FOUND: "SETTINGS_CHANGE_NOT_FOUND";
|
|
5708
6966
|
};
|
|
5709
6967
|
type SettingsErrorCode = (typeof SETTINGS_ERROR_CODES)[keyof typeof SETTINGS_ERROR_CODES];
|
|
6968
|
+
/** Codes of maintenance windows: the lock's refusal, and the operator's routes. */
|
|
6969
|
+
declare const MAINTENANCE_ERROR_CODES: {
|
|
6970
|
+
/** The application is locked for maintenance; the body carries the window. */
|
|
6971
|
+
readonly MAINTENANCE: "MAINTENANCE";
|
|
6972
|
+
/** A window is already open: move or cancel it before announcing another. */
|
|
6973
|
+
readonly MAINTENANCE_WINDOW_ALREADY_OPEN: "MAINTENANCE_WINDOW_ALREADY_OPEN";
|
|
6974
|
+
/** No open window has this id — it ended, or it never existed. */
|
|
6975
|
+
readonly MAINTENANCE_WINDOW_NOT_OPEN: "MAINTENANCE_WINDOW_NOT_OPEN";
|
|
6976
|
+
/** The window is locked: its start is history, and unlocking is what ends it. */
|
|
6977
|
+
readonly MAINTENANCE_WINDOW_LOCKED: "MAINTENANCE_WINDOW_LOCKED";
|
|
6978
|
+
/** The announced end is not after the announced start. */
|
|
6979
|
+
readonly MAINTENANCE_WINDOW_END_NOT_AFTER_START: "MAINTENANCE_WINDOW_END_NOT_AFTER_START";
|
|
6980
|
+
/** The announced end has already passed. */
|
|
6981
|
+
readonly MAINTENANCE_WINDOW_END_IN_PAST: "MAINTENANCE_WINDOW_END_IN_PAST";
|
|
6982
|
+
/** A time without its zone, or not a date and time at all; `field` names which. */
|
|
6983
|
+
readonly MAINTENANCE_TIME_INVALID: "MAINTENANCE_TIME_INVALID";
|
|
6984
|
+
/** The message is longer than `MAINTENANCE_MESSAGE_MAX_LENGTH`. */
|
|
6985
|
+
readonly MAINTENANCE_MESSAGE_TOO_LONG: "MAINTENANCE_MESSAGE_TOO_LONG";
|
|
6986
|
+
};
|
|
6987
|
+
type MaintenanceErrorCode = (typeof MAINTENANCE_ERROR_CODES)[keyof typeof MAINTENANCE_ERROR_CODES];
|
|
5710
6988
|
/**
|
|
5711
6989
|
* Every exception code the platform emits, in one object.
|
|
5712
6990
|
*
|
|
@@ -5715,6 +6993,22 @@ type SettingsErrorCode = (typeof SETTINGS_ERROR_CODES)[keyof typeof SETTINGS_ERR
|
|
|
5715
6993
|
* removing one may not.
|
|
5716
6994
|
*/
|
|
5717
6995
|
declare const PLATFORM_ERROR_CODES: {
|
|
6996
|
+
/** The application is locked for maintenance; the body carries the window. */
|
|
6997
|
+
readonly MAINTENANCE: "MAINTENANCE";
|
|
6998
|
+
/** A window is already open: move or cancel it before announcing another. */
|
|
6999
|
+
readonly MAINTENANCE_WINDOW_ALREADY_OPEN: "MAINTENANCE_WINDOW_ALREADY_OPEN";
|
|
7000
|
+
/** No open window has this id — it ended, or it never existed. */
|
|
7001
|
+
readonly MAINTENANCE_WINDOW_NOT_OPEN: "MAINTENANCE_WINDOW_NOT_OPEN";
|
|
7002
|
+
/** The window is locked: its start is history, and unlocking is what ends it. */
|
|
7003
|
+
readonly MAINTENANCE_WINDOW_LOCKED: "MAINTENANCE_WINDOW_LOCKED";
|
|
7004
|
+
/** The announced end is not after the announced start. */
|
|
7005
|
+
readonly MAINTENANCE_WINDOW_END_NOT_AFTER_START: "MAINTENANCE_WINDOW_END_NOT_AFTER_START";
|
|
7006
|
+
/** The announced end has already passed. */
|
|
7007
|
+
readonly MAINTENANCE_WINDOW_END_IN_PAST: "MAINTENANCE_WINDOW_END_IN_PAST";
|
|
7008
|
+
/** A time without its zone, or not a date and time at all; `field` names which. */
|
|
7009
|
+
readonly MAINTENANCE_TIME_INVALID: "MAINTENANCE_TIME_INVALID";
|
|
7010
|
+
/** The message is longer than `MAINTENANCE_MESSAGE_MAX_LENGTH`. */
|
|
7011
|
+
readonly MAINTENANCE_MESSAGE_TOO_LONG: "MAINTENANCE_MESSAGE_TOO_LONG";
|
|
5718
7012
|
/** No recorded change has this id, or the installation keeps no record at all. */
|
|
5719
7013
|
readonly SETTINGS_CHANGE_NOT_FOUND: "SETTINGS_CHANGE_NOT_FOUND";
|
|
5720
7014
|
/**
|
|
@@ -5812,6 +7106,14 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
5812
7106
|
readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
|
|
5813
7107
|
readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
|
|
5814
7108
|
readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
|
|
7109
|
+
/**
|
|
7110
|
+
* A successor would run beside another contract of the tenant: the
|
|
7111
|
+
* contract in force moved while it was being written — another successor
|
|
7112
|
+
* took its place, or a cancellation capped it — and kept moving on a
|
|
7113
|
+
* second attempt, or a contract begins after the moment the successor
|
|
7114
|
+
* would take effect. Nothing was written.
|
|
7115
|
+
*/
|
|
7116
|
+
readonly SUBSCRIPTION_CONTRACT_CHANGED: "SUBSCRIPTION_CONTRACT_CHANGED";
|
|
5815
7117
|
/**
|
|
5816
7118
|
* Feature not covered by the plan. Defined in `upsell.types.ts` because the
|
|
5817
7119
|
* upsell body type is built around it; re-exported here so an exhaustive
|
|
@@ -5823,6 +7125,22 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
5823
7125
|
readonly BUNDLE_NOT_SELF_SERVICE: "BUNDLE_NOT_SELF_SERVICE";
|
|
5824
7126
|
readonly BUNDLE_CYCLE_EXCEEDS_PLAN: "BUNDLE_CYCLE_EXCEEDS_PLAN";
|
|
5825
7127
|
readonly BUNDLE_NOT_PRICED_FOR_THIS_PLAN: "BUNDLE_NOT_PRICED_FOR_THIS_PLAN";
|
|
7128
|
+
/**
|
|
7129
|
+
* The bundle cannot run on a plan the subscription is already set to move
|
|
7130
|
+
* to — by a scheduled change, or by a retirement it has been told of — and
|
|
7131
|
+
* the booking would still be running then: that plan does not book it, or
|
|
7132
|
+
* has no price for it. Carries that plan's key, the rhythm it is billed in
|
|
7133
|
+
* there, and the day the move takes effect from, which can lie in the past
|
|
7134
|
+
* while the move has not run yet.
|
|
7135
|
+
*/
|
|
7136
|
+
readonly BUNDLE_CANNOT_RUN_ON_UPCOMING_PLAN: "BUNDLE_CANNOT_RUN_ON_UPCOMING_PLAN";
|
|
7137
|
+
/**
|
|
7138
|
+
* As `BUNDLE_CANNOT_RUN_ON_UPCOMING_PLAN`, where only the rhythm stands in
|
|
7139
|
+
* the way: a yearly bundle, and the subscription billed monthly from the
|
|
7140
|
+
* day of the move — a switch of rhythm on the plan it keeps, for one, where
|
|
7141
|
+
* naming the plan would point at the one it is already on. Same values.
|
|
7142
|
+
*/
|
|
7143
|
+
readonly BUNDLE_CANNOT_RUN_ON_UPCOMING_CYCLE: "BUNDLE_CANNOT_RUN_ON_UPCOMING_CYCLE";
|
|
5826
7144
|
readonly SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED: "SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED";
|
|
5827
7145
|
readonly SUBSCRIPTION_BUNDLE_NOT_CANCELLED: "SUBSCRIPTION_BUNDLE_NOT_CANCELLED";
|
|
5828
7146
|
readonly SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE: "SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE";
|
|
@@ -5841,6 +7159,12 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
5841
7159
|
* in it: a plan without a yearly price is a monthly plan.
|
|
5842
7160
|
*/
|
|
5843
7161
|
readonly PLAN_NOT_SOLD_IN_CYCLE: "PLAN_NOT_SOLD_IN_CYCLE";
|
|
7162
|
+
/**
|
|
7163
|
+
* The subscription is bound to a plan version the plan repository does not
|
|
7164
|
+
* find, or finds as a version of another plan. What the subscription pays
|
|
7165
|
+
* cannot be read, so no change is quoted until the binding is repaired.
|
|
7166
|
+
*/
|
|
7167
|
+
readonly BOUND_PLAN_VERSION_UNREADABLE: "BOUND_PLAN_VERSION_UNREADABLE";
|
|
5844
7168
|
/** Plan change refused. Carries `blockers[]` with their own codes. */
|
|
5845
7169
|
readonly PLAN_CHANGE_BLOCKED: "PLAN_CHANGE_BLOCKED";
|
|
5846
7170
|
/**
|
|
@@ -5863,6 +7187,102 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
5863
7187
|
* Carries the recomputed dates, so the page can re-ask instead of guessing.
|
|
5864
7188
|
*/
|
|
5865
7189
|
readonly CANCELLATION_TERMS_CHANGED: "CANCELLATION_TERMS_CHANGED";
|
|
7190
|
+
/**
|
|
7191
|
+
* The version the caller asked to switch to is no longer the one offered —
|
|
7192
|
+
* another is on sale, the subscription moved, or there is no offer. Nothing
|
|
7193
|
+
* was switched. Carries the current `offer`, or `null`, so the page can show
|
|
7194
|
+
* it instead of guessing.
|
|
7195
|
+
*/
|
|
7196
|
+
readonly VERSION_OFFER_CHANGED: "VERSION_OFFER_CHANGED";
|
|
7197
|
+
/**
|
|
7198
|
+
* The version a change to another plan named is not the one on sale when
|
|
7199
|
+
* the change was submitted: its preview was shown at another moment.
|
|
7200
|
+
* Nothing was changed. Carries the current `preview`, so the page shows
|
|
7201
|
+
* what the change binds now instead of what it would have.
|
|
7202
|
+
*/
|
|
7203
|
+
readonly PLAN_CHANGE_QUOTE_CHANGED: "PLAN_CHANGE_QUOTE_CHANGED";
|
|
7204
|
+
/**
|
|
7205
|
+
* A change to another plan named no version, where its preview names one:
|
|
7206
|
+
* nothing says which price and terms the customer was shown, so nothing
|
|
7207
|
+
* is changed.
|
|
7208
|
+
*/
|
|
7209
|
+
readonly PLAN_CHANGE_VERSION_NOT_NAMED: "PLAN_CHANGE_VERSION_NOT_NAMED";
|
|
7210
|
+
/**
|
|
7211
|
+
* A version that takes something away takes effect when the term ends, and
|
|
7212
|
+
* the subscription's cancellation lands no later: the switch would never
|
|
7213
|
+
* happen, so it is refused rather than recorded. Carries both dates.
|
|
7214
|
+
*/
|
|
7215
|
+
readonly VERSION_SWITCH_AFTER_CANCELLATION: "VERSION_SWITCH_AFTER_CANCELLATION";
|
|
7216
|
+
/**
|
|
7217
|
+
* A version that takes something away takes effect when the term ends, and
|
|
7218
|
+
* it stops being sold before then — by its window or because an operator
|
|
7219
|
+
* ended it — so it could not be bound when the change comes due. Refused
|
|
7220
|
+
* rather than recorded; carries the dates.
|
|
7221
|
+
*/
|
|
7222
|
+
readonly VERSION_ENDS_BEFORE_SWITCH: "VERSION_ENDS_BEFORE_SWITCH";
|
|
7223
|
+
/**
|
|
7224
|
+
* The operator's terms are not confirmed to carry the clause a retirement
|
|
7225
|
+
* rests on (`tenantBilling.orderlyRetirement.termsConfirmed` in
|
|
7226
|
+
* `config/saas.yaml`), so none is accepted.
|
|
7227
|
+
*/
|
|
7228
|
+
readonly RETIREMENT_TERMS_NOT_CONFIRMED: "RETIREMENT_TERMS_NOT_CONFIRMED";
|
|
7229
|
+
/**
|
|
7230
|
+
* The version is still on sale: a subscription booked after the
|
|
7231
|
+
* announcement would be on it without having been told. Carries the plan
|
|
7232
|
+
* key and the version.
|
|
7233
|
+
*/
|
|
7234
|
+
readonly RETIREMENT_VERSION_ON_SALE: "RETIREMENT_VERSION_ON_SALE";
|
|
7235
|
+
/** The replacement is not on sale, so nobody can continue on it. Carries plan key and version. */
|
|
7236
|
+
readonly RETIREMENT_REPLACEMENT_NOT_ON_SALE: "RETIREMENT_REPLACEMENT_NOT_ON_SALE";
|
|
7237
|
+
/**
|
|
7238
|
+
* The replacement has no price in the rhythm some of the subscriptions it
|
|
7239
|
+
* reaches are billed in, so they cannot continue on it. Carries how many,
|
|
7240
|
+
* and the replacement's plan key and version.
|
|
7241
|
+
*/
|
|
7242
|
+
readonly RETIREMENT_REPLACEMENT_NOT_SOLD_IN_RHYTHM: "RETIREMENT_REPLACEMENT_NOT_SOLD_IN_RHYTHM";
|
|
7243
|
+
/**
|
|
7244
|
+
* Some of the subscriptions the retirement reaches hold an add-on that
|
|
7245
|
+
* cannot run on the replacement's plan, so they cannot continue on it.
|
|
7246
|
+
* Carries how many, and the replacement's plan key and version.
|
|
7247
|
+
*/
|
|
7248
|
+
readonly RETIREMENT_REPLACEMENT_CANNOT_CARRY_BUNDLES: "RETIREMENT_REPLACEMENT_CANNOT_CARRY_BUNDLES";
|
|
7249
|
+
/** The replacement named is the version being retired. */
|
|
7250
|
+
readonly RETIREMENT_REPLACEMENT_IS_RETIRED: "RETIREMENT_REPLACEMENT_IS_RETIRED";
|
|
7251
|
+
/** No running subscription is on the version: there is nobody to tell. Carries plan key and version. */
|
|
7252
|
+
readonly RETIREMENT_NOTHING_AFFECTED: "RETIREMENT_NOTHING_AFFECTED";
|
|
7253
|
+
/**
|
|
7254
|
+
* Some of the subscriptions it reaches were reached by a retirement within
|
|
7255
|
+
* the last twelve months, and a subscription is reached at most once in that
|
|
7256
|
+
* time. Carries how many and which.
|
|
7257
|
+
*/
|
|
7258
|
+
readonly RETIREMENT_WITHIN_TWELVE_MONTHS: "RETIREMENT_WITHIN_TWELVE_MONTHS";
|
|
7259
|
+
/**
|
|
7260
|
+
* The subscriptions the retirement reaches, or their dates, changed since
|
|
7261
|
+
* the preview the operator confirmed. Carries the preview as it stands.
|
|
7262
|
+
*/
|
|
7263
|
+
readonly RETIREMENT_PREVIEW_CHANGED: "RETIREMENT_PREVIEW_CHANGED";
|
|
7264
|
+
/** No retirement of the subscription's version waits for its date: there is nothing to switch to. */
|
|
7265
|
+
readonly RETIREMENT_SWITCH_NOT_PENDING: "RETIREMENT_SWITCH_NOT_PENDING";
|
|
7266
|
+
/** The switch opens once the trial has converted: a trial has no contract to hold the price on. */
|
|
7267
|
+
readonly RETIREMENT_SWITCH_IN_TRIAL: "RETIREMENT_SWITCH_IN_TRIAL";
|
|
7268
|
+
/**
|
|
7269
|
+
* An add-on running today cannot run beside the replacement's plan, which
|
|
7270
|
+
* the switch would move the subscription onto today. Carries the add-on,
|
|
7271
|
+
* the plan and the earliest day the booking can end. Its own code rather
|
|
7272
|
+
* than a plan change's: the switch has no other plan to choose and no day
|
|
7273
|
+
* to pick, so the way past it is the add-on ending.
|
|
7274
|
+
*/
|
|
7275
|
+
readonly RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW: "RETIREMENT_SWITCH_BUNDLE_CANNOT_FOLLOW";
|
|
7276
|
+
/**
|
|
7277
|
+
* The subscription takes no switch now: a change is scheduled, it has
|
|
7278
|
+
* ended, or its plan is held for a special contract.
|
|
7279
|
+
*/
|
|
7280
|
+
readonly RETIREMENT_SWITCH_NOT_OPEN: "RETIREMENT_SWITCH_NOT_OPEN";
|
|
7281
|
+
/**
|
|
7282
|
+
* The version named is not the replacement the retirement names. Carries
|
|
7283
|
+
* the retirement as it now stands.
|
|
7284
|
+
*/
|
|
7285
|
+
readonly RETIREMENT_SWITCH_CHANGED: "RETIREMENT_SWITCH_CHANGED";
|
|
5866
7286
|
/** The subscription has ended; its plan can no longer be changed. */
|
|
5867
7287
|
readonly SUBSCRIPTION_ENDED: "SUBSCRIPTION_ENDED";
|
|
5868
7288
|
/** An active special contract blocks self-service plan changes. */
|
|
@@ -5880,14 +7300,23 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
5880
7300
|
readonly CANCELLATION_LOCKS_THE_CYCLE: "CANCELLATION_LOCKS_THE_CYCLE";
|
|
5881
7301
|
/**
|
|
5882
7302
|
* A bundle the tenant already holds runs past the cycle they are moving to.
|
|
7303
|
+
* Carries the bundle, the earliest day the booking can end, and the two
|
|
7304
|
+
* rhythms.
|
|
5883
7305
|
*
|
|
5884
7306
|
* Its own code rather than `BUNDLE_CYCLE_EXCEEDS_PLAN`, which states the
|
|
5885
7307
|
* same rule about a booking that has not been made yet. The two need
|
|
5886
7308
|
* different sentences: this one can name the day the obstacle lifts and
|
|
5887
|
-
* tell the reader to
|
|
5888
|
-
*
|
|
7309
|
+
* tell the reader how to get past it, and that advice is wrong for someone
|
|
7310
|
+
* who is only about to book. One template cannot serve both.
|
|
5889
7311
|
*/
|
|
5890
7312
|
readonly BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE: "BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE";
|
|
7313
|
+
/**
|
|
7314
|
+
* A bundle the tenant already holds cannot run on the plan they are moving
|
|
7315
|
+
* to: that plan may not book it, or it has no price there in the rhythm
|
|
7316
|
+
* the booking is billed in. Carries the bundle, the plan and the earliest
|
|
7317
|
+
* day the booking can end.
|
|
7318
|
+
*/
|
|
7319
|
+
readonly BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN: "BUNDLE_BOOKING_DOES_NOT_FIT_TARGET_PLAN";
|
|
5891
7320
|
/**
|
|
5892
7321
|
* Features of the previewed bundle are already covered by the plan or by
|
|
5893
7322
|
* another booked bundle. A warning rather than a blocker: paying twice is
|
|
@@ -5909,7 +7338,6 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
5909
7338
|
* tenant reads and therefore needs a shipped text for.
|
|
5910
7339
|
*/
|
|
5911
7340
|
readonly BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED: "BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED";
|
|
5912
|
-
readonly NO_PENDING_PLAN_VERSION: "NO_PENDING_PLAN_VERSION";
|
|
5913
7341
|
readonly ONBOARDING_CREATE_FAILED: "ONBOARDING_CREATE_FAILED";
|
|
5914
7342
|
readonly BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS: "BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS";
|
|
5915
7343
|
/**
|
|
@@ -5941,10 +7369,41 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
5941
7369
|
readonly PLAN_TERMINATE_INVALID_DATE: "PLAN_TERMINATE_INVALID_DATE";
|
|
5942
7370
|
readonly PLAN_TERMINATE_DATE_NOT_FUTURE: "PLAN_TERMINATE_DATE_NOT_FUTURE";
|
|
5943
7371
|
readonly PLAN_TERMINATE_NOT_IMPLEMENTED: "PLAN_TERMINATE_NOT_IMPLEMENTED";
|
|
7372
|
+
/**
|
|
7373
|
+
* Subscriptions told of a retirement still move onto this version, and
|
|
7374
|
+
* nothing moves onto a version that has ended. Carries the version, its
|
|
7375
|
+
* plan key and the first day it may end: the day after the last move.
|
|
7376
|
+
*/
|
|
7377
|
+
readonly PLAN_TERMINATE_BEFORE_RETIREMENT_MOVES: "PLAN_TERMINATE_BEFORE_RETIREMENT_MOVES";
|
|
7378
|
+
/**
|
|
7379
|
+
* Subscriptions told of a retirement are past their date and still to be
|
|
7380
|
+
* moved onto this version — a move the platform could not make yet — so it
|
|
7381
|
+
* cannot end until they have moved. Carries how many, the version and its
|
|
7382
|
+
* plan key.
|
|
7383
|
+
*/
|
|
7384
|
+
readonly PLAN_TERMINATE_WHILE_MOVES_OVERDUE: "PLAN_TERMINATE_WHILE_MOVES_OVERDUE";
|
|
7385
|
+
/**
|
|
7386
|
+
* Subscriptions on a retired version have not yet been told of their move
|
|
7387
|
+
* onto this version — their notice has reached nobody, so their date is not
|
|
7388
|
+
* set — and it cannot end until they have been. Carries how many, the
|
|
7389
|
+
* version and its plan key.
|
|
7390
|
+
*/
|
|
7391
|
+
readonly PLAN_TERMINATE_WHILE_NOTICES_UNDELIVERED: "PLAN_TERMINATE_WHILE_NOTICES_UNDELIVERED";
|
|
5944
7392
|
readonly BUNDLE_VERSION_ALREADY_PUBLISHED: "BUNDLE_VERSION_ALREADY_PUBLISHED";
|
|
5945
7393
|
readonly BUNDLE_VERSION_NOT_EDITABLE: "BUNDLE_VERSION_NOT_EDITABLE";
|
|
5946
7394
|
readonly BUNDLE_VERSION_NOT_PUBLISHED: "BUNDLE_VERSION_NOT_PUBLISHED";
|
|
5947
7395
|
readonly BUNDLE_VERSION_SUPERSEDED: "BUNDLE_VERSION_SUPERSEDED";
|
|
7396
|
+
/**
|
|
7397
|
+
* The bundle version is published, and its window has not opened: it goes
|
|
7398
|
+
* on sale on `validFrom`, and until then its predecessor is the one sold.
|
|
7399
|
+
*/
|
|
7400
|
+
readonly BUNDLE_VERSION_NOT_YET_ON_SALE: "BUNDLE_VERSION_NOT_YET_ON_SALE";
|
|
7401
|
+
/**
|
|
7402
|
+
* The add-on itself has been deleted from the catalogue. Deleting it leaves
|
|
7403
|
+
* its versions' dates as they were, so the version asked for can still be
|
|
7404
|
+
* inside its window; it is not on offer all the same.
|
|
7405
|
+
*/
|
|
7406
|
+
readonly BUNDLE_DELETED: "BUNDLE_DELETED";
|
|
5948
7407
|
readonly BUNDLE_VERSION_REGRESSION: "BUNDLE_VERSION_REGRESSION";
|
|
5949
7408
|
readonly BUNDLE_VERSION_ZERO_PRICE: "BUNDLE_VERSION_ZERO_PRICE";
|
|
5950
7409
|
readonly BUNDLE_VERSION_NO_PRICE: "BUNDLE_VERSION_NO_PRICE";
|
|
@@ -6034,7 +7493,7 @@ declare const PLATFORM_ERROR_CODES: {
|
|
|
6034
7493
|
/** Email already taken (mapped from `PlatformUserExistsError`). */
|
|
6035
7494
|
readonly EMAIL_EXISTS: "EMAIL_EXISTS";
|
|
6036
7495
|
};
|
|
6037
|
-
type PlatformErrorCode = SetupErrorCode | AuthErrorCode | PromoErrorCode | CatalogErrorCode | BillingErrorCode | ContractErrorCode | SubscriberErrorCode | RegistrationErrorCode | PaymentErrorCode | SettingsErrorCode;
|
|
7496
|
+
type PlatformErrorCode = SetupErrorCode | AuthErrorCode | PromoErrorCode | CatalogErrorCode | BillingErrorCode | ContractErrorCode | SubscriberErrorCode | RegistrationErrorCode | PaymentErrorCode | SettingsErrorCode | MaintenanceErrorCode;
|
|
6038
7497
|
/**
|
|
6039
7498
|
* Shape of a coded error response.
|
|
6040
7499
|
*
|
|
@@ -6072,6 +7531,160 @@ declare class PlatformUserExistsError extends Error {
|
|
|
6072
7531
|
* when thrower and catcher see the class from different module instances.
|
|
6073
7532
|
*/
|
|
6074
7533
|
declare function isPlatformUserExistsError(err: unknown): err is PlatformUserExistsError;
|
|
7534
|
+
/**
|
|
7535
|
+
* What a refused write found instead of the state its caller had read:
|
|
7536
|
+
* `gone` — the row no longer exists; `moved` — it exists, but no longer in the
|
|
7537
|
+
* state the write required, because a concurrent request changed it first.
|
|
7538
|
+
*/
|
|
7539
|
+
type PersistenceRefusalReason = 'gone' | 'moved';
|
|
7540
|
+
/**
|
|
7541
|
+
* A write an adapter refused because the row was no longer what the caller
|
|
7542
|
+
* read, carrying the platform's error code for that case.
|
|
7543
|
+
*
|
|
7544
|
+
* The platform checks these conditions before it writes and answers with the
|
|
7545
|
+
* same code. The adapter's own guard is what holds when two requests pass
|
|
7546
|
+
* that check together — a double click, two operators — and throwing this
|
|
7547
|
+
* rather than a plain `Error` gives the loser of that race the answer the
|
|
7548
|
+
* check would have given, instead of a 500 that reads like a crash in the log.
|
|
7549
|
+
* The adapter says what it found; the platform decides what that is on the
|
|
7550
|
+
* wire.
|
|
7551
|
+
*/
|
|
7552
|
+
declare class PersistenceRefusal extends Error {
|
|
7553
|
+
readonly code: string;
|
|
7554
|
+
readonly reason: PersistenceRefusalReason;
|
|
7555
|
+
readonly params: Readonly<Record<string, unknown>>;
|
|
7556
|
+
constructor(code: string, reason: PersistenceRefusalReason, message: string, params?: Readonly<Record<string, unknown>>);
|
|
7557
|
+
}
|
|
7558
|
+
/** Realm-safe type guard, like `isPlatformUserExistsError`. */
|
|
7559
|
+
declare function isPersistenceRefusal(err: unknown): err is PersistenceRefusal;
|
|
7560
|
+
|
|
7561
|
+
/**
|
|
7562
|
+
* The canonical models a schema may leave out, each with the persistence
|
|
7563
|
+
* bundle members that need it.
|
|
7564
|
+
*
|
|
7565
|
+
* `saasicat schema check` lists every canonical model it does not find as not
|
|
7566
|
+
* adopted. Naming one of these in a bundle's `notAdopted` leaves its members
|
|
7567
|
+
* out of the bundle, so the platform decides at start what it can do without
|
|
7568
|
+
* them — and says so where it cannot — instead of the first request failing
|
|
7569
|
+
* against a table that is not there. Any other model the bundle needs: an
|
|
7570
|
+
* application that leaves it out brings its own adapter for it.
|
|
7571
|
+
*/
|
|
7572
|
+
declare const OPTIONAL_CANONICAL_MODELS: {
|
|
7573
|
+
readonly SuperAdminUser: readonly ["core.superAdminProvisioning"];
|
|
7574
|
+
readonly SuperAdminMfa: readonly ["core.mfa"];
|
|
7575
|
+
readonly AppliedSettings: readonly ["core.appliedSettings"];
|
|
7576
|
+
readonly SettingsChange: readonly ["core.appliedSettings"];
|
|
7577
|
+
readonly MaintenanceWindow: readonly ["core.maintenanceWindows"];
|
|
7578
|
+
readonly SubscriptionNotice: readonly ["tenantBilling.subscriptionNotices"];
|
|
7579
|
+
readonly VersionRetirement: readonly ["tenantBilling.versionRetirements"];
|
|
7580
|
+
readonly SubscriberLedgerEntry: readonly ["entitlement.subscriberLedgerRepository"];
|
|
7581
|
+
readonly PromoCodeHold: readonly ["promo.holdRepository"];
|
|
7582
|
+
};
|
|
7583
|
+
type OptionalCanonicalModel = keyof typeof OPTIONAL_CANONICAL_MODELS;
|
|
7584
|
+
/** A bundle member one of the optional models is needed by. */
|
|
7585
|
+
type OptionalBundleMember = (typeof OPTIONAL_CANONICAL_MODELS)[OptionalCanonicalModel][number];
|
|
7586
|
+
/**
|
|
7587
|
+
* The bundle members a `notAdopted` list leaves out.
|
|
7588
|
+
*
|
|
7589
|
+
* A name that is not one of the optional models is refused rather than
|
|
7590
|
+
* ignored: a typo would otherwise leave a member in that fails at its first
|
|
7591
|
+
* request, and a model the bundle cannot run without needs the application's
|
|
7592
|
+
* own adapter, which only the application can supply.
|
|
7593
|
+
*/
|
|
7594
|
+
declare function membersLeftOut(notAdopted?: readonly string[]): ReadonlySet<OptionalBundleMember>;
|
|
7595
|
+
|
|
7596
|
+
/** Admits a piece of work when a place is free; see `concurrencyGate`. */
|
|
7597
|
+
type ConcurrencyGate = <T>(work: () => Promise<T>) => Promise<T>;
|
|
7598
|
+
/**
|
|
7599
|
+
* Admits at most `limit` pieces of work at once and queues the rest in the
|
|
7600
|
+
* order they arrived.
|
|
7601
|
+
*
|
|
7602
|
+
* Meant for transactions. Each holds a pooled connection for its whole life,
|
|
7603
|
+
* and the platform's transactions take row locks and then read further. Run
|
|
7604
|
+
* as many at once as there are requests, and every connection can end up held
|
|
7605
|
+
* by a transaction waiting for a lock — or for a connection a sibling needs —
|
|
7606
|
+
* while the statements that would let them finish wait for the pool: the
|
|
7607
|
+
* service stalls until transactions time out. A limit below the pool size
|
|
7608
|
+
* keeps connections free for the work outside a transaction.
|
|
7609
|
+
*
|
|
7610
|
+
* A place is handed to the next in line when work ends, however it ends, so
|
|
7611
|
+
* the count never rises above the limit and nobody waiting is overtaken.
|
|
7612
|
+
*/
|
|
7613
|
+
declare function concurrencyGate(limit: number): ConcurrencyGate;
|
|
7614
|
+
/**
|
|
7615
|
+
* The one gate of a pool: every caller naming the same `pool` — the client or
|
|
7616
|
+
* database handle the transactions run on — gets the same queue.
|
|
7617
|
+
*
|
|
7618
|
+
* A bound is a property of the pool, not of whoever builds a runner. Where
|
|
7619
|
+
* the client is an injection token, Nest builds a runner once for every module
|
|
7620
|
+
* that asks for one, all on the same client; a gate per runner would admit the
|
|
7621
|
+
* limit once per module, and a gate per configuration object would join two
|
|
7622
|
+
* pools that happen to share one. A second, different limit for a pool already
|
|
7623
|
+
* bounded is refused rather than split.
|
|
7624
|
+
*/
|
|
7625
|
+
declare function concurrencyGateOf(pool: object, limit: number): ConcurrencyGate;
|
|
7626
|
+
|
|
7627
|
+
/** The two versioned catalogue entities, by the name their rows go by. */
|
|
7628
|
+
type CatalogVersionKind = 'PlanVersion' | 'BundleVersion';
|
|
7629
|
+
/** A publish of a version that is not there, refused with the platform's code. */
|
|
7630
|
+
declare function catalogVersionGone(kind: CatalogVersionKind, versionId: string): PersistenceRefusal;
|
|
7631
|
+
/**
|
|
7632
|
+
* A publish or discard of a version somebody published first. A published
|
|
7633
|
+
* version is what tenants may have booked, so it is neither published a second
|
|
7634
|
+
* time — which would rewrite when and by whom — nor discarded.
|
|
7635
|
+
*/
|
|
7636
|
+
declare function catalogVersionAlreadyPublished(kind: CatalogVersionKind, versionId: string): PersistenceRefusal;
|
|
7637
|
+
/**
|
|
7638
|
+
* A draft asked for where the plan or bundle already has one: there is one
|
|
7639
|
+
* draft at a time, so that publishing it is never a choice between two.
|
|
7640
|
+
*/
|
|
7641
|
+
declare function catalogDraftExists(kind: CatalogVersionKind, key: string, draftVersion: number): PersistenceRefusal;
|
|
7642
|
+
|
|
7643
|
+
/** A plan key a plan already carries. */
|
|
7644
|
+
declare function planKeyTaken(planKey: string): PersistenceRefusal;
|
|
7645
|
+
/** A bundle key a bundle already carries. */
|
|
7646
|
+
declare function bundleKeyTaken(bundleKey: string): PersistenceRefusal;
|
|
7647
|
+
/** A marketing projection for a version and locale that already has one. */
|
|
7648
|
+
declare function marketingProjectionTaken(target: {
|
|
7649
|
+
targetType: string;
|
|
7650
|
+
targetVersionId: string;
|
|
7651
|
+
locale: string;
|
|
7652
|
+
}): PersistenceRefusal;
|
|
7653
|
+
|
|
7654
|
+
/**
|
|
7655
|
+
* The decimal a number was written as, for a `numeric` column.
|
|
7656
|
+
*
|
|
7657
|
+
* `toFixed` rounds the binary double rather than the decimal somebody typed:
|
|
7658
|
+
* `(1.005).toFixed(2)` is `'1.00'` and `(2.675).toFixed(2)` is `'2.67'`, while
|
|
7659
|
+
* `(10.005).toFixed(2)` is `'10.01'` — which way a value goes depends on its
|
|
7660
|
+
* binary representation, not on a rule anyone chose. The shortest decimal that
|
|
7661
|
+
* reads back as the same number is what was written; handed to the column, the
|
|
7662
|
+
* database applies its one rounding rule, half away from zero. Where the
|
|
7663
|
+
* platform validates an amount to the column's places at its boundary, nothing
|
|
7664
|
+
* is rounded at all.
|
|
7665
|
+
*/
|
|
7666
|
+
declare function toDecimalString(value: number): string;
|
|
7667
|
+
|
|
7668
|
+
/**
|
|
7669
|
+
* A code whose name is taken — by a live code, or by a deleted one, since a
|
|
7670
|
+
* deleted code keeps its name (`SC-PROMO-028`). The platform checks before it
|
|
7671
|
+
* creates; this is what the unique index answers when two creates race past
|
|
7672
|
+
* that check.
|
|
7673
|
+
*/
|
|
7674
|
+
declare function promoCodeTaken(code: string): PersistenceRefusal;
|
|
7675
|
+
|
|
7676
|
+
/** The tenant has no subscription to write to. */
|
|
7677
|
+
declare function subscriptionGone(tenantId: string): PersistenceRefusal;
|
|
7678
|
+
/** The plan to bind has no version in effect at `asOf`. */
|
|
7679
|
+
declare function noActivePlanVersion(planId: string, asOf: Date): PersistenceRefusal;
|
|
7680
|
+
/** The plan to bind is not in the catalogue, or was retired in the meantime. */
|
|
7681
|
+
declare function planNotInCatalog(planKey: string): PersistenceRefusal;
|
|
7682
|
+
/** The booking to cancel does not exist. */
|
|
7683
|
+
declare function subscriptionBundleGone(subscriptionBundleId: string): PersistenceRefusal;
|
|
7684
|
+
/** The booking to cancel was cancelled first, by another request. */
|
|
7685
|
+
declare function subscriptionBundleAlreadyCancelled(subscriptionBundleId: string): PersistenceRefusal;
|
|
7686
|
+
/** No contract of the tenant named carries the id. */
|
|
7687
|
+
declare function subscriptionContractGone(contractId: string): PersistenceRefusal;
|
|
6075
7688
|
|
|
6076
7689
|
/** Feature key → its `requires` keys (from Discovery/FeatureCatalogEntry). */
|
|
6077
7690
|
type FeatureRequiresIndex = ReadonlyMap<string, readonly string[]>;
|
|
@@ -6807,13 +8420,6 @@ interface SetupConfirmMfaResponse {
|
|
|
6807
8420
|
ok: boolean;
|
|
6808
8421
|
}
|
|
6809
8422
|
|
|
6810
|
-
/** What the adapter's schema can actually answer about a version's dates. */
|
|
6811
|
-
interface PlanVersionMappingFields {
|
|
6812
|
-
/** `validFrom`/`validUntil` are maintained; otherwise both read as null. */
|
|
6813
|
-
validityWindows: boolean;
|
|
6814
|
-
/** `endsAt` exists; otherwise the field is left off the record entirely. */
|
|
6815
|
-
endsAt: boolean;
|
|
6816
|
-
}
|
|
6817
8423
|
/** A `plans` row as either adapter reads it back. */
|
|
6818
8424
|
interface CanonicalPlanRow {
|
|
6819
8425
|
id: string;
|
|
@@ -6841,9 +8447,9 @@ interface CanonicalPlanVersionRow {
|
|
|
6841
8447
|
publishedChanges: unknown;
|
|
6842
8448
|
changeNote: string;
|
|
6843
8449
|
nonRegressive: boolean;
|
|
6844
|
-
validFrom
|
|
6845
|
-
validUntil
|
|
6846
|
-
endsAt
|
|
8450
|
+
validFrom: Date | null;
|
|
8451
|
+
validUntil: Date | null;
|
|
8452
|
+
endsAt: Date | null;
|
|
6847
8453
|
createdByUserId: string | null;
|
|
6848
8454
|
publishedByUserId: string | null;
|
|
6849
8455
|
createdAt: Date;
|
|
@@ -6856,7 +8462,7 @@ declare function toPlanRow(row: CanonicalPlanRow): PlanRow;
|
|
|
6856
8462
|
* real foreign key has to resolve it first, and only the adapter knows which
|
|
6857
8463
|
* shape it is looking at.
|
|
6858
8464
|
*/
|
|
6859
|
-
declare function toPlanVersionRow(row: CanonicalPlanVersionRow, planKey: string
|
|
8465
|
+
declare function toPlanVersionRow(row: CanonicalPlanVersionRow, planKey: string): PlanVersionRow;
|
|
6860
8466
|
|
|
6861
8467
|
/**
|
|
6862
8468
|
* The legal identity of the issuer a catalogue names, or none where it names no
|
|
@@ -7298,4 +8904,4 @@ declare function resolveErrorMessage(body: ResolvableErrorBody, overrides?: Part
|
|
|
7298
8904
|
|
|
7299
8905
|
declare const ERROR_MESSAGES_DE: Record<PlatformErrorCode, string>;
|
|
7300
8906
|
|
|
7301
|
-
export { ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES, AUTH_ERROR_CODES, type ActionKey, type ActivationOrchestrator, type ActivePlanVersionWhere, type ActivePlanVersionWhereWithEndsAt, type ActiveVersionWhere, type ActiveVersionWhereWithEndsAt, type ActorTag, type AdminAccountEntry, type AdminAccountHolder, type AdminActor, type AdminAuditListFilter, type AdminManifest, type AdminResourcesPort, type AdminSubscriberAccount, type AdminSubscriptionListRow, type AdminTenantDetail, type AdminTenantListFilter, type AdminTenantListRow, type AdminTenantStateResult, type AdminUserListFilter, type AdminUserListRow, type AppliedSettingsPort, type AppliedSettingsRecord, type AppliedSettingsValues, type ApplyOnboardingSelectionInput, type ApplyOnboardingSelectionResult, type ApprovedCatalogKeys, type AuditActionDef, type AuditEntry, type AuditPort, type AuditQuery, type AuditQueryPort, type AuditStatsPort, type AuditStatsSnapshot, type AuthErrorCode, BILLING_ERROR_CODES, BUNDLE_PRICE_LOOKUP_LIMIT, type BillingCycle, type BillingErrorCode, type BundleAvailabilityState, type BundleCompatibility, type BundleFeatureShape, type BundleListFilter, type BundlePricingOverride, type BundleRepository, type BundleRow, type BundleVersionFields, type BundleVersionMutationResult, type BundleVersionRow, CATALOGUE_KEYS, CATALOG_ERROR_CODES, CONTRACT_ERROR_CODES, type CancelSubscriptionBundleData, type CancelSubscriptionInput, type CancelSubscriptionResult, type CancellationNoticePeriods, type CanonicalContractLineItemRow, type CanonicalContractRow, type CanonicalPlanRow, type CanonicalPlanVersionRow, type CanonicalRunningContractRow, type CanonicalSubscriberChargeRow, type CanonicalSubscriberCorrectionRow, type CanonicalSubscriberPaymentMethodRow, type CanonicalSubscriberRow, type CanonicalSubscriptionBundleRow, type CapabilityCatalogEntryRow, type CapabilityCodeStatus, type CapabilityKey, type CapabilityKind, type CatalogEntryFilter, type CatalogEntryI18n, type CatalogEntryI18nFields, type CatalogEntryRepository, type CatalogErrorCode, type ChangeDirection, type CheckoutOfferFilter, type CheckoutOfferLineItem, type CheckoutOfferLineItemKind, type CheckoutOfferPriceBreakdown, type CheckoutOfferPromoCodeSnapshot, type CheckoutOfferPromotionSnapshot, type CheckoutOfferRepository, type CheckoutOfferRow, type CheckoutOfferSelection, type CheckoutOfferSelectionUpdate, type CheckoutOfferStatus, type CleanupResult, type CliUserRow, type ComponentKey, type ConfiguratorCatalog, type ConfiguratorMarketingProvider, type ConfiguratorModel, type ConfiguratorPlanMarketing, type ConfiguratorPlanVersionRow, type ConfiguratorPriceBreakdown, type ConfiguratorSourcesLookup, type ConfirmedPaymentMethod, type ContractErrorCode, type ContractIssuerParty, type ContractLineItemKind, type ContractLineItemRecord, type ContractSubscriberParty, type CreateBundleData, type CreateBundleVersionDraftData, type CreateCheckoutOfferData, type CreateMarketingProjectionData, type CreatePlanData, type CreatePlanVersionDraftData, type CreatePromoCodeData, type CreatePromoCodeRequest, type CreatePromotionData, type CreateSubscriberData, type CreateSubscriptionBundleData, type CreateSubscriptionContractData, type CreateSuperAdminCliInput, type CreateTenantInput, type DiffResult, type DiscoveredCapability, type DiscoveredFeature, type DiscoveredQuota, type DiscoveredQuotaPolicy, type DiscoveryCodeStatus, type DiscoverySnapshot, type DiscoveryStatus, ERROR_MESSAGES_DE, ERROR_MESSAGES_EN, type EffectiveLimitsSnapshot, type EmailPort, type ErrorMessageParams, FEATURE_NOT_LICENSED, type FeatureCatalogEntryRow, type FeatureDef, type FeatureKey, type FeatureNotLicensedBody, type FeatureRequiresIndex, type FeatureTier, type FeatureUiMeta, type FeatureUiRegistry, type FinalActivationResult, type FirstTimeCustomerCheck, ForeignPaymentMethodReferenceError, type ImmediatePlanChangeInput, type InvoiceLineItemSnapshot, type IssuerCorrectionFault, type IssuerIdentityChange, type KpiCardDef, type KpiDisplayHint, LEGAL_IDENTITY_FIELDS, type LegalIdentity, type LegalIdentityField, MARKETING_PRIORITY_MAX, MARKETING_PRIORITY_MIN, type ManifestAccessPort, type ManifestContribution, type MarketingProjectionFilter, type MarketingProjectionRepository, type MarketingProjectionRow, type MarketingSettingsRepository, type MarketingSettingsRow, type MarketingTargetType, type MarketingTopFeature, type MaskedPaymentMethod, type MfaPort, type NewContractLineItemData, type NewSettingsChange, type NewSubscriberCharge, type NewSubscriberDetails, type NewSubscriptionContractData, OTP_RATE_LIMIT_MAX_SENDS, OTP_RATE_LIMIT_WINDOW_MINUTES, OTP_TTL_MINUTES, OTP_VERIFY_MAX_ATTEMPTS, type OnboardingPromoRedemption, type OnboardingSelectionRequest, type OnboardingSelectionResponse, PASSWORD_RESET_TTL_MINUTES, PAYMENT_ERROR_CODES, PAYMENT_METHOD_TYPES, PENDING_CHECKOUT_TTL_DAYS, PENDING_EMAIL_TTL_HOURS, PENDING_ONBOARDING_TTL_DAYS, PLATFORM_ERROR_CODES, PROMO_ERROR_CODES, type Paginated, type PartyAddress, type PasswordHasher, type PasswordResetCliResult, PaymentCallbackRejectedError, type PaymentErrorCode, type PaymentEventClaim, type PaymentEventLog, type PaymentGateway, type PaymentGatewayCallback, type PaymentGatewayEvent, type PaymentMethodHolder, type PaymentMethodSetupSession, type PaymentMethodSetupSubject, type PaymentMethodType, type PendingRegistration, type PendingRegistrationCreateInput, type PendingRegistrationRepository, type PendingRegistrationSnapshot, type PendingRegistrationUpdateInput, type PersistenceCapabilities, PersistenceCapabilityError, type PersistenceClassRef, type PersistenceInjectionToken, type PersistenceProvider, type PlanCatalog, type PlanCatalogApp, type PlanCatalogImportReport, type PlanCatalogImportSink, type PlanCatalogIssuer, type PlanCatalogIssuerCorrection, type PlanCatalogLookup, type PlanCatalogMarketing, type PlanCatalogNotifications, type PlanCatalogPaymentAccount, type PlanCatalogPayments, type PlanCatalogReadSink, type PlanCatalogReadSnapshot, type PlanCatalogSettings, type PlanCatalogSubscribers, type PlanCatalogTenantBilling, type PlanDef, type PlanId, type PlanListFilter, type PlanRepository, type PlanRow, type PlanVersion, type PlanVersionFields, type PlanVersionMappingFields, type PlanVersionMutationResult, type PlanVersionRecord, type PlanVersionRepository, type PlanVersionRow, type PlatformErrorBody, type PlatformErrorCode, type PlatformRole, type PlatformUserDto, PlatformUserExistsError, type ProjectPageDef, type PromoCode, type PromoCodeDurationType, type PromoCodeFilter, type PromoCodeHoldRecord, type PromoCodeHoldRepository, type PromoCodeHoldTaken, type PromoCodeRecord, type PromoCodeRedemption, type PromoCodeRedemptionListItem, type PromoCodeRedemptionRecord, type PromoCodeRedemptionRepository, type PromoCodeRedemptionStatus, type PromoCodeRepository, type PromoCodeStatsPort, type PromoCodeStatsSnapshot, type PromoCodeStatus, type PromoCodeValidationLog, type PromoCodeValidationLogRepository, type PromoCodeValidationResult, type PromoCodeValueType, type PromoErrorCode, type PromoPreviewInvalidReason, type PromoPreviewRequest, type PromoPreviewResponse, type PromoPreviewValidResponse, type PromoRevenueDeductionAggregator, type PromoSubscriptionLookup, type PromotionBillingCycle, type PromotionI18n, type PromotionI18nFields, type PromotionOnPrice, type PromotionRepository, type PromotionResult, type PromotionRow, type PromotionStatus, type PromotionTargetType, type PromotionType, type PromotionValue, type PublicBootResponse, type PublicComparisonRow, type PublicMarketingBundle, type PublicMarketingCatalogResponse, type PublicMarketingPlan, type PublicMarketingPromo, type PublicNewPaymentMethods, type PublicSignupPlan, type PublishBundleVersionData, type PublishBundleVersionMeta, type PublishPlanVersionData, type QuotaCatalogEntryRow, type QuotaEnforcementMode, type QuotaKey, type QuotaProvider, REGISTRATION_ERROR_CODES, REGISTRATION_RESUME_TTL_MINUTES, REGISTRATION_STEP_BY_STATUS, type ReassignTenantAdminCliResult, type RecommendablePlan, type RecordSubscriberPaymentMethodData, type RecordSubscriberPaymentMethodOutcome, type RecordSubscriberPaymentMethodResult, type RedeemPromoInTransactionCallback, type RegistrationActivation, type RegistrationAuditContext, type RegistrationAuditEvent, type RegistrationAuditEventType, type RegistrationAuditLogger, type RegistrationBillingDetails, type RegistrationConfigSelection, type RegistrationConfiguratorLookup, type RegistrationErrorCode, type RegistrationOtpDelivery, type RegistrationPromoPreview, type RegistrationResumeDelivery, type RegistrationResumeTokenSigner, type RegistrationStatus, type RegistrationStep, type RequiredCapabilities, type ResolvableErrorBody, type ResumeRegistrationInput, type ResumeRegistrationResult, type ReviewCatalogEntryData, type RlsBypassPort, type RunningContractIssuer, type RunningContractIssuers, SETTINGS_ERROR_CODES, SETUP_ERROR_CODES, SUBSCRIBER_ACCOUNT_CAPABILITY, SUBSCRIBER_ERROR_CODES, type SaaSiCatPersistenceAdapter, type SaaSiCatPersistenceAdminResources, type SaaSiCatPersistenceCatalog, type SaaSiCatPersistenceCore, type SaaSiCatPersistenceEntitlement, type SaaSiCatPersistencePayments, type SaaSiCatPersistencePromo, type SaaSiCatPersistenceTenantBilling, type SaveRegistrationConfigInput, type SaveRegistrationConfigResult, type ScheduledPlanChangeInput, type SelectPlanInput, type SelectPlanResult, type SelectableBundleShape, type SelfServiceBlockedPlans, type SetCatalogEntryReviewData, type SettingsChangeFilter, type SettingsChangeRecord, type SettingsDifference, type SettingsErrorCode, type SetupConfirmMfaRequest, type SetupConfirmMfaResponse, type SetupErrorCode, type SetupRequest, type SetupResult, type SetupStatusResponse, type SlugAvailabilityCheck, type StandardPageDef, type StandardPageKey, type StartCheckoutInput, type StartCheckoutResult, type StartPaymentMethodSetupInput, type StartRegistrationInput, type StartRegistrationResult, type StoredBundleStem, type StrictModeWarning, type StrictModeWarningCode, type SubscriberCharge, type SubscriberChargeOrigin, type SubscriberChargeRecord, type SubscriberChargeSource, type SubscriberContact, type SubscriberContactChange, type SubscriberCorrectionData, type SubscriberCorrectionRecord, type SubscriberCorrectionResult, type SubscriberDetails, type SubscriberErrorCode, type SubscriberIdentityCorrection, type SubscriberIdentityDelta, type SubscriberIdentityValues, type SubscriberLedgerRepository, type SubscriberPaymentMethodRecord, type SubscriberPaymentMethodReference, type SubscriberPaymentMethodRepository, type SubscriberPaymentMethodSetupData, type SubscriberPaymentMethodSetupMatch, type SubscriberPaymentMethodStatus, type SubscriberRecord, type SubscriberRepository, type Subscription, type SubscriptionBundleRecord, type SubscriptionBundleRepository, type SubscriptionBundleView, type SubscriptionContractFilter, type SubscriptionContractInvoiceSnapshot, type SubscriptionContractParties, type SubscriptionContractPriceSnapshot, type SubscriptionContractRecord, type SubscriptionContractRepository, type SubscriptionContractStatus, type SubscriptionRecord, type SubscriptionRepository, type SubscriptionStatsPort, type SubscriptionStatsSnapshot, type SubscriptionStatus, type SubscriptionUsagePort, type SubscriptionUsageRecord, type SuperAdminProvisioningPort, type SyncDiscoveryResult, type TenantActionDef, type TenantColumnDef, type TenantDto, type TenantListFilter, type TenantPort, type TenantSubscriptionWritePort, type TerminateSubscriptionContractData, type TopPromoCode, type TransactionContext, type TransactionRunner, type UpdateBundleData, type UpdateBundleVersionDraftData, type UpdateCatalogEntryBaseData, type UpdateCatalogEntryI18nData, type UpdateCheckoutOfferData, type UpdateMarketingProjectionData, type UpdateMarketingSettingsData, type UpdatePlanData, type UpdatePlanVersionDraftData, type UpdatePromoCodeData, type UpdatePromoCodeRequest, type UpdatePromotionData, type UpsellOffer, type UpsellOfferResolver, type UpsertCapabilityEntryData, type UpsertFeatureCatalogEntryInput, type UpsertFeatureEntryData, type UpsertPlanInput, type UpsertPlanVersionInput, type UpsertQuotaEntryData, type UpsertResult, type UsageSnapshotPort, type UserAccountLookup, type UserListFilter, type UserManagementPort, type UserPort, type VerifyRegistrationOtpResult, type VersionChange, type VersionChangeDirection, type VersionEditability, type VersionEditableReason, type VersionedEntityBase, applyPromo, assertPersistenceCapabilities, buildActivePlanVersionWhere, buildActiveVersionWhere, buildFeatureRequiresIndex, bundleDraftDefaults, bundleStemDefaults, canonicalJson, classifyBundleVersionDiff, classifyIssuerChange, classifyPlanDiff, collectUnsatisfiedRequires, contractPartiesOf, coverageExcludingSelf, definedFields, diffSettings, formatCustomerNumber, formatErrorMessage, identityCorrectionDelta, isBundleRedundant, isForeignPaymentMethodReferenceError, isPaymentCallbackRejectedError, isPlatformUserExistsError, isVersionEditable, issuerIdentityOf, keepOneRecommended, missingRequiresFor, movedIdentityFields, pickActivePromo, planCatalogSettingsOf, previousUtcDay, promoStatus, promotionOnPrice, readQuotaRecord, readQuotaValue, recordedIssuerIdentity, refuseForeignPaymentMethodReference, resolveBundleAvailability, resolveErrorMessage, sameLegalIdentity, selectChargeableBundles, settingsSubtreeOf, startOfUtcDay, subscriberChargeColumns, subscriberFromRegistration, subscriberPaymentMethodColumns, toBundleStemRow, toContractLineItemRecord, toPlanRow, toPlanVersionRow, toRunningContractIssuer, toSubscriberChargeRecord, toSubscriberCorrectionRecord, toSubscriberPaymentMethodRecord, toSubscriberRecord, toSubscriptionBundleRecord, toSubscriptionContractRecord };
|
|
8907
|
+
export { ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES, AUTH_ERROR_CODES, type ActionKey, type ActivationOrchestrator, type ActivePlanVersionWhere, type ActivePlanVersionWhereWithEndsAt, type ActiveVersionWhere, type ActiveVersionWhereWithEndsAt, type ActorTag, type AdminAccountEntry, type AdminAccountHolder, type AdminActor, type AdminAuditListFilter, type AdminManifest, type AdminResourcesPort, type AdminSubscriberAccount, type AdminSubscriptionListRow, type AdminTenantDetail, type AdminTenantListFilter, type AdminTenantListRow, type AdminTenantStateResult, type AdminUserListFilter, type AdminUserListRow, type AppliedSettingsPort, type AppliedSettingsRecord, type AppliedSettingsValues, type ApplyOnboardingSelectionInput, type ApplyOnboardingSelectionResult, type ApprovedCatalogKeys, type AuditActionDef, type AuditActor, type AuditEntry, type AuditPort, type AuditQuery, type AuditQueryPort, type AuditStatsPort, type AuditStatsSnapshot, type AuthErrorCode, BILLING_ERROR_CODES, BUNDLE_PRICE_LOOKUP_LIMIT, type BillingCycle, type BillingErrorCode, type BundleAvailabilityState, type BundleCompatibility, type BundleFeatureShape, type BundleListFilter, type BundlePricingOverride, type BundleRepository, type BundleRow, type BundleVersionFields, type BundleVersionMutationResult, type BundleVersionRow, CATALOGUE_KEYS, CATALOG_ERROR_CODES, CONTRACT_ERROR_CODES, CUSTOM_LIMITS_KEYS, type CancelSubscriptionBundleData, type CancelSubscriptionInput, type CancelSubscriptionResult, type CancellationNoticePeriods, type CanonicalContractLineItemRow, type CanonicalContractRow, type CanonicalMaintenanceWindowRow, type CanonicalPlanRow, type CanonicalPlanVersionRow, type CanonicalRunningContractRow, type CanonicalSubscriberChargeRow, type CanonicalSubscriberCorrectionRow, type CanonicalSubscriberPaymentMethodRow, type CanonicalSubscriberRow, type CanonicalSubscriptionBundleRow, type CanonicalSubscriptionNoticeRow, type CanonicalVersionRetirementRow, type CapabilityCatalogEntryRow, type CapabilityCodeStatus, type CapabilityKey, type CapabilityKind, type CatalogEntryFilter, type CatalogEntryI18n, type CatalogEntryI18nFields, type CatalogEntryRepository, type CatalogErrorCode, type CatalogVersionKind, type ChangeDirection, type CheckoutOfferFilter, type CheckoutOfferLineItem, type CheckoutOfferLineItemKind, type CheckoutOfferPriceBreakdown, type CheckoutOfferPromoCodeSnapshot, type CheckoutOfferPromotionSnapshot, type CheckoutOfferRepository, type CheckoutOfferRow, type CheckoutOfferSelection, type CheckoutOfferSelectionUpdate, type CheckoutOfferStatus, type CleanupResult, type CliUserRow, type ComponentKey, type ConcurrencyGate, type ConfiguratorCatalog, type ConfiguratorMarketingProvider, type ConfiguratorModel, type ConfiguratorPlanMarketing, type ConfiguratorPlanVersionRow, type ConfiguratorPriceBreakdown, type ConfiguratorSourcesLookup, type ConfirmedPaymentMethod, type ContractErrorCode, type ContractIssuerParty, type ContractLineItemKind, type ContractLineItemRecord, type ContractSubscriberParty, type CreateBundleData, type CreateBundleVersionDraftData, type CreateCheckoutOfferData, type CreateMarketingProjectionData, type CreatePlanData, type CreatePlanVersionDraftData, type CreatePromoCodeData, type CreatePromoCodeRequest, type CreatePromotionData, type CreateSubscriberData, type CreateSubscriptionBundleData, type CreateSubscriptionContractData, type CreateSuperAdminCliInput, type CreateTenantInput, type CustomLimits, type DiffResult, type DiscoveredCapability, type DiscoveredFeature, type DiscoveredQuota, type DiscoveredQuotaPolicy, type DiscoveryCodeStatus, type DiscoverySnapshot, type DiscoveryStatus, ERROR_MESSAGES_DE, ERROR_MESSAGES_EN, type EffectiveLimitsSnapshot, type EmailPort, type ErrorMessageParams, FEATURE_NOT_LICENSED, type FeatureCatalogEntryRow, type FeatureDef, type FeatureKey, type FeatureNotLicensedBody, type FeatureRequiresIndex, type FeatureTier, type FeatureUiMeta, type FeatureUiRegistry, type FinalActivationResult, type FirstTimeCustomerCheck, ForeignPaymentMethodReferenceError, type ImmediatePlanChangeInput, type InvoiceLineItemSnapshot, type IssuerCorrectionFault, type IssuerIdentityChange, type KpiCardDef, type KpiDisplayHint, LEGAL_IDENTITY_FIELDS, type LegalIdentity, type LegalIdentityField, MAINTENANCE_CAPABILITY, MAINTENANCE_ERROR_CODES, MAINTENANCE_MESSAGE_MAX_LENGTH, MAINTENANCE_STATE_MAX_AGE_SECONDS, MARKETING_PRIORITY_MAX, MARKETING_PRIORITY_MIN, type MaintenanceErrorCode, type MaintenanceLockView, type MaintenanceNotificationPort, type MaintenanceOverview, type MaintenanceStatusView, type MaintenanceUnlockView, type MaintenanceWindowChanges, type MaintenanceWindowEvent, type MaintenanceWindowPort, type MaintenanceWindowRecord, type MaintenanceWindowStage, type MaintenanceWindowStatus, type MaintenanceWindowView, type ManifestAccessPort, type ManifestContribution, type MarketingProjectionFilter, type MarketingProjectionRepository, type MarketingProjectionRow, type MarketingSettingsRepository, type MarketingSettingsRow, type MarketingTargetType, type MarketingTopFeature, type MaskedPaymentMethod, type MfaPort, NO_SCHEDULED_CHANGE, type NewContractLineItemData, type NewMaintenanceWindow, type NewSettingsChange, type NewSubscriberCharge, type NewSubscriberDetails, type NewSubscriptionContractData, type NewVersionRetirement, type NoticeToRecord, OPTIONAL_CANONICAL_MODELS, OTP_RATE_LIMIT_MAX_SENDS, OTP_RATE_LIMIT_WINDOW_MINUTES, OTP_TTL_MINUTES, OTP_VERIFY_MAX_ATTEMPTS, type OnboardingPromoRedemption, type OnboardingSelectionRequest, type OnboardingSelectionResponse, type OptionalBundleMember, type OptionalCanonicalModel, type OrderlyRetirementSettings, PASSWORD_RESET_TTL_MINUTES, PAYMENT_ERROR_CODES, PAYMENT_METHOD_TYPES, PENDING_CHECKOUT_TTL_DAYS, PENDING_EMAIL_TTL_HOURS, PENDING_ONBOARDING_TTL_DAYS, PLATFORM_ERROR_CODES, PROMO_ERROR_CODES, type Paginated, type PartyAddress, type PasswordHasher, type PasswordResetCliResult, PaymentCallbackRejectedError, type PaymentErrorCode, type PaymentEventClaim, type PaymentEventLog, type PaymentGateway, type PaymentGatewayCallback, type PaymentGatewayEvent, type PaymentMethodHolder, type PaymentMethodSetupSession, type PaymentMethodSetupSubject, type PaymentMethodType, type PendingRegistration, type PendingRegistrationCreateInput, type PendingRegistrationRepository, type PendingRegistrationSnapshot, type PendingRegistrationUpdateInput, type PersistenceCapabilities, PersistenceCapabilityError, type PersistenceClassRef, type PersistenceInjectionToken, type PersistenceProvider, PersistenceRefusal, type PersistenceRefusalReason, type PlanCatalog, type PlanCatalogApp, type PlanCatalogImportReport, type PlanCatalogImportSink, type PlanCatalogIssuer, type PlanCatalogIssuerCorrection, type PlanCatalogLookup, type PlanCatalogMarketing, type PlanCatalogNotifications, type PlanCatalogPaymentAccount, type PlanCatalogPayments, type PlanCatalogReadSink, type PlanCatalogReadSnapshot, type PlanCatalogSettings, type PlanCatalogSubscribers, type PlanCatalogTenantBilling, type PlanDef, type PlanId, type PlanListFilter, type PlanRepository, type PlanRow, type PlanVersion, type PlanVersionFields, type PlanVersionMutationResult, type PlanVersionRecord, type PlanVersionRepository, type PlanVersionRow, type PlatformErrorBody, type PlatformErrorCode, type PlatformJobActor, type PlatformRole, type PlatformUserDto, PlatformUserExistsError, type ProjectPageDef, type PromoCode, type PromoCodeDurationType, type PromoCodeFilter, type PromoCodeHoldRecord, type PromoCodeHoldRepository, type PromoCodeHoldTaken, type PromoCodeRecord, type PromoCodeRedemption, type PromoCodeRedemptionListItem, type PromoCodeRedemptionRecord, type PromoCodeRedemptionRepository, type PromoCodeRedemptionStatus, type PromoCodeRepository, type PromoCodeStatsPort, type PromoCodeStatsSnapshot, type PromoCodeStatus, type PromoCodeValidationLog, type PromoCodeValidationLogRepository, type PromoCodeValidationResult, type PromoCodeValueType, type PromoErrorCode, type PromoPreviewInvalidReason, type PromoPreviewRequest, type PromoPreviewResponse, type PromoPreviewValidResponse, type PromoRevenueDeductionAggregator, type PromoSubscriptionLookup, type PromotionBillingCycle, type PromotionI18n, type PromotionI18nFields, type PromotionOnPrice, type PromotionRepository, type PromotionResult, type PromotionRow, type PromotionStatus, type PromotionTargetType, type PromotionType, type PromotionValue, type PublicBootResponse, type PublicComparisonRow, type PublicMarketingBundle, type PublicMarketingCatalogResponse, type PublicMarketingPlan, type PublicMarketingPromo, type PublicNewPaymentMethods, type PublicSignupPlan, type PublishBundleVersionData, type PublishBundleVersionMeta, type PublishPlanVersionData, type QuotaCatalogEntryRow, type QuotaEnforcementMode, type QuotaKey, type QuotaProvider, REGISTRATION_ERROR_CODES, REGISTRATION_RESUME_TTL_MINUTES, REGISTRATION_STEP_BY_STATUS, RETIREMENT_REMINDER_LEAD_DAYS, type ReadCustomLimits, type ReassignTenantAdminCliResult, type RecommendablePlan, type RecordSubscriberPaymentMethodData, type RecordSubscriberPaymentMethodOutcome, type RecordSubscriberPaymentMethodResult, type RedeemPromoInTransactionCallback, type RegistrationActivation, type RegistrationAuditContext, type RegistrationAuditEvent, type RegistrationAuditEventType, type RegistrationAuditLogger, type RegistrationBillingDetails, type RegistrationConfigSelection, type RegistrationConfiguratorLookup, type RegistrationErrorCode, type RegistrationOtpDelivery, type RegistrationPromoPreview, type RegistrationResumeDelivery, type RegistrationResumeTokenSigner, type RegistrationStatus, type RegistrationStep, type RequiredCapabilities, type ResolvableErrorBody, type ResumeRegistrationInput, type ResumeRegistrationResult, type RetiredVersionRef, type RetirementAnnounced, type RetirementBlocker, type RetirementMoveRun, type RetirementPreview, type RetirementProgress, type RetirementReachedRow, type RetirementSide, type RetirementSkipReason, type RetirementSkippedRow, type RetirementSwitchResult, type RetirementSwitchTerms, type ReviewCatalogEntryData, type RlsBypassPort, type RunningContractIssuer, type RunningContractIssuers, SETTINGS_ERROR_CODES, SETUP_ERROR_CODES, SUBSCRIBER_ACCOUNT_CAPABILITY, SUBSCRIBER_ERROR_CODES, type SaaSiCatPersistenceAdapter, type SaaSiCatPersistenceAdminResources, type SaaSiCatPersistenceCatalog, type SaaSiCatPersistenceCore, type SaaSiCatPersistenceEntitlement, type SaaSiCatPersistencePayments, type SaaSiCatPersistencePromo, type SaaSiCatPersistenceTenantBilling, type SaveRegistrationConfigInput, type SaveRegistrationConfigResult, type ScheduledChangeColumns, type ScheduledPlanChangeInput, type SecretSealer, type SelectPlanInput, type SelectPlanResult, type SelectableBundleShape, type SelfServiceBlockedPlans, type SetCatalogEntryReviewData, type SettingsChangeFilter, type SettingsChangeRecord, type SettingsDifference, type SettingsErrorCode, type SetupConfirmMfaRequest, type SetupConfirmMfaResponse, type SetupErrorCode, type SetupRequest, type SetupResult, type SetupStatusResponse, type SlugAvailabilityCheck, type StandardPageDef, type StandardPageKey, type StartCheckoutInput, type StartCheckoutResult, type StartPaymentMethodSetupInput, type StartRegistrationInput, type StartRegistrationResult, type StoredBundleStem, type StrictModeWarning, type StrictModeWarningCode, type SubscriberCharge, type SubscriberChargeOrigin, type SubscriberChargeRecord, type SubscriberChargeSource, type SubscriberContact, type SubscriberContactChange, type SubscriberCorrectionData, type SubscriberCorrectionRecord, type SubscriberCorrectionResult, type SubscriberDetails, type SubscriberErrorCode, type SubscriberIdentityCorrection, type SubscriberIdentityDelta, type SubscriberIdentityValues, type SubscriberLedgerRepository, type SubscriberPaymentMethodRecord, type SubscriberPaymentMethodReference, type SubscriberPaymentMethodRepository, type SubscriberPaymentMethodSetupData, type SubscriberPaymentMethodSetupMatch, type SubscriberPaymentMethodStatus, type SubscriberRecord, type SubscriberRepository, type Subscription, type SubscriptionBundleRecord, type SubscriptionBundleRepository, type SubscriptionBundleView, type SubscriptionContractFilter, type SubscriptionContractInvoiceSnapshot, type SubscriptionContractParties, type SubscriptionContractPriceSnapshot, type SubscriptionContractRecord, type SubscriptionContractRepository, type SubscriptionContractStatus, type SubscriptionNotice, type SubscriptionNoticeDelivery, type SubscriptionNoticeKey, type SubscriptionNoticeKind, type SubscriptionNoticePort, type SubscriptionNoticeRecord, type SubscriptionNoticeRepository, type SubscriptionRecord, type SubscriptionRepository, type SubscriptionStatsPort, type SubscriptionStatsSnapshot, type SubscriptionStatus, type SubscriptionUsagePort, type SubscriptionUsageRecord, type SuperAdminProvisioningPort, type SupersedeSubscriptionContractData, type SyncDiscoveryResult, type TenantActionDef, type TenantColumnDef, type TenantDto, type TenantListFilter, type TenantPort, type TenantSubscriptionUsage, type TenantSubscriptionWritePort, type TerminateSubscriptionContractData, type TopPromoCode, type TransactionContext, type TransactionRunner, type UpdateBundleData, type UpdateBundleVersionDraftData, type UpdateCatalogEntryBaseData, type UpdateCatalogEntryI18nData, type UpdateCheckoutOfferData, type UpdateMarketingProjectionData, type UpdateMarketingSettingsData, type UpdatePlanData, type UpdatePlanVersionDraftData, type UpdatePromoCodeData, type UpdatePromoCodeRequest, type UpdatePromotionData, type UpsellOffer, type UpsellOfferResolver, type UpsertCapabilityEntryData, type UpsertFeatureCatalogEntryInput, type UpsertFeatureEntryData, type UpsertPlanInput, type UpsertPlanVersionInput, type UpsertQuotaEntryData, type UpsertResult, type UsageSnapshotPort, type UserAccountLookup, type UserListFilter, type UserManagementPort, type UserPort, VERSION_RETIREMENT_CAPABILITY, type VerifyRegistrationOtpResult, type VersionChange, type VersionChangeDirection, type VersionEditability, type VersionEditableReason, type VersionOffer, type VersionOfferClass, type VersionOfferFields, type VersionOfferSide, type VersionOfferView, type VersionOfferedNotice, type VersionRetiredNotice, type VersionRetirementRecord, type VersionRetirementReminder, type VersionRetirementRepository, type VersionRetirementView, type VersionSale, type VersionSaleDates, type VersionSaleKind, type VersionSwitchResult, type VersionWindow, type VersionedEntityBase, applyPromo, assertPersistenceCapabilities, buildActivePlanVersionWhere, buildActiveVersionWhere, buildFeatureRequiresIndex, bundleDraftDefaults, bundleKeyTaken, bundleStemDefaults, canonicalJson, catalogDraftExists, catalogVersionAlreadyPublished, catalogVersionGone, classifyBundleVersionDiff, classifyIssuerChange, classifyPlanDiff, classifyVersionOffer, collectUnsatisfiedRequires, computeIncludedVat, concurrencyGate, concurrencyGateOf, contractPartiesOf, coverageExcludingSelf, customLimitsReader, definedFields, diffSettings, formatCustomerNumber, formatErrorMessage, grossFromNet, identityCorrectionDelta, isBundleRedundant, isForeignPaymentMethodReferenceError, isMaintenanceAnnouncementLapsed, isMaintenanceOverrun, isPaymentCallbackRejectedError, isPersistenceRefusal, isPlatformUserExistsError, isVersionActiveAt, isVersionEditable, issuerIdentityOf, keepOneRecommended, maintenanceRetryAfterSeconds, maintenanceStatusOf, maintenanceWindowStatusOf, maintenanceWindowViewOf, marketingProjectionTaken, membersLeftOut, missingRequiresFor, movedIdentityFields, netFromGross, noActivePlanVersion, parseZonedInstant, percentOf, pickActivePromo, planCatalogSettingsOf, planKeyTaken, planNotInCatalog, previousUtcDay, promoCodeTaken, promoStatus, promotionOnPrice, prorate, readCustomLimits, readQuotaRecord, readQuotaValue, recordedIssuerIdentity, refuseForeignPaymentMethodReference, resolveBundleAvailability, resolveErrorMessage, retirementCostsTheSubscription, retirementReminderDueAt, retirementReminderIsDue, retirementSwitchTerms, roundToCents, sameLegalIdentity, scheduledChangeAfterWrite, selectChargeableBundles, settingsSubtreeOf, startOfUtcDay, subscriberChargeColumns, subscriberFromRegistration, subscriberPaymentMethodColumns, subscriptionBundleAlreadyCancelled, subscriptionBundleGone, subscriptionContractGone, subscriptionGone, sumToCents, toBundleStemRow, toCents, toContractLineItemRecord, toDecimalString, toMaintenanceWindowRecord, toPlanRow, toPlanVersionRow, toRunningContractIssuer, toSubscriberChargeRecord, toSubscriberCorrectionRecord, toSubscriberPaymentMethodRecord, toSubscriberRecord, toSubscriptionBundleRecord, toSubscriptionContractRecord, toSubscriptionNoticeRecord, toVersionRetirementRecord, versionOnSale, versionOnSaleOrNext, versionSale };
|