@saasicat/core 1.0.0-rc.14 → 1.0.0-rc.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -589,8 +589,38 @@ interface PlanCatalogNotifications {
589
589
  /** Addresses mailed when a start finds the applied settings changed. */
590
590
  settingsChanged?: string[];
591
591
  }
592
- interface PlanCatalog {
593
- schemaVersion: 1;
592
+ /**
593
+ * The legal entity on the operator's side of every contract the installation
594
+ * concludes. A contract copies it on the day it is concluded; only the legal
595
+ * name is required while nothing is invoiced.
596
+ */
597
+ interface PlanCatalogIssuer {
598
+ legalName: string;
599
+ addressLine1?: string;
600
+ addressLine2?: string;
601
+ postalCode?: string;
602
+ city?: string;
603
+ /** ISO 3166-1 alpha-2. */
604
+ country?: string;
605
+ vatId?: string;
606
+ taxNumber?: string;
607
+ }
608
+ /** How the parties contracts are concluded with are numbered. */
609
+ interface PlanCatalogSubscribers {
610
+ /**
611
+ * Put in front of every customer number assigned from the next start on.
612
+ * A number keeps the prefix it was assigned with.
613
+ */
614
+ customerNumberPrefix?: string;
615
+ }
616
+ /**
617
+ * The part of `config/saas.yaml` that is configuration rather than catalogue.
618
+ *
619
+ * Declared apart so it can be handed on whole — a database catalogue takes its
620
+ * settings from the file and its plans from the database — without anybody
621
+ * listing the blocks again. `CATALOGUE_KEYS` names what is left over.
622
+ */
623
+ interface PlanCatalogSettings {
594
624
  /** App identity (branding + version), see PlanCatalogApp. */
595
625
  app: PlanCatalogApp;
596
626
  /** ISO-4217 currency code. */
@@ -603,6 +633,13 @@ interface PlanCatalog {
603
633
  marketing?: PlanCatalogMarketing;
604
634
  /** Who is told when the settings change between two starts. Optional. */
605
635
  notifications?: PlanCatalogNotifications;
636
+ /** The operator's side of every contract. Optional until invoicing requires it. */
637
+ issuer?: PlanCatalogIssuer;
638
+ /** How subscribers are numbered. Optional. */
639
+ subscribers?: PlanCatalogSubscribers;
640
+ }
641
+ interface PlanCatalog extends PlanCatalogSettings {
642
+ schemaVersion: 1;
606
643
  features?: FeatureDef[];
607
644
  /**
608
645
  * Optional. When omitted, plans come exclusively from the
@@ -2125,6 +2162,14 @@ interface SettingsDifference {
2125
2162
  * property the schema declares lands on one side.
2126
2163
  */
2127
2164
  declare const CATALOGUE_KEYS: ReadonlySet<keyof PlanCatalog>;
2165
+ /**
2166
+ * The settings of a catalogue, typed, for handing them on as a whole.
2167
+ *
2168
+ * The same selection as `settingsSubtreeOf`, which is why it is that function:
2169
+ * a caller that listed the blocks it passes on would drop the next one the
2170
+ * schema gains, and nothing would say so.
2171
+ */
2172
+ declare function planCatalogSettingsOf(catalog: PlanCatalog): PlanCatalogSettings;
2128
2173
  /** Everything in the catalogue that is configuration, as it was resolved. */
2129
2174
  declare function settingsSubtreeOf(catalog: PlanCatalog): AppliedSettingsValues;
2130
2175
  /**
@@ -2758,6 +2803,130 @@ interface PromoRevenueDeductionAggregator {
2758
2803
  sumGrossForPromoCode(promoCodeId: string): Promise<string>;
2759
2804
  }
2760
2805
 
2806
+ /** The address lines a party is named with. Every one of them may be unknown. */
2807
+ interface PartyAddress {
2808
+ /** Street and number. */
2809
+ addressLine1: string | null;
2810
+ /** A second line, such as a building or a c/o. */
2811
+ addressLine2: string | null;
2812
+ postalCode: string | null;
2813
+ city: string | null;
2814
+ /** ISO 3166-1 alpha-2, upper case. */
2815
+ country: string | null;
2816
+ }
2817
+ /**
2818
+ * What names a legal entity: the name it is registered under and the
2819
+ * identifiers its tax office gave it.
2820
+ *
2821
+ * For a subscriber these are the party a contract was concluded with. Under a
2822
+ * running contract they change only as a correction of that same entity,
2823
+ * recorded with the values it replaced and the reason; contact details change
2824
+ * freely.
2825
+ */
2826
+ interface LegalIdentity {
2827
+ /** The registered name, legal form included. */
2828
+ legalName: string;
2829
+ /** VAT identification number. */
2830
+ vatId: string | null;
2831
+ /** The national tax number, where one is stated beside or instead of the VAT id. */
2832
+ taxNumber: string | null;
2833
+ }
2834
+ /** The fields of the legal identity, the ones a correction may change. */
2835
+ type SubscriberIdentityField = keyof LegalIdentity;
2836
+ /** How a subscriber is reached, which may change at any time. */
2837
+ interface SubscriberContact extends PartyAddress {
2838
+ /** Where invoices will be sent. */
2839
+ invoiceEmail: string | null;
2840
+ }
2841
+ /** A subscriber's master data, as it stands. */
2842
+ type SubscriberDetails = LegalIdentity & SubscriberContact;
2843
+ /**
2844
+ * What a subscriber is created with.
2845
+ *
2846
+ * Only the legal name is required. The address, the tax identifiers and the
2847
+ * invoice email stay optional until sign-up asks for them and invoicing
2848
+ * requires them; an absent or blank value is recorded as unknown.
2849
+ */
2850
+ type NewSubscriberDetails = Pick<SubscriberDetails, 'legalName'> & Partial<Omit<SubscriberDetails, 'legalName'>>;
2851
+ interface SubscriberRecord extends SubscriberDetails {
2852
+ id: string;
2853
+ /**
2854
+ * Assigned when the subscriber is created and never changed: the number,
2855
+ * counted per installation, behind the prefix configured at that moment.
2856
+ */
2857
+ customerNumber: string;
2858
+ /** The tenant this subscriber is live for, or `null` once it has none. */
2859
+ tenantId: string | null;
2860
+ /**
2861
+ * Created by the migration that gave every existing tenant its subscriber,
2862
+ * from the application's own tenant record rather than from what a customer
2863
+ * entered.
2864
+ */
2865
+ migrated: boolean;
2866
+ createdAt: Date;
2867
+ updatedAt: Date;
2868
+ }
2869
+ /** What a repository writes for a new subscriber, every detail already settled. */
2870
+ interface CreateSubscriberData extends SubscriberDetails {
2871
+ /** The tenant the subscriber is created for and live with. */
2872
+ tenantId: string;
2873
+ /** Put in front of the assigned number; empty for the number alone. */
2874
+ customerNumberPrefix: string;
2875
+ }
2876
+ /** Contact details to change; a member left out keeps its value. */
2877
+ type SubscriberContactChange = Partial<SubscriberContact>;
2878
+ /**
2879
+ * A change to a subscriber's legal identity, and what the operator declares it
2880
+ * to be.
2881
+ *
2882
+ * SaaSiCat cannot tell a misspelt name from another company taking over, so the
2883
+ * operator says which: `correction` for the same legal entity — a typo, a wrong
2884
+ * tax identifier, a change of name that entity went through — and `takeover`
2885
+ * for another one, which is a transfer rather than an edit and is refused.
2886
+ */
2887
+ interface SubscriberIdentityCorrection {
2888
+ kind: 'correction' | 'takeover';
2889
+ legalName?: string;
2890
+ vatId?: string | null;
2891
+ taxNumber?: string | null;
2892
+ /** Why the identity is corrected. Part of the record. */
2893
+ reason: string;
2894
+ /** Who corrects it, as an actor tag the audit log would write. */
2895
+ correctedBy: string;
2896
+ }
2897
+ /** Identity values by field, holding only the fields a correction changed. */
2898
+ type SubscriberIdentityValues = Partial<LegalIdentity>;
2899
+ /** What a correction replaces and what it writes, holding only the fields that move. */
2900
+ interface SubscriberIdentityDelta {
2901
+ previous: SubscriberIdentityValues;
2902
+ corrected: SubscriberIdentityValues;
2903
+ }
2904
+ /** What a repository writes for a correction the service has accepted. */
2905
+ interface SubscriberCorrectionData {
2906
+ /** The new values; a field equal to what is stored is not recorded. */
2907
+ corrected: SubscriberIdentityValues;
2908
+ reason: string;
2909
+ correctedBy: string;
2910
+ correctedAt: Date;
2911
+ }
2912
+ /** One correction of a subscriber's legal identity, as it was recorded. */
2913
+ interface SubscriberCorrectionRecord {
2914
+ id: string;
2915
+ subscriberId: string;
2916
+ /** The values the correction replaced. */
2917
+ previous: SubscriberIdentityValues;
2918
+ /** The values it wrote. */
2919
+ corrected: SubscriberIdentityValues;
2920
+ reason: string;
2921
+ correctedBy: string;
2922
+ correctedAt: Date;
2923
+ }
2924
+ /** The outcome of writing a correction: nothing is recorded when no value moved. */
2925
+ interface SubscriberCorrectionResult {
2926
+ subscriber: SubscriberRecord;
2927
+ correction: SubscriberCorrectionRecord | null;
2928
+ }
2929
+
2761
2930
  type ContractLineItemKind = 'plan' | 'bundle' | 'discount';
2762
2931
  type SubscriptionContractStatus = 'active' | 'scheduled' | 'terminated' | 'superseded';
2763
2932
  /**
@@ -2832,9 +3001,40 @@ interface SubscriptionContractPriceSnapshot {
2832
3001
  vatRate: number;
2833
3002
  totalGross: number;
2834
3003
  }
2835
- interface SubscriptionContractRecord {
3004
+ /**
3005
+ * The subscriber as a contract copied it on the day it was concluded.
3006
+ *
3007
+ * The invoice email is not part of it: it says how the party is reached, not
3008
+ * who the party is, and a contract is kept for years after an address like that
3009
+ * stopped mattering.
3010
+ */
3011
+ interface ContractSubscriberParty extends LegalIdentity, PartyAddress {
3012
+ customerNumber: string;
3013
+ }
3014
+ /** The issuer as `config/saas.yaml` named it on the day a contract was concluded. */
3015
+ interface ContractIssuerParty extends LegalIdentity, PartyAddress {
3016
+ }
3017
+ /** Who a contract is between, copied when it is concluded. */
3018
+ interface SubscriptionContractParties {
3019
+ subscriberId: string;
3020
+ subscriber: ContractSubscriberParty;
3021
+ /** `null` where `config/saas.yaml` named no issuer that day. */
3022
+ issuer: ContractIssuerParty | null;
3023
+ }
3024
+ interface SubscriptionContractRecord extends SubscriptionContractParties {
2836
3025
  id: string;
3026
+ /**
3027
+ * The tenant the contract was concluded for, kept as a trace. The contract
3028
+ * belongs to its subscriber and outlives the tenant.
3029
+ */
2837
3030
  tenantId: string;
3031
+ /**
3032
+ * The parties were copied by the migration that attached contracts
3033
+ * concluded before subscribers existed, not on the day the contract was
3034
+ * concluded. Either party may have changed in between, so such a copy is
3035
+ * never presented as what was agreed.
3036
+ */
3037
+ partiesMigrated: boolean;
2838
3038
  status: SubscriptionContractStatus;
2839
3039
  effectiveFrom: Date;
2840
3040
  effectiveUntil: Date | null;
@@ -2851,6 +3051,11 @@ interface SubscriptionContractRecord {
2851
3051
  updatedAt: Date;
2852
3052
  }
2853
3053
  type NewContractLineItemData = Omit<ContractLineItemRecord, 'id' | 'contractId' | 'createdAt'>;
3054
+ /**
3055
+ * A contract as a caller asks for it. The parties are not among it: the
3056
+ * platform copies them from the tenant's subscriber and the configuration when
3057
+ * the contract is written, so no caller can name a party of its own.
3058
+ */
2854
3059
  interface CreateSubscriptionContractData {
2855
3060
  tenantId: string;
2856
3061
  status?: SubscriptionContractStatus;
@@ -2866,6 +3071,10 @@ interface CreateSubscriptionContractData {
2866
3071
  termsSnapshot?: Record<string, unknown> | null;
2867
3072
  lineItems: NewContractLineItemData[];
2868
3073
  }
3074
+ /** What a repository writes: the contract as asked for, with the parties the platform copied. */
3075
+ interface NewSubscriptionContractData extends CreateSubscriptionContractData {
3076
+ parties: SubscriptionContractParties;
3077
+ }
2869
3078
  interface TerminateSubscriptionContractData {
2870
3079
  effectiveUntil: Date;
2871
3080
  /**
@@ -3085,9 +3294,53 @@ interface SubscriptionContractRepository {
3085
3294
  * instead of drawing an extra pool connection (starvation guard, #70).
3086
3295
  */
3087
3296
  findActiveByTenantId(tenantId: string, asOf?: Date, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
3088
- create(data: CreateSubscriptionContractData): Promise<SubscriptionContractRecord>;
3297
+ /**
3298
+ * Writes the contract with the parties it names. With `tx`, the contract is
3299
+ * written on that transaction and undone with it.
3300
+ */
3301
+ create(data: NewSubscriptionContractData, tx?: TransactionContext): Promise<SubscriptionContractRecord>;
3302
+ /**
3303
+ * The contract concluded from a checkout offer (`originalOfferId`), or
3304
+ * `null` when none was. An offer is consumed once and so yields one
3305
+ * contract (`SC-MKT-017`); where an application's own path wrote two, the
3306
+ * earliest is returned, so the answer does not depend on read order.
3307
+ */
3308
+ findByOriginalOfferId(offerId: string, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
3089
3309
  terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
3090
3310
  }
3311
+ /**
3312
+ * The parties contracts are concluded with, their link to the tenant they are
3313
+ * live for, and the corrections of their legal identity.
3314
+ *
3315
+ * A subscriber has at most one live tenant and a tenant at most one live
3316
+ * subscriber; the database holds both, so two callers creating one for the
3317
+ * same tenant at once end with one.
3318
+ */
3319
+ interface SubscriberRepository {
3320
+ /**
3321
+ * Creates a subscriber, assigns its customer number, and makes it the
3322
+ * tenant's live subscriber — all or nothing. `null` when the tenant already
3323
+ * has a live subscriber, in which case nothing is written and the caller's
3324
+ * transaction stays usable.
3325
+ */
3326
+ createForTenant(data: CreateSubscriberData, tx?: TransactionContext): Promise<SubscriberRecord | null>;
3327
+ findById(subscriberId: string, tx?: TransactionContext): Promise<SubscriberRecord | null>;
3328
+ /** The subscriber live for this tenant, or `null` when it has none. */
3329
+ findByTenantId(tenantId: string, tx?: TransactionContext): Promise<SubscriberRecord | null>;
3330
+ /** Writes the members given and keeps the rest; `null` when no such subscriber exists. */
3331
+ updateContact(subscriberId: string, change: SubscriberContactChange, tx?: TransactionContext): Promise<SubscriberRecord | null>;
3332
+ /**
3333
+ * Writes a correction of the legal identity and records it, in one step:
3334
+ * the subscriber is read and changed under a lock, so the values recorded
3335
+ * as replaced are the ones this write replaced even when two corrections
3336
+ * arrive at once. A field whose stored value already equals the corrected
3337
+ * one is left out of the record, and when none differs nothing is written
3338
+ * and `correction` is `null`. `null` when no such subscriber exists.
3339
+ */
3340
+ correctIdentity(subscriberId: string, data: SubscriberCorrectionData, tx?: TransactionContext): Promise<SubscriberCorrectionResult | null>;
3341
+ /** Every correction of this subscriber, the latest first. */
3342
+ listCorrections(subscriberId: string): Promise<SubscriberCorrectionRecord[]>;
3343
+ }
3091
3344
  /**
3092
3345
  * Display form of a subscription for the tenant self-service UI.
3093
3346
  * Richer than `SubscriptionRecord` (which is only the aggregation form); contains
@@ -4030,8 +4283,19 @@ interface CheckoutOfferRepository {
4030
4283
  findById(id: string): Promise<CheckoutOfferRow | null>;
4031
4284
  create(data: CreateCheckoutOfferData): Promise<CheckoutOfferRow>;
4032
4285
  update(id: string, data: UpdateCheckoutOfferData): Promise<CheckoutOfferRow>;
4033
- /** Sets `status = 'consumed'` + `consumedAt = NOW()`. */
4034
- consume(id: string): Promise<CheckoutOfferRow>;
4286
+ /**
4287
+ * Sets `status = 'consumed'` + `consumedAt = NOW()`, and only while the
4288
+ * offer is still `open`: the write carries that condition, so of two
4289
+ * callers consuming at once one succeeds and the other is refused with
4290
+ * `CHECKOUT_OFFER_ALREADY_CONSUMED` (or `CHECKOUT_OFFER_EXPIRED`). A check
4291
+ * before the write cannot decide it, because the status can change in
4292
+ * between.
4293
+ *
4294
+ * With `tx`, the write runs on that transaction, so it is undone with
4295
+ * everything else the transaction wrote. `CheckoutOfferService.conclude`
4296
+ * depends on that; the persistence contract holds both.
4297
+ */
4298
+ consume(id: string, tx?: TransactionContext): Promise<CheckoutOfferRow>;
4035
4299
  }
4036
4300
 
4037
4301
  /** Which changes to list. */
@@ -4159,6 +4423,8 @@ interface SaaSiCatPersistenceEntitlement {
4159
4423
  subscriptionRepository: PersistenceProvider<SubscriptionRepository>;
4160
4424
  planVersionRepository: PersistenceProvider<PlanVersionRepository>;
4161
4425
  subscriptionContractRepository?: PersistenceProvider<SubscriptionContractRepository>;
4426
+ /** The parties contracts are concluded with; required wherever contracts are written. */
4427
+ subscriberRepository?: PersistenceProvider<SubscriberRepository>;
4162
4428
  subscriptionBundleRepository?: PersistenceProvider<SubscriptionBundleRepository>;
4163
4429
  bundleRepository?: PersistenceProvider<BundleRepository>;
4164
4430
  }
@@ -4461,11 +4727,40 @@ declare const CONTRACT_ERROR_CODES: {
4461
4727
  readonly CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED";
4462
4728
  readonly CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED";
4463
4729
  readonly CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED";
4730
+ /**
4731
+ * The offer changed between the checks of `conclude` and the transaction
4732
+ * that consumed it, so the contract checked is not the one the offer now
4733
+ * describes. Nothing was written; load the offer and conclude it again.
4734
+ */
4735
+ readonly CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED";
4464
4736
  readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
4465
4737
  readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
4466
4738
  readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
4467
4739
  };
4468
4740
  type ContractErrorCode = (typeof CONTRACT_ERROR_CODES)[keyof typeof CONTRACT_ERROR_CODES];
4741
+ /** The parties contracts are concluded with (`SubscriberService`), and their absence. */
4742
+ declare const SUBSCRIBER_ERROR_CODES: {
4743
+ /**
4744
+ * A contract, a plan change or a booking for a tenant that has no
4745
+ * subscriber. Nothing is agreed or charged without the party to it.
4746
+ * Carries `tenantId`.
4747
+ */
4748
+ readonly SUBSCRIBER_REQUIRED: "SUBSCRIBER_REQUIRED";
4749
+ /** The tenant already has a live subscriber. Carries `tenantId`. */
4750
+ readonly SUBSCRIBER_ALREADY_EXISTS: "SUBSCRIBER_ALREADY_EXISTS";
4751
+ readonly SUBSCRIBER_NOT_FOUND: "SUBSCRIBER_NOT_FOUND";
4752
+ readonly SUBSCRIBER_LEGAL_NAME_REQUIRED: "SUBSCRIBER_LEGAL_NAME_REQUIRED";
4753
+ /** A detail that has a form — the country, the invoice email — is not in it. Carries `field`. */
4754
+ readonly SUBSCRIBER_DETAIL_INVALID: "SUBSCRIBER_DETAIL_INVALID";
4755
+ /** A contact change named a field of the legal identity. Carries `field`. */
4756
+ readonly SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "SUBSCRIBER_IDENTITY_NOT_A_CONTACT";
4757
+ readonly SUBSCRIBER_CORRECTION_REASON_REQUIRED: "SUBSCRIBER_CORRECTION_REASON_REQUIRED";
4758
+ readonly SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "SUBSCRIBER_CORRECTION_ACTOR_REQUIRED";
4759
+ readonly SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "SUBSCRIBER_CORRECTION_CHANGES_NOTHING";
4760
+ /** The operator declared another legal entity: that is a transfer, not an edit. */
4761
+ readonly SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "SUBSCRIBER_TAKEOVER_IS_A_TRANSFER";
4762
+ };
4763
+ type SubscriberErrorCode = (typeof SUBSCRIBER_ERROR_CODES)[keyof typeof SUBSCRIBER_ERROR_CODES];
4469
4764
  /** Self-service registration funnel (`PendingRegistration`). */
4470
4765
  declare const REGISTRATION_ERROR_CODES: {
4471
4766
  readonly PENDING_REGISTRATION_NOT_FOUND: "PENDING_REGISTRATION_NOT_FOUND";
@@ -4555,6 +4850,25 @@ declare const PLATFORM_ERROR_CODES: {
4555
4850
  readonly PLAN_NOT_AVAILABLE: "PLAN_NOT_AVAILABLE";
4556
4851
  readonly PLAN_NOT_SELECTED: "PLAN_NOT_SELECTED";
4557
4852
  readonly MODEL_NOT_AVAILABLE: "MODEL_NOT_AVAILABLE";
4853
+ /**
4854
+ * A contract, a plan change or a booking for a tenant that has no
4855
+ * subscriber. Nothing is agreed or charged without the party to it.
4856
+ * Carries `tenantId`.
4857
+ */
4858
+ readonly SUBSCRIBER_REQUIRED: "SUBSCRIBER_REQUIRED";
4859
+ /** The tenant already has a live subscriber. Carries `tenantId`. */
4860
+ readonly SUBSCRIBER_ALREADY_EXISTS: "SUBSCRIBER_ALREADY_EXISTS";
4861
+ readonly SUBSCRIBER_NOT_FOUND: "SUBSCRIBER_NOT_FOUND";
4862
+ readonly SUBSCRIBER_LEGAL_NAME_REQUIRED: "SUBSCRIBER_LEGAL_NAME_REQUIRED";
4863
+ /** A detail that has a form — the country, the invoice email — is not in it. Carries `field`. */
4864
+ readonly SUBSCRIBER_DETAIL_INVALID: "SUBSCRIBER_DETAIL_INVALID";
4865
+ /** A contact change named a field of the legal identity. Carries `field`. */
4866
+ readonly SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "SUBSCRIBER_IDENTITY_NOT_A_CONTACT";
4867
+ readonly SUBSCRIBER_CORRECTION_REASON_REQUIRED: "SUBSCRIBER_CORRECTION_REASON_REQUIRED";
4868
+ readonly SUBSCRIBER_CORRECTION_ACTOR_REQUIRED: "SUBSCRIBER_CORRECTION_ACTOR_REQUIRED";
4869
+ readonly SUBSCRIBER_CORRECTION_CHANGES_NOTHING: "SUBSCRIBER_CORRECTION_CHANGES_NOTHING";
4870
+ /** The operator declared another legal entity: that is a transfer, not an edit. */
4871
+ readonly SUBSCRIBER_TAKEOVER_IS_A_TRANSFER: "SUBSCRIBER_TAKEOVER_IS_A_TRANSFER";
4558
4872
  readonly CHECKOUT_OFFER_LINE_ITEMS_REQUIRED: "CHECKOUT_OFFER_LINE_ITEMS_REQUIRED";
4559
4873
  readonly CHECKOUT_OFFER_PLAN_LINE_ITEM_REQUIRED: "CHECKOUT_OFFER_PLAN_LINE_ITEM_REQUIRED";
4560
4874
  readonly CHECKOUT_OFFER_BUNDLE_LINE_ITEMS_REQUIRED: "CHECKOUT_OFFER_BUNDLE_LINE_ITEMS_REQUIRED";
@@ -4576,6 +4890,12 @@ declare const PLATFORM_ERROR_CODES: {
4576
4890
  readonly CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED";
4577
4891
  readonly CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED";
4578
4892
  readonly CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED";
4893
+ /**
4894
+ * The offer changed between the checks of `conclude` and the transaction
4895
+ * that consumed it, so the contract checked is not the one the offer now
4896
+ * describes. Nothing was written; load the offer and conclude it again.
4897
+ */
4898
+ readonly CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED";
4579
4899
  readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
4580
4900
  readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
4581
4901
  readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
@@ -4789,7 +5109,7 @@ declare const PLATFORM_ERROR_CODES: {
4789
5109
  /** Email already taken (mapped from `PlatformUserExistsError`). */
4790
5110
  readonly EMAIL_EXISTS: "EMAIL_EXISTS";
4791
5111
  };
4792
- type PlatformErrorCode = SetupErrorCode | AuthErrorCode | PromoErrorCode | CatalogErrorCode | BillingErrorCode | ContractErrorCode | RegistrationErrorCode | SettingsErrorCode;
5112
+ type PlatformErrorCode = SetupErrorCode | AuthErrorCode | PromoErrorCode | CatalogErrorCode | BillingErrorCode | ContractErrorCode | SubscriberErrorCode | RegistrationErrorCode | SettingsErrorCode;
4793
5113
  /**
4794
5114
  * Shape of a coded error response.
4795
5115
  *
@@ -5113,15 +5433,24 @@ interface FinalActivationResult {
5113
5433
  userId: string;
5114
5434
  tenantId: string;
5115
5435
  subscriptionId: string;
5436
+ /**
5437
+ * The subscriber created for the tenant in the same transaction — the party
5438
+ * its contracts are concluded with. `subscriberFromRegistration(pending)`
5439
+ * says what it is created with.
5440
+ */
5441
+ subscriberId: string;
5116
5442
  }
5117
5443
  /**
5118
5444
  * Adapter port: orchestrates the final creation of User + Tenant +
5119
- * Subscription after successful payment. App-specific — each app has its
5120
- * own schema (e.g. Tenant + TenantUser + Role + UserRole +
5445
+ * Subscriber + Subscription after successful payment. App-specific — each app
5446
+ * has its own schema (e.g. Tenant + TenantUser + Role + UserRole +
5121
5447
  * Subscription).
5122
5448
  *
5123
5449
  * Implementations MUST perform the creation in a DB transaction so that
5124
- * partial creations are fully rolled back on errors.
5450
+ * partial creations are fully rolled back on errors. The subscriber is created
5451
+ * there too, before any contract: `SubscriberService.createForTenant(tenantId,
5452
+ * details, tx)`, or `CheckoutOfferService.conclude` with `subscriber`, which
5453
+ * creates it on the transaction it concludes the offer on.
5125
5454
  */
5126
5455
  interface ActivationOrchestrator {
5127
5456
  activate(pending: PendingRegistration): Promise<FinalActivationResult>;
@@ -5586,10 +5915,71 @@ declare function toPlanRow(row: CanonicalPlanRow): PlanRow;
5586
5915
  */
5587
5916
  declare function toPlanVersionRow(row: CanonicalPlanVersionRow, planKey: string, fields: PlanVersionMappingFields): PlanVersionRow;
5588
5917
 
5918
+ /** The fields a correction of the legal identity may change, in the order they are shown. */
5919
+ declare const SUBSCRIBER_IDENTITY_FIELDS: readonly SubscriberIdentityField[];
5920
+ /** A `subscribers` row as either adapter reads it back. */
5921
+ interface CanonicalSubscriberRow {
5922
+ id: string;
5923
+ customerSequence: number;
5924
+ customerNumberPrefix: string;
5925
+ legalName: string;
5926
+ addressLine1: string | null;
5927
+ addressLine2: string | null;
5928
+ postalCode: string | null;
5929
+ city: string | null;
5930
+ country: string | null;
5931
+ vatId: string | null;
5932
+ taxNumber: string | null;
5933
+ invoiceEmail: string | null;
5934
+ migrated: boolean;
5935
+ createdAt: Date;
5936
+ updatedAt: Date;
5937
+ }
5938
+ /** A `subscriber_corrections` row as either adapter reads it back. */
5939
+ interface CanonicalSubscriberCorrectionRow {
5940
+ id: string;
5941
+ subscriberId: string;
5942
+ previous: unknown;
5943
+ corrected: unknown;
5944
+ reason: string;
5945
+ correctedBy: string;
5946
+ correctedAt: Date;
5947
+ }
5948
+ /**
5949
+ * The customer number a subscriber is known by: the prefix it was assigned
5950
+ * with, then the number. Kept apart in storage so the number orders and the
5951
+ * prefix stays what it was on the day it was assigned.
5952
+ */
5953
+ declare function formatCustomerNumber(prefix: string, sequence: number): string;
5954
+ /** `tenantId` is the tenant the subscriber's live link names, read beside the row. */
5955
+ declare function toSubscriberRecord(row: CanonicalSubscriberRow, tenantId: string | null): SubscriberRecord;
5956
+ declare function toSubscriberCorrectionRecord(row: CanonicalSubscriberCorrectionRow): SubscriberCorrectionRecord;
5957
+ /**
5958
+ * The part of a correction that changes something: every corrected field whose
5959
+ * stored value differs, with the value it replaces. Both adapters decide this
5960
+ * the same way, under the lock they read `current` with.
5961
+ */
5962
+ declare function identityCorrectionDelta(current: Pick<SubscriberRecord, SubscriberIdentityField>, corrected: SubscriberIdentityValues): SubscriberIdentityDelta;
5963
+ /**
5964
+ * Who a new contract is between: the subscriber as it stands, and the issuer as
5965
+ * the running configuration names it — or no issuer, where it names none.
5966
+ */
5967
+ declare function contractPartiesOf(subscriber: SubscriberRecord, issuer: PlanCatalog['issuer']): SubscriptionContractParties;
5968
+ /**
5969
+ * The subscriber a completed sign-up is created with: the name the tenant was
5970
+ * registered under as its legal name, and the address the registration was
5971
+ * verified with as its invoice email. Sign-up collects nothing more yet.
5972
+ */
5973
+ declare function subscriberFromRegistration(pending: Pick<PendingRegistration, 'tenantName' | 'email'>): NewSubscriberDetails;
5974
+
5589
5975
  /** A `subscription_contracts` row as either adapter reads it back. */
5590
5976
  interface CanonicalContractRow {
5591
5977
  id: string;
5592
5978
  tenantId: string;
5979
+ subscriberId: string;
5980
+ subscriberSnapshot: unknown;
5981
+ issuerSnapshot: unknown;
5982
+ partiesMigrated: boolean;
5593
5983
  status: string;
5594
5984
  effectiveFrom: Date;
5595
5985
  effectiveUntil: Date | null;
@@ -5711,4 +6101,4 @@ declare function resolveErrorMessage(body: ResolvableErrorBody, overrides?: Part
5711
6101
 
5712
6102
  declare const ERROR_MESSAGES_DE: Record<PlatformErrorCode, string>;
5713
6103
 
5714
- export { ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES, AUTH_ERROR_CODES, type ActionKey, type ActivationOrchestrator, type ActivePlanVersionWhere, type ActivePlanVersionWhereWithEndsAt, type ActiveVersionWhere, type ActiveVersionWhereWithEndsAt, type ActorTag, type AdminActor, type AdminAuditListFilter, type AdminManifest, type AdminResourcesPort, 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 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 CheckoutSession, type CleanupResult, type CliUserRow, type ComponentKey, type ConfiguratorCatalog, type ConfiguratorMarketingProvider, type ConfiguratorModel, type ConfiguratorPlanMarketing, type ConfiguratorPlanVersionRow, type ConfiguratorPriceBreakdown, type ConfiguratorSourcesLookup, type ContractErrorCode, type ContractLineItemKind, type ContractLineItemRecord, type CreateBundleData, type CreateBundleVersionDraftData, type CreateCheckoutOfferData, type CreateMarketingProjectionData, type CreatePlanData, type CreatePlanVersionDraftData, type CreatePromoCodeData, type CreatePromoCodeRequest, type CreatePromotionData, 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, type HandlePaymentEventInput, type HandlePaymentEventReason, type HandlePaymentEventResult, type ImmediatePlanChangeInput, type InvoiceLineItemSnapshot, type KpiCardDef, type KpiDisplayHint, 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 MfaPort, type NewContractLineItemData, type NewSettingsChange, 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, PENDING_CHECKOUT_TTL_DAYS, PENDING_EMAIL_TTL_HOURS, PENDING_ONBOARDING_TTL_DAYS, PLATFORM_ERROR_CODES, PROMO_ERROR_CODES, type Paginated, type PasswordHasher, type PasswordResetCliResult, type PaymentEventLog, type PaymentEventStatus, type PaymentProvider, 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 PlanCatalogLookup, type PlanCatalogMarketing, type PlanCatalogNotifications, type PlanCatalogReadSink, type PlanCatalogReadSnapshot, 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 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 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 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 RedeemPromoInTransactionCallback, type RegistrationAuditContext, type RegistrationAuditEvent, type RegistrationAuditEventType, type RegistrationAuditLogger, 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, SETTINGS_ERROR_CODES, SETUP_ERROR_CODES, type SaaSiCatPersistenceAdapter, type SaaSiCatPersistenceAdminResources, type SaaSiCatPersistenceCatalog, type SaaSiCatPersistenceCore, type SaaSiCatPersistenceEntitlement, 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 StartRegistrationInput, type StartRegistrationResult, type StoredBundleStem, type StrictModeWarning, type StrictModeWarningCode, type Subscription, type SubscriptionBundleRecord, type SubscriptionBundleRepository, type SubscriptionBundleView, type SubscriptionContractFilter, type SubscriptionContractInvoiceSnapshot, 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, classifyPlanDiff, collectUnsatisfiedRequires, coverageExcludingSelf, definedFields, diffSettings, formatErrorMessage, isBundleRedundant, isPlatformUserExistsError, isVersionEditable, keepOneRecommended, missingRequiresFor, pickActivePromo, previousUtcDay, promoStatus, readQuotaRecord, readQuotaValue, resolveBundleAvailability, resolveErrorMessage, selectChargeableBundles, settingsSubtreeOf, startOfUtcDay, toBundleStemRow, toContractLineItemRecord, toPlanRow, toPlanVersionRow, toSubscriptionContractRecord };
6104
+ export { ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES, AUTH_ERROR_CODES, type ActionKey, type ActivationOrchestrator, type ActivePlanVersionWhere, type ActivePlanVersionWhereWithEndsAt, type ActiveVersionWhere, type ActiveVersionWhereWithEndsAt, type ActorTag, type AdminActor, type AdminAuditListFilter, type AdminManifest, type AdminResourcesPort, 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 CanonicalSubscriberCorrectionRow, type CanonicalSubscriberRow, 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 CheckoutSession, type CleanupResult, type CliUserRow, type ComponentKey, type ConfiguratorCatalog, type ConfiguratorMarketingProvider, type ConfiguratorModel, type ConfiguratorPlanMarketing, type ConfiguratorPlanVersionRow, type ConfiguratorPriceBreakdown, type ConfiguratorSourcesLookup, 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, type HandlePaymentEventInput, type HandlePaymentEventReason, type HandlePaymentEventResult, type ImmediatePlanChangeInput, type InvoiceLineItemSnapshot, type KpiCardDef, type KpiDisplayHint, type LegalIdentity, 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 MfaPort, type NewContractLineItemData, type NewSettingsChange, 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, 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, type PaymentEventLog, type PaymentEventStatus, type PaymentProvider, 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 PlanCatalogLookup, type PlanCatalogMarketing, type PlanCatalogNotifications, 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 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 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 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 RedeemPromoInTransactionCallback, type RegistrationAuditContext, type RegistrationAuditEvent, type RegistrationAuditEventType, type RegistrationAuditLogger, 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, SETTINGS_ERROR_CODES, SETUP_ERROR_CODES, SUBSCRIBER_ERROR_CODES, SUBSCRIBER_IDENTITY_FIELDS, type SaaSiCatPersistenceAdapter, type SaaSiCatPersistenceAdminResources, type SaaSiCatPersistenceCatalog, type SaaSiCatPersistenceCore, type SaaSiCatPersistenceEntitlement, 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 StartRegistrationInput, type StartRegistrationResult, type StoredBundleStem, type StrictModeWarning, type StrictModeWarningCode, type SubscriberContact, type SubscriberContactChange, type SubscriberCorrectionData, type SubscriberCorrectionRecord, type SubscriberCorrectionResult, type SubscriberDetails, type SubscriberErrorCode, type SubscriberIdentityCorrection, type SubscriberIdentityDelta, type SubscriberIdentityField, type SubscriberIdentityValues, 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, classifyPlanDiff, collectUnsatisfiedRequires, contractPartiesOf, coverageExcludingSelf, definedFields, diffSettings, formatCustomerNumber, formatErrorMessage, identityCorrectionDelta, isBundleRedundant, isPlatformUserExistsError, isVersionEditable, keepOneRecommended, missingRequiresFor, pickActivePromo, planCatalogSettingsOf, previousUtcDay, promoStatus, readQuotaRecord, readQuotaValue, resolveBundleAvailability, resolveErrorMessage, selectChargeableBundles, settingsSubtreeOf, startOfUtcDay, subscriberFromRegistration, toBundleStemRow, toContractLineItemRecord, toPlanRow, toPlanVersionRow, toSubscriberCorrectionRecord, toSubscriberRecord, toSubscriptionContractRecord };