@saasicat/nest 1.0.0-rc.2 → 1.0.0-rc.21

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.
Files changed (154) hide show
  1. package/README.md +44 -8
  2. package/dist/.build-stamp +1 -1
  3. package/dist/_entries.cjs +10214 -4796
  4. package/dist/admin/index.d.cts +5 -4
  5. package/dist/admin/index.d.ts +5 -4
  6. package/dist/admin/index.js +13 -9
  7. package/dist/{admin-resources.module-CpvzcfCc.d.cts → admin-resources.module-B4XNvdH-.d.cts} +1 -2
  8. package/dist/{admin-resources.module-DF5_Q7RD.d.ts → admin-resources.module-CWqdI9BV.d.ts} +1 -2
  9. package/dist/{admin-stats.service-TYiSUwIR.d.ts → admin-stats.service-CsLNt19Z.d.ts} +11 -7
  10. package/dist/{admin-stats.service-DfKupywR.d.cts → admin-stats.service-DrZrU8IJ.d.cts} +11 -7
  11. package/dist/{aggregation-B3CD0v_d.d.cts → aggregation-ChpZDh0g.d.ts} +39 -6
  12. package/dist/{aggregation-BFzW07DE.d.ts → aggregation-OpnhwzF5.d.cts} +39 -6
  13. package/dist/billing/index.d.cts +448 -108
  14. package/dist/billing/index.d.ts +448 -108
  15. package/dist/billing/index.js +108 -41
  16. package/dist/catalog/index.d.cts +74 -45
  17. package/dist/catalog/index.d.ts +74 -45
  18. package/dist/catalog/index.js +21 -13
  19. package/dist/catalog.module-C9O7BxRq.d.ts +180 -0
  20. package/dist/catalog.module-T-I5Ricz.d.cts +180 -0
  21. package/dist/checkout-offer/index.d.cts +17 -22
  22. package/dist/checkout-offer/index.d.ts +17 -22
  23. package/dist/checkout-offer/index.js +21 -7
  24. package/dist/checkout-offer.module-DFhGy6JO.d.cts +58 -0
  25. package/dist/checkout-offer.module-x7SP_dX4.d.ts +58 -0
  26. package/dist/checkout-offer.service-BeHgYikI.d.ts +242 -0
  27. package/dist/checkout-offer.service-CCVxG9b2.d.cts +242 -0
  28. package/dist/chunk-34XVPR6P.js +222 -0
  29. package/dist/{chunk-AOQJEYOL.js → chunk-3QVGA6JX.js} +3 -1
  30. package/dist/chunk-3RLWML2S.js +896 -0
  31. package/dist/{chunk-TXC3LHHB.js → chunk-4SDSYV4A.js} +21 -13
  32. package/dist/chunk-55QEDAMX.js +946 -0
  33. package/dist/chunk-5CKC7O52.js +140 -0
  34. package/dist/chunk-6PJE7EWO.js +185 -0
  35. package/dist/chunk-7NJKVC5X.js +353 -0
  36. package/dist/{chunk-RUNZ3X4C.js → chunk-AOS2JPDD.js} +1263 -185
  37. package/dist/{chunk-WOVQPXV4.js → chunk-CQ2ZZMTD.js} +702 -725
  38. package/dist/{chunk-NA6O63B7.js → chunk-F5X66HF5.js} +5 -5
  39. package/dist/chunk-FEQZCWUL.js +174 -0
  40. package/dist/{chunk-VIJ5NJWC.js → chunk-G6EZWECL.js} +107 -31
  41. package/dist/chunk-G7RQO2XO.js +0 -0
  42. package/dist/{chunk-N3L3AICU.js → chunk-GPQWGA6B.js} +5 -6
  43. package/dist/chunk-GZTL64QK.js +7 -0
  44. package/dist/{chunk-SABTXESR.js → chunk-J7NJRK3K.js} +17 -1
  45. package/dist/{chunk-SEPN52AD.js → chunk-JBCC6C3M.js} +566 -307
  46. package/dist/{chunk-I7GTA3RX.js → chunk-JQRA724W.js} +1 -1
  47. package/dist/{chunk-WXYJHZCN.js → chunk-JVAEKTJ4.js} +2 -14
  48. package/dist/chunk-KPEMTBOP.js +26 -0
  49. package/dist/chunk-LF6J4YYN.js +301 -0
  50. package/dist/{chunk-LTT736P3.js → chunk-LLYVYRGJ.js} +228 -387
  51. package/dist/{chunk-6Z7JR4EW.js → chunk-M47BNEY2.js} +1897 -633
  52. package/dist/{chunk-KFT5AIIH.js → chunk-NDLC5GYK.js} +206 -24
  53. package/dist/{chunk-O2J2HDXA.js → chunk-OOTEXP47.js} +3 -8
  54. package/dist/chunk-QPVDCKYS.js +702 -0
  55. package/dist/{chunk-NHVDCYK5.js → chunk-R5YCJBHY.js} +71 -106
  56. package/dist/{chunk-XBYAFEOR.js → chunk-S33SO5XX.js} +1 -1
  57. package/dist/chunk-SZ7RFPXA.js +10 -0
  58. package/dist/chunk-TBBZWZQT.js +98 -0
  59. package/dist/chunk-TOEFN7DN.js +295 -0
  60. package/dist/{chunk-7ZEGFL42.js → chunk-WHJSYKNC.js} +6 -6
  61. package/dist/chunk-WOEJ6K7M.js +55 -0
  62. package/dist/{chunk-AU3OOREM.js → chunk-XSSWYPP5.js} +16 -3
  63. package/dist/contract-line-item-money-B0Z3Ogur.d.cts +43 -0
  64. package/dist/contract-line-item-money-B0Z3Ogur.d.ts +43 -0
  65. package/dist/discovery/index.d.cts +2 -2
  66. package/dist/discovery/index.d.ts +2 -2
  67. package/dist/discovery/index.js +6 -6
  68. package/dist/{discovery.scanner-9cMqF95o.d.cts → discovery.scanner-DXKc6JkV.d.cts} +1 -1
  69. package/dist/{discovery.scanner-9cMqF95o.d.ts → discovery.scanner-DXKc6JkV.d.ts} +1 -1
  70. package/dist/{enforce-quota.interceptor-Df0e3OWe.d.cts → enforce-quota.interceptor-BFyVdWe8.d.cts} +6 -6
  71. package/dist/{enforce-quota.interceptor-DW3etVyI.d.ts → enforce-quota.interceptor-GaBXboGx.d.ts} +6 -6
  72. package/dist/entitlement/index.d.cts +27 -4
  73. package/dist/entitlement/index.d.ts +27 -4
  74. package/dist/entitlement/index.js +13 -8
  75. package/dist/index.d.cts +209 -28
  76. package/dist/index.d.ts +209 -28
  77. package/dist/index.js +285 -163
  78. package/dist/issuer-identity.check-CBO0vcsq.d.cts +197 -0
  79. package/dist/issuer-identity.check-Cz9CEMkZ.d.ts +197 -0
  80. package/dist/{module-options-COSEb0VW.d.ts → module-options-DmQ3G4sZ.d.ts} +135 -41
  81. package/dist/{module-options-BG3MzQva.d.cts → module-options-qAOwinHR.d.cts} +135 -41
  82. package/dist/payment-callback.service-CR84Xw1Z.d.cts +125 -0
  83. package/dist/payment-callback.service-CR84Xw1Z.d.ts +125 -0
  84. package/dist/payments/index.cjs +4 -0
  85. package/dist/payments/index.d.cts +187 -0
  86. package/dist/payments/index.d.ts +187 -0
  87. package/dist/payments/index.js +141 -0
  88. package/dist/payments.module-BdUq9ot_.d.cts +57 -0
  89. package/dist/payments.module-CQGv_VG7.d.ts +57 -0
  90. package/dist/plan-catalog-source-DWe-BGY1.d.cts +21 -0
  91. package/dist/plan-catalog-source-DWe-BGY1.d.ts +21 -0
  92. package/dist/{plan-resolution-Cgo_TR1H.d.cts → plan-resolution-CwUy_OqC.d.cts} +14 -0
  93. package/dist/{plan-resolution-Cgo_TR1H.d.ts → plan-resolution-CwUy_OqC.d.ts} +14 -0
  94. package/dist/{plan-versions.service-DChhbK6h.d.ts → plan-versions.service-C0N-Em2W.d.ts} +38 -64
  95. package/dist/{plan-versions.service-TPEtbN0r.d.cts → plan-versions.service-DARLh-qI.d.cts} +38 -64
  96. package/dist/platform/index.d.cts +52 -23
  97. package/dist/platform/index.d.ts +52 -23
  98. package/dist/platform/index.js +57 -36
  99. package/dist/promo/index.d.cts +23 -8
  100. package/dist/promo/index.d.ts +23 -8
  101. package/dist/promo/index.js +15 -7
  102. package/dist/{promo.module-DtvIycpt.d.cts → promo.module-CKkECmU8.d.cts} +9 -3
  103. package/dist/{promo.module-Z8h1PNX-.d.ts → promo.module-DuIJdK3U.d.ts} +9 -3
  104. package/dist/promo.service-BYBu6dy3.d.cts +215 -0
  105. package/dist/promo.service-CFjfF0Xm.d.ts +215 -0
  106. package/dist/registration/index.d.cts +104 -47
  107. package/dist/registration/index.d.ts +104 -47
  108. package/dist/registration/index.js +15 -9
  109. package/dist/subscriber/index.cjs +4 -0
  110. package/dist/subscriber/index.d.cts +28 -0
  111. package/dist/subscriber/index.d.ts +28 -0
  112. package/dist/subscriber/index.js +16 -0
  113. package/dist/subscriber.service-5W6Gi-1B.d.cts +68 -0
  114. package/dist/subscriber.service-5W6Gi-1B.d.ts +68 -0
  115. package/dist/subscription-contract/index.d.cts +4 -2
  116. package/dist/subscription-contract/index.d.ts +4 -2
  117. package/dist/subscription-contract/index.js +13 -5
  118. package/dist/{subscription-contract.module-fDFdQ0jm.d.ts → subscription-contract.module-BfIRpc1o.d.ts} +8 -2
  119. package/dist/{subscription-contract.module-CEK8HS5-.d.cts → subscription-contract.module-DTMuUJYd.d.cts} +8 -2
  120. package/dist/{subscription-contract.service-hD87MKyg.d.cts → subscription-contract.service-CPZrTM9C.d.ts} +32 -3
  121. package/dist/{subscription-contract.service-hD87MKyg.d.ts → subscription-contract.service-CfNApLuP.d.cts} +32 -3
  122. package/dist/tenant-billing.controller-BLqbsONe.d.ts +812 -0
  123. package/dist/tenant-billing.controller-DKbAqTbM.d.cts +812 -0
  124. package/dist/tenant-billing.module-ClbjzocC.d.cts +364 -0
  125. package/dist/tenant-billing.module-DohgJJ2m.d.ts +364 -0
  126. package/dist/tenant-billing.tokens-G-1xOlMr.d.cts +129 -0
  127. package/dist/tenant-billing.tokens-G-1xOlMr.d.ts +129 -0
  128. package/dist/testing/index.d.cts +44 -17
  129. package/dist/testing/index.d.ts +44 -17
  130. package/dist/testing/index.js +189 -40
  131. package/package.json +24 -4
  132. package/dist/catalog.module-BDDO6iwq.d.cts +0 -103
  133. package/dist/catalog.module-BTnMsE6u.d.ts +0 -103
  134. package/dist/checkout-offer.module-CMtiQJTT.d.ts +0 -39
  135. package/dist/checkout-offer.module-CVpWrzbe.d.cts +0 -39
  136. package/dist/checkout-offer.service-BLOv2HOo.d.cts +0 -49
  137. package/dist/checkout-offer.service-BLOv2HOo.d.ts +0 -49
  138. package/dist/chunk-57V6ZTI6.js +0 -22
  139. package/dist/chunk-BSK6YBLI.js +0 -87
  140. package/dist/chunk-DQKCK7DX.js +0 -217
  141. package/dist/chunk-VXEYLNIB.js +0 -632
  142. package/dist/chunk-WUDYIPYH.js +0 -715
  143. package/dist/define-saasicat-DROBe-b1.d.ts +0 -69
  144. package/dist/define-saasicat-vGBCkFys.d.cts +0 -69
  145. package/dist/promo.service-BJbKAmw3.d.cts +0 -112
  146. package/dist/promo.service-BJbKAmw3.d.ts +0 -112
  147. package/dist/tenant-billing.controller-BQ67mlmI.d.ts +0 -438
  148. package/dist/tenant-billing.controller-DS8kB8a7.d.cts +0 -438
  149. package/dist/tenant-billing.module-BznC3XtW.d.cts +0 -299
  150. package/dist/tenant-billing.module-wUbsQSFG.d.ts +0 -299
  151. /package/dist/{chunk-2FR6ZL7R.js → chunk-BHZOH2DY.js} +0 -0
  152. /package/dist/{chunk-2SLTRKXC.js → chunk-DFOW3JVO.js} +0 -0
  153. /package/dist/{chunk-DBZGV3HC.js → chunk-DU56UKEH.js} +0 -0
  154. /package/dist/{chunk-OYNHOY45.js → chunk-GAUEVIAE.js} +0 -0
@@ -1,9 +1,10 @@
1
- import { PromoCodeValueType, PromoCodeDurationType, BillingCycle, PromoCodeRepository, PromoCodeRedemptionRepository } from '@saasicat/core';
2
- import { i as PromoCodesService, f as PreviewResult } from '../promo.service-BJbKAmw3.js';
3
- export { C as CODE_MAX_LENGTH, a as CODE_MIN_LENGTH, b as CODE_PATTERN, c as PreviewInput, d as PreviewInvalid, e as PreviewReason, g as PreviewValid, h as PromoCodeStats, P as PromoServiceConfig, R as RedeemInput } from '../promo.service-BJbKAmw3.js';
1
+ import { PromoCodeValueType, PromoCodeDurationType, BillingCycle, PromoCodeRepository, PromoCodeRedemptionRepository, PromoCodeHoldRepository } from '@saasicat/core';
2
+ import { a as PromoCodesService, i as PreviewResult } from '../promo.service-CFjfF0Xm.js';
3
+ export { C as CODE_MAX_LENGTH, b as CODE_MIN_LENGTH, c as CODE_PATTERN, d as CheckoutHoldInput, e as PreviewInput, f as PreviewInvalid, g as PreviewOptions, h as PreviewReason, j as PreviewValid, k as PromoCodeStats, P as PromoServiceConfig, R as RedeemInput } from '../promo.service-CFjfF0Xm.js';
4
4
  export { P as PromoCodeRateLimitGuard, h as hashIp, i as ipFingerprint } from '../rate-limit.guard-dntqAlfZ.js';
5
- export { P as PromoCodesModule, a as PromoCodesModuleOptions } from '../promo.module-Z8h1PNX-.js';
5
+ export { a as PromoCodesModule, P as PromoCodesModuleOptions } from '../promo.module-DuIJdK3U.js';
6
6
  import { Type, CanActivate } from '@nestjs/common';
7
+ import '../plan-catalog-source-DWe-BGY1.js';
7
8
  import '../di-CcNeq9v-.js';
8
9
 
9
10
  /** Structural view of a PromoCode for the calculator functions.
@@ -80,20 +81,34 @@ interface PromoLabelOptions {
80
81
  declare function buildLabel(code: Pick<PromoCodeForCalc, 'valueType' | 'value' | 'durationType' | 'durationValue'>, cycle: BillingCycle, options?: PromoLabelOptions): string;
81
82
 
82
83
  declare function round2(n: number): number;
83
- /** Gross = net * (1 + vatRate/100). */
84
+ /**
85
+ * Whether a tax rate is one SaaSiCat accepts. Every tax rate in SaaSiCat is a
86
+ * percentage — 19 means 19 % — wherever it is stated: the settings, the
87
+ * catalogue, an offer, a contract, a contract line.
88
+ *
89
+ * A percentage lies from 0 to 100, and none lies strictly between 0 and 1:
90
+ * that is the shape of a fraction such as 0.19, and a fraction is refused
91
+ * rather than taken for a fraction of a per cent.
92
+ */
93
+ declare function isTaxRatePercent(rate: number): boolean;
94
+ /** Gross = net * (1 + vatRate/100), with `vatRate` a percentage. */
84
95
  declare function grossFromNet(net: number, vatRate: number): number;
85
- /** VAT included in the gross amount: gross * (vatRate / (100 + vatRate)). */
96
+ /** Net = gross * 100 / (100 + vatRate), with `vatRate` a percentage. */
97
+ declare function netFromGross(gross: number, vatRate: number): number;
98
+ /** VAT included in the gross amount: gross * vatRate / (100 + vatRate). */
86
99
  declare function computeIncludedVat(grossAmount: number, vatRate: number): number;
87
100
 
88
101
  declare class PromoCodeExpirer {
89
102
  private readonly promoRepo;
90
103
  private readonly redemptionRepo;
104
+ private readonly holds;
91
105
  private readonly logger;
92
- constructor(promoRepo: PromoCodeRepository, redemptionRepo: PromoCodeRedemptionRepository);
106
+ constructor(promoRepo: PromoCodeRepository, redemptionRepo: PromoCodeRedemptionRepository, holds?: PromoCodeHoldRepository | null);
93
107
  expirePromoCodes(): Promise<void>;
94
108
  }
95
109
 
96
110
  declare const PROMO_CODE_REPOSITORY_TOKEN: unique symbol;
111
+ declare const PROMO_CODE_HOLD_REPOSITORY_TOKEN: unique symbol;
97
112
  declare const PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN: unique symbol;
98
113
  declare const PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN: unique symbol;
99
114
  declare const PROMO_FIRST_TIME_CUSTOMER_CHECK_TOKEN: unique symbol;
@@ -166,4 +181,4 @@ declare class UpdatePromoCodeDto {
166
181
  revenueDeductionAccount?: string | null;
167
182
  }
168
183
 
169
- export { CreatePromoCodeDto, PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN, PROMO_CODE_REPOSITORY_TOKEN, PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN, PROMO_FIRST_TIME_CUSTOMER_CHECK_TOKEN, PROMO_REVENUE_DEDUCTION_AGGREGATOR_TOKEN, PROMO_SERVICE_CONFIG_TOKEN, PROMO_SUBSCRIPTION_LOOKUP_TOKEN, PROMO_TRANSACTION_RUNNER_TOKEN, PreviewPromoCodeDto, PreviewResult, PromoCodeExpirer, type PromoCodeForCalc, PromoCodePublicController, PromoCodesService, type PromoLabelOptions, UpdatePromoCodeDto, addCycles, buildLabel, buildPromoCodeAdminController, computeDiscountGross, computeDiscountedGross, computeIncludedVat, computeRegularStartsAt, grossFromNet, round2 };
184
+ export { CreatePromoCodeDto, PROMO_CODE_HOLD_REPOSITORY_TOKEN, PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN, PROMO_CODE_REPOSITORY_TOKEN, PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN, PROMO_FIRST_TIME_CUSTOMER_CHECK_TOKEN, PROMO_REVENUE_DEDUCTION_AGGREGATOR_TOKEN, PROMO_SERVICE_CONFIG_TOKEN, PROMO_SUBSCRIPTION_LOOKUP_TOKEN, PROMO_TRANSACTION_RUNNER_TOKEN, PreviewPromoCodeDto, PreviewResult, PromoCodeExpirer, type PromoCodeForCalc, PromoCodePublicController, PromoCodesService, type PromoLabelOptions, UpdatePromoCodeDto, addCycles, buildLabel, buildPromoCodeAdminController, computeDiscountGross, computeDiscountedGross, computeIncludedVat, computeRegularStartsAt, grossFromNet, isTaxRatePercent, netFromGross, round2 };
@@ -10,11 +10,13 @@ import {
10
10
  buildPromoCodeAdminController,
11
11
  hashIp,
12
12
  ipFingerprint
13
- } from "../chunk-TXC3LHHB.js";
13
+ } from "../chunk-4SDSYV4A.js";
14
+ import "../chunk-OOTEXP47.js";
14
15
  import {
15
16
  CODE_MAX_LENGTH,
16
17
  CODE_MIN_LENGTH,
17
18
  CODE_PATTERN,
19
+ PROMO_CODE_HOLD_REPOSITORY_TOKEN,
18
20
  PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN,
19
21
  PROMO_CODE_REPOSITORY_TOKEN,
20
22
  PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN,
@@ -29,22 +31,26 @@ import {
29
31
  computeDiscountGross,
30
32
  computeDiscountedGross,
31
33
  computeRegularStartsAt
32
- } from "../chunk-VXEYLNIB.js";
33
- import "../chunk-O2J2HDXA.js";
34
- import "../chunk-YSC46BGM.js";
34
+ } from "../chunk-3RLWML2S.js";
35
+ import "../chunk-TBBZWZQT.js";
35
36
  import {
36
37
  computeIncludedVat,
37
38
  grossFromNet,
39
+ isTaxRatePercent,
40
+ netFromGross,
38
41
  round2
39
- } from "../chunk-DQKCK7DX.js";
40
- import "../chunk-57V6ZTI6.js";
41
- import "../chunk-SABTXESR.js";
42
+ } from "../chunk-6PJE7EWO.js";
43
+ import "../chunk-SZ7RFPXA.js";
44
+ import "../chunk-YSC46BGM.js";
45
+ import "../chunk-FEQZCWUL.js";
46
+ import "../chunk-J7NJRK3K.js";
42
47
  import "../chunk-SHUYVCID.js";
43
48
  export {
44
49
  CODE_MAX_LENGTH,
45
50
  CODE_MIN_LENGTH,
46
51
  CODE_PATTERN,
47
52
  CreatePromoCodeDto,
53
+ PROMO_CODE_HOLD_REPOSITORY_TOKEN,
48
54
  PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN,
49
55
  PROMO_CODE_REPOSITORY_TOKEN,
50
56
  PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN,
@@ -70,5 +76,7 @@ export {
70
76
  grossFromNet,
71
77
  hashIp,
72
78
  ipFingerprint,
79
+ isTaxRatePercent,
80
+ netFromGross,
73
81
  round2
74
82
  };
@@ -1,7 +1,7 @@
1
1
  import { Type, CanActivate, DynamicModule, ForwardReference } from '@nestjs/common';
2
- import { PromoCodeRepository, PromoCodeRedemptionRepository, PromoCodeValidationLogRepository, FirstTimeCustomerCheck, PromoSubscriptionLookup, PromoRevenueDeductionAggregator, TransactionRunner } from '@saasicat/core';
2
+ import { PromoCodeRepository, PromoCodeRedemptionRepository, PromoCodeValidationLogRepository, FirstTimeCustomerCheck, PromoSubscriptionLookup, PromoRevenueDeductionAggregator, TransactionRunner, PromoCodeHoldRepository } from '@saasicat/core';
3
3
  import { P as ProviderSpec } from './di-CcNeq9v-.cjs';
4
- import { P as PromoServiceConfig } from './promo.service-BJbKAmw3.cjs';
4
+ import { P as PromoServiceConfig } from './promo.service-BYBu6dy3.cjs';
5
5
 
6
6
  interface PromoCodesModuleOptions {
7
7
  promoCodeRepository: ProviderSpec<PromoCodeRepository>;
@@ -11,6 +11,12 @@ interface PromoCodesModuleOptions {
11
11
  subscriptionLookup: ProviderSpec<PromoSubscriptionLookup>;
12
12
  revenueAggregator: ProviderSpec<PromoRevenueDeductionAggregator>;
13
13
  transactionRunner: ProviderSpec<TransactionRunner>;
14
+ /**
15
+ * The slots a code keeps for checkouts that have started. Left out, no
16
+ * checkout holds a slot, and a sign-up that asks for one is refused at
17
+ * start-up of the hold rather than holding nothing.
18
+ */
19
+ holdRepository?: ProviderSpec<PromoCodeHoldRepository>;
14
20
  config?: PromoServiceConfig;
15
21
  /**
16
22
  * Default `true`. Set to `false` if the consumer wants to disable the cron
@@ -36,4 +42,4 @@ declare class PromoCodesModule {
36
42
  static forRoot(options: PromoCodesModuleOptions): DynamicModule;
37
43
  }
38
44
 
39
- export { PromoCodesModule as P, type PromoCodesModuleOptions as a };
45
+ export { type PromoCodesModuleOptions as P, PromoCodesModule as a };
@@ -1,7 +1,7 @@
1
1
  import { Type, CanActivate, DynamicModule, ForwardReference } from '@nestjs/common';
2
- import { PromoCodeRepository, PromoCodeRedemptionRepository, PromoCodeValidationLogRepository, FirstTimeCustomerCheck, PromoSubscriptionLookup, PromoRevenueDeductionAggregator, TransactionRunner } from '@saasicat/core';
2
+ import { PromoCodeRepository, PromoCodeRedemptionRepository, PromoCodeValidationLogRepository, FirstTimeCustomerCheck, PromoSubscriptionLookup, PromoRevenueDeductionAggregator, TransactionRunner, PromoCodeHoldRepository } from '@saasicat/core';
3
3
  import { P as ProviderSpec } from './di-CcNeq9v-.js';
4
- import { P as PromoServiceConfig } from './promo.service-BJbKAmw3.js';
4
+ import { P as PromoServiceConfig } from './promo.service-CFjfF0Xm.js';
5
5
 
6
6
  interface PromoCodesModuleOptions {
7
7
  promoCodeRepository: ProviderSpec<PromoCodeRepository>;
@@ -11,6 +11,12 @@ interface PromoCodesModuleOptions {
11
11
  subscriptionLookup: ProviderSpec<PromoSubscriptionLookup>;
12
12
  revenueAggregator: ProviderSpec<PromoRevenueDeductionAggregator>;
13
13
  transactionRunner: ProviderSpec<TransactionRunner>;
14
+ /**
15
+ * The slots a code keeps for checkouts that have started. Left out, no
16
+ * checkout holds a slot, and a sign-up that asks for one is refused at
17
+ * start-up of the hold rather than holding nothing.
18
+ */
19
+ holdRepository?: ProviderSpec<PromoCodeHoldRepository>;
14
20
  config?: PromoServiceConfig;
15
21
  /**
16
22
  * Default `true`. Set to `false` if the consumer wants to disable the cron
@@ -36,4 +42,4 @@ declare class PromoCodesModule {
36
42
  static forRoot(options: PromoCodesModuleOptions): DynamicModule;
37
43
  }
38
44
 
39
- export { PromoCodesModule as P, type PromoCodesModuleOptions as a };
45
+ export { type PromoCodesModuleOptions as P, PromoCodesModule as a };
@@ -0,0 +1,215 @@
1
+ import { PromoCodeRepository, PromoCodeRedemptionRepository, PromoCodeValidationLogRepository, FirstTimeCustomerCheck, PromoSubscriptionLookup, PromoRevenueDeductionAggregator, TransactionRunner, PromoCodeHoldRepository, CreatePromoCodeData, PromoCodeRecord, UpdatePromoCodeData, PromoCodeFilter, PromoCodeRedemptionListItem, BillingCycle, PromoPreviewInvalidReason, TransactionContext, PromoCodeRedemptionRecord } from '@saasicat/core';
2
+ import { P as PlanCatalogSource } from './plan-catalog-source-DWe-BGY1.cjs';
3
+
4
+ declare const CODE_MIN_LENGTH = 4;
5
+ declare const CODE_MAX_LENGTH = 32;
6
+ declare const CODE_PATTERN: RegExp;
7
+ type PreviewReason = PromoPreviewInvalidReason;
8
+ type PreviewInvalid = {
9
+ valid: false;
10
+ reason: PreviewReason;
11
+ };
12
+ interface PreviewValid {
13
+ valid: true;
14
+ code: string;
15
+ label: string;
16
+ discount: {
17
+ valueType: PromoCodeRecord['valueType'];
18
+ value: string;
19
+ durationType: PromoCodeRecord['durationType'];
20
+ durationValue: number | null;
21
+ };
22
+ price: {
23
+ originalGross: string;
24
+ discountGross: string;
25
+ discountNet: string;
26
+ discountedGross: string;
27
+ includedVat: string;
28
+ nextRegularAmountGross: string;
29
+ regularStartsAt: string | null;
30
+ };
31
+ }
32
+ type PreviewResult = PreviewValid | PreviewInvalid;
33
+ interface PreviewInput {
34
+ code: string;
35
+ planId: string;
36
+ billingCycle: BillingCycle;
37
+ /** For the firstTimeCustomersOnly check. */
38
+ email?: string;
39
+ ipHash?: string;
40
+ sessionId?: string;
41
+ }
42
+ interface PreviewOptions {
43
+ /**
44
+ * The checkout offer the code is priced for. A live slot that offer holds
45
+ * is its own and is not counted against it.
46
+ */
47
+ checkoutOfferId?: string;
48
+ /**
49
+ * The offer is priced as it is concluded: its live slot also keeps the
50
+ * code's state as it was when the slot was taken, so a code paused or past
51
+ * its validity since is still accepted for the checkout that holds it.
52
+ */
53
+ concluding?: boolean;
54
+ }
55
+ interface RedeemInput {
56
+ code: string;
57
+ subscriptionId: string;
58
+ tenantId: string;
59
+ /** For the firstTimeCustomersOnly check in the final redeem path. */
60
+ email?: string;
61
+ }
62
+ /** A slot of a code to hold for a checkout. */
63
+ interface CheckoutHoldInput {
64
+ /** The checkout offer the slot is held for; it holds one at most. */
65
+ checkoutOfferId: string;
66
+ code: string;
67
+ planId: string;
68
+ billingCycle: BillingCycle;
69
+ /** For the firstTimeCustomersOnly check. */
70
+ email?: string;
71
+ /** When the checkout expires, and with it the hold. */
72
+ until: Date;
73
+ }
74
+ interface PromoServiceConfig {
75
+ /** Plans that are not discountable (e.g. 'ENTERPRISE'). */
76
+ nonRedeemablePlans?: readonly string[];
77
+ }
78
+ interface PromoCodeStats {
79
+ code: PromoCodeRecord;
80
+ validations: number;
81
+ redemptions: {
82
+ active: number;
83
+ total: number;
84
+ reversed: number;
85
+ expired: number;
86
+ };
87
+ /** Slots held for checkouts that have not concluded, which no one else can take. */
88
+ held: number;
89
+ /** Decimal-as-string ('0.00' if no aggregator is available). */
90
+ revenueDeductionGross: string;
91
+ }
92
+ declare class PromoCodesService {
93
+ private readonly promoRepo;
94
+ private readonly redemptionRepo;
95
+ private readonly validationLogRepo;
96
+ private readonly firstTimeCheck;
97
+ private readonly subscriptionLookup;
98
+ private readonly revenueAggregator;
99
+ private readonly transactionRunner;
100
+ private readonly planCatalogs;
101
+ private readonly config;
102
+ private readonly holds;
103
+ constructor(promoRepo: PromoCodeRepository, redemptionRepo: PromoCodeRedemptionRepository, validationLogRepo: PromoCodeValidationLogRepository, firstTimeCheck: FirstTimeCustomerCheck, subscriptionLookup: PromoSubscriptionLookup, revenueAggregator: PromoRevenueDeductionAggregator, transactionRunner: TransactionRunner, planCatalogs: PlanCatalogSource, config: PromoServiceConfig, holds?: PromoCodeHoldRepository | null);
104
+ create(input: CreatePromoCodeData): Promise<PromoCodeRecord>;
105
+ /**
106
+ * Changes a code under the rules a new one is held to, asking the rules the
107
+ * named fields bear on: the terms as they stand after the change have to be
108
+ * ones `create` would accept. Pausing alone is always possible.
109
+ */
110
+ update(id: string, input: UpdatePromoCodeData): Promise<PromoCodeRecord>;
111
+ softDelete(id: string): Promise<void>;
112
+ findAll(filter?: PromoCodeFilter): Promise<PromoCodeRecord[]>;
113
+ findOne(id: string): Promise<PromoCodeRecord>;
114
+ stats(id: string): Promise<PromoCodeStats>;
115
+ listRedemptions(promoCodeId: string): Promise<PromoCodeRedemptionListItem[]>;
116
+ preview(input: PreviewInput, options?: PreviewOptions): Promise<PreviewResult>;
117
+ /**
118
+ * Holds a slot of the code for a checkout offer until `until`, after every
119
+ * check a preview makes — so a customer who reaches the payment form keeps
120
+ * the code however many others redeem it meanwhile. Starting the same
121
+ * checkout again moves the expiry of the slot it holds rather than taking a
122
+ * second — later, never earlier (`PromoCodeHoldRepository.extend`); a
123
+ * checkout that held another code gives that one back.
124
+ *
125
+ * Refused with `PROMO_CODE_NOT_REDEEMABLE` and the reason a preview would
126
+ * give, `EXHAUSTED` when every slot is redeemed or held — also when the
127
+ * code changed between that check and taking the slot. Nothing is held
128
+ * then, and a slot the offer held before stays with it until it expires.
129
+ */
130
+ holdForCheckout(input: CheckoutHoldInput): Promise<void>;
131
+ /** Gives back the slot a checkout offer holds, if it holds one. */
132
+ releaseCheckoutHold(checkoutOfferId: string, tx?: TransactionContext): Promise<void>;
133
+ /**
134
+ * Gives back the slot a checkout offer holds only while it still expires at
135
+ * `expiresAt` — the hold as the caller wrote it. A slot another start of the
136
+ * checkout moved since stays with the form that start opened.
137
+ */
138
+ releaseCheckoutHoldIfUnmoved(checkoutOfferId: string, expiresAt: Date): Promise<void>;
139
+ /**
140
+ * Hands the offer's live hold to the redemption that runs on `tx`: redeeming
141
+ * the code there takes the held slot instead of a free one, whatever
142
+ * happened to the code since the hold was taken. The caller releases it
143
+ * with `releaseCheckoutHold` on the same transaction once the redemption
144
+ * had its chance — a hold the redemption did not take is not held any more.
145
+ * False when the offer holds no live slot.
146
+ */
147
+ handOverCheckoutHold(checkoutOfferId: string, tx: TransactionContext): Promise<boolean>;
148
+ /**
149
+ * Wraps `redeemInTransaction` in its own transaction-runner call —
150
+ * the default path when the caller has no external tx context
151
+ * (e.g. POST /billing/promo/redeem as a stand-alone endpoint).
152
+ */
153
+ redeem(input: RedeemInput): Promise<PromoCodeRedemptionRecord>;
154
+ /**
155
+ * Redeems a promo code within an EXTERNAL transaction — the caller
156
+ * (typically `TenantSubscriptionWritePort.applyOnboardingSelection`)
157
+ * already has `prisma.$transaction(...)` open and passes the `tx`
158
+ * context through. This lands plan change, add-on insert, and redemption
159
+ * insert in a single DB transaction (P10.1.1).
160
+ *
161
+ * A checkout that held a slot of the code, and whose conclusion handed it
162
+ * over on this transaction, is redeemed on that slot: its state is not
163
+ * asked again, and no free slot is taken. Otherwise a free one is claimed.
164
+ * Either way the redemption is refused where a preview would refuse on the
165
+ * price — an invoice of zero the code does not allow — and it records at
166
+ * most the price it is redeemed against.
167
+ */
168
+ redeemInTransaction(input: RedeemInput, tx: TransactionContext): Promise<PromoCodeRedemptionRecord>;
169
+ reverse(subscriptionId: string): Promise<PromoCodeRedemptionRecord | null>;
170
+ /**
171
+ * Why a code does not apply to a plan, or what it takes off it. The plans
172
+ * are read only once the code itself has passed, so somebody trying codes
173
+ * that do not exist costs no read of the plan tables.
174
+ */
175
+ private judge;
176
+ /** Everything about a code that needs no plan price: its state, its slots, and the plans it fits. */
177
+ private checkCode;
178
+ /** Whether the code can be used now at all: its status and its validity window. */
179
+ private checkState;
180
+ /** Whether the plan is sold at a price in this rhythm, and one the code's minimum allows. */
181
+ private checkPlanPrice;
182
+ private checkFirstTimeCustomer;
183
+ /**
184
+ * Lazy expiry: sets codes whose validUntil has passed to EXPIRED.
185
+ * Called before every find/preview — defense-in-depth alongside the cron.
186
+ */
187
+ private lazyExpire;
188
+ /**
189
+ * The code with the slots of its expired holds given back, so that what
190
+ * it counts as held is what is held now. One code at a time: this runs on
191
+ * every preview, and a sweep of one code locks one row.
192
+ */
193
+ private findWithLiveHolds;
194
+ /**
195
+ * Why a code the checks passed a moment ago had no slot to take: it may
196
+ * have been paused, deleted or run past its validity in between, and a
197
+ * refusal that says "exhausted" for any of them misleads the customer and
198
+ * the log a support answer is built on.
199
+ */
200
+ private whyNoSlot;
201
+ /** Whether the checkout offer holds a slot of this code that has not expired. */
202
+ private holdsLiveSlot;
203
+ /** The slots of a code held right now, its expired holds given back first. */
204
+ private liveHeldCount;
205
+ private requireHolds;
206
+ private ruleContext;
207
+ /**
208
+ * Lowest applicable plan price. With a whitelist it takes the minimum
209
+ * from the whitelist, otherwise across all marketed plans of the catalog
210
+ * (except non-redeemable).
211
+ */
212
+ private lowestApplicablePlanGross;
213
+ }
214
+
215
+ export { CODE_MAX_LENGTH as C, type PromoServiceConfig as P, type RedeemInput as R, PromoCodesService as a, CODE_MIN_LENGTH as b, CODE_PATTERN as c, type CheckoutHoldInput as d, type PreviewInput as e, type PreviewInvalid as f, type PreviewOptions as g, type PreviewReason as h, type PreviewResult as i, type PreviewValid as j, type PromoCodeStats as k };
@@ -0,0 +1,215 @@
1
+ import { PromoCodeRepository, PromoCodeRedemptionRepository, PromoCodeValidationLogRepository, FirstTimeCustomerCheck, PromoSubscriptionLookup, PromoRevenueDeductionAggregator, TransactionRunner, PromoCodeHoldRepository, CreatePromoCodeData, PromoCodeRecord, UpdatePromoCodeData, PromoCodeFilter, PromoCodeRedemptionListItem, BillingCycle, PromoPreviewInvalidReason, TransactionContext, PromoCodeRedemptionRecord } from '@saasicat/core';
2
+ import { P as PlanCatalogSource } from './plan-catalog-source-DWe-BGY1.js';
3
+
4
+ declare const CODE_MIN_LENGTH = 4;
5
+ declare const CODE_MAX_LENGTH = 32;
6
+ declare const CODE_PATTERN: RegExp;
7
+ type PreviewReason = PromoPreviewInvalidReason;
8
+ type PreviewInvalid = {
9
+ valid: false;
10
+ reason: PreviewReason;
11
+ };
12
+ interface PreviewValid {
13
+ valid: true;
14
+ code: string;
15
+ label: string;
16
+ discount: {
17
+ valueType: PromoCodeRecord['valueType'];
18
+ value: string;
19
+ durationType: PromoCodeRecord['durationType'];
20
+ durationValue: number | null;
21
+ };
22
+ price: {
23
+ originalGross: string;
24
+ discountGross: string;
25
+ discountNet: string;
26
+ discountedGross: string;
27
+ includedVat: string;
28
+ nextRegularAmountGross: string;
29
+ regularStartsAt: string | null;
30
+ };
31
+ }
32
+ type PreviewResult = PreviewValid | PreviewInvalid;
33
+ interface PreviewInput {
34
+ code: string;
35
+ planId: string;
36
+ billingCycle: BillingCycle;
37
+ /** For the firstTimeCustomersOnly check. */
38
+ email?: string;
39
+ ipHash?: string;
40
+ sessionId?: string;
41
+ }
42
+ interface PreviewOptions {
43
+ /**
44
+ * The checkout offer the code is priced for. A live slot that offer holds
45
+ * is its own and is not counted against it.
46
+ */
47
+ checkoutOfferId?: string;
48
+ /**
49
+ * The offer is priced as it is concluded: its live slot also keeps the
50
+ * code's state as it was when the slot was taken, so a code paused or past
51
+ * its validity since is still accepted for the checkout that holds it.
52
+ */
53
+ concluding?: boolean;
54
+ }
55
+ interface RedeemInput {
56
+ code: string;
57
+ subscriptionId: string;
58
+ tenantId: string;
59
+ /** For the firstTimeCustomersOnly check in the final redeem path. */
60
+ email?: string;
61
+ }
62
+ /** A slot of a code to hold for a checkout. */
63
+ interface CheckoutHoldInput {
64
+ /** The checkout offer the slot is held for; it holds one at most. */
65
+ checkoutOfferId: string;
66
+ code: string;
67
+ planId: string;
68
+ billingCycle: BillingCycle;
69
+ /** For the firstTimeCustomersOnly check. */
70
+ email?: string;
71
+ /** When the checkout expires, and with it the hold. */
72
+ until: Date;
73
+ }
74
+ interface PromoServiceConfig {
75
+ /** Plans that are not discountable (e.g. 'ENTERPRISE'). */
76
+ nonRedeemablePlans?: readonly string[];
77
+ }
78
+ interface PromoCodeStats {
79
+ code: PromoCodeRecord;
80
+ validations: number;
81
+ redemptions: {
82
+ active: number;
83
+ total: number;
84
+ reversed: number;
85
+ expired: number;
86
+ };
87
+ /** Slots held for checkouts that have not concluded, which no one else can take. */
88
+ held: number;
89
+ /** Decimal-as-string ('0.00' if no aggregator is available). */
90
+ revenueDeductionGross: string;
91
+ }
92
+ declare class PromoCodesService {
93
+ private readonly promoRepo;
94
+ private readonly redemptionRepo;
95
+ private readonly validationLogRepo;
96
+ private readonly firstTimeCheck;
97
+ private readonly subscriptionLookup;
98
+ private readonly revenueAggregator;
99
+ private readonly transactionRunner;
100
+ private readonly planCatalogs;
101
+ private readonly config;
102
+ private readonly holds;
103
+ constructor(promoRepo: PromoCodeRepository, redemptionRepo: PromoCodeRedemptionRepository, validationLogRepo: PromoCodeValidationLogRepository, firstTimeCheck: FirstTimeCustomerCheck, subscriptionLookup: PromoSubscriptionLookup, revenueAggregator: PromoRevenueDeductionAggregator, transactionRunner: TransactionRunner, planCatalogs: PlanCatalogSource, config: PromoServiceConfig, holds?: PromoCodeHoldRepository | null);
104
+ create(input: CreatePromoCodeData): Promise<PromoCodeRecord>;
105
+ /**
106
+ * Changes a code under the rules a new one is held to, asking the rules the
107
+ * named fields bear on: the terms as they stand after the change have to be
108
+ * ones `create` would accept. Pausing alone is always possible.
109
+ */
110
+ update(id: string, input: UpdatePromoCodeData): Promise<PromoCodeRecord>;
111
+ softDelete(id: string): Promise<void>;
112
+ findAll(filter?: PromoCodeFilter): Promise<PromoCodeRecord[]>;
113
+ findOne(id: string): Promise<PromoCodeRecord>;
114
+ stats(id: string): Promise<PromoCodeStats>;
115
+ listRedemptions(promoCodeId: string): Promise<PromoCodeRedemptionListItem[]>;
116
+ preview(input: PreviewInput, options?: PreviewOptions): Promise<PreviewResult>;
117
+ /**
118
+ * Holds a slot of the code for a checkout offer until `until`, after every
119
+ * check a preview makes — so a customer who reaches the payment form keeps
120
+ * the code however many others redeem it meanwhile. Starting the same
121
+ * checkout again moves the expiry of the slot it holds rather than taking a
122
+ * second — later, never earlier (`PromoCodeHoldRepository.extend`); a
123
+ * checkout that held another code gives that one back.
124
+ *
125
+ * Refused with `PROMO_CODE_NOT_REDEEMABLE` and the reason a preview would
126
+ * give, `EXHAUSTED` when every slot is redeemed or held — also when the
127
+ * code changed between that check and taking the slot. Nothing is held
128
+ * then, and a slot the offer held before stays with it until it expires.
129
+ */
130
+ holdForCheckout(input: CheckoutHoldInput): Promise<void>;
131
+ /** Gives back the slot a checkout offer holds, if it holds one. */
132
+ releaseCheckoutHold(checkoutOfferId: string, tx?: TransactionContext): Promise<void>;
133
+ /**
134
+ * Gives back the slot a checkout offer holds only while it still expires at
135
+ * `expiresAt` — the hold as the caller wrote it. A slot another start of the
136
+ * checkout moved since stays with the form that start opened.
137
+ */
138
+ releaseCheckoutHoldIfUnmoved(checkoutOfferId: string, expiresAt: Date): Promise<void>;
139
+ /**
140
+ * Hands the offer's live hold to the redemption that runs on `tx`: redeeming
141
+ * the code there takes the held slot instead of a free one, whatever
142
+ * happened to the code since the hold was taken. The caller releases it
143
+ * with `releaseCheckoutHold` on the same transaction once the redemption
144
+ * had its chance — a hold the redemption did not take is not held any more.
145
+ * False when the offer holds no live slot.
146
+ */
147
+ handOverCheckoutHold(checkoutOfferId: string, tx: TransactionContext): Promise<boolean>;
148
+ /**
149
+ * Wraps `redeemInTransaction` in its own transaction-runner call —
150
+ * the default path when the caller has no external tx context
151
+ * (e.g. POST /billing/promo/redeem as a stand-alone endpoint).
152
+ */
153
+ redeem(input: RedeemInput): Promise<PromoCodeRedemptionRecord>;
154
+ /**
155
+ * Redeems a promo code within an EXTERNAL transaction — the caller
156
+ * (typically `TenantSubscriptionWritePort.applyOnboardingSelection`)
157
+ * already has `prisma.$transaction(...)` open and passes the `tx`
158
+ * context through. This lands plan change, add-on insert, and redemption
159
+ * insert in a single DB transaction (P10.1.1).
160
+ *
161
+ * A checkout that held a slot of the code, and whose conclusion handed it
162
+ * over on this transaction, is redeemed on that slot: its state is not
163
+ * asked again, and no free slot is taken. Otherwise a free one is claimed.
164
+ * Either way the redemption is refused where a preview would refuse on the
165
+ * price — an invoice of zero the code does not allow — and it records at
166
+ * most the price it is redeemed against.
167
+ */
168
+ redeemInTransaction(input: RedeemInput, tx: TransactionContext): Promise<PromoCodeRedemptionRecord>;
169
+ reverse(subscriptionId: string): Promise<PromoCodeRedemptionRecord | null>;
170
+ /**
171
+ * Why a code does not apply to a plan, or what it takes off it. The plans
172
+ * are read only once the code itself has passed, so somebody trying codes
173
+ * that do not exist costs no read of the plan tables.
174
+ */
175
+ private judge;
176
+ /** Everything about a code that needs no plan price: its state, its slots, and the plans it fits. */
177
+ private checkCode;
178
+ /** Whether the code can be used now at all: its status and its validity window. */
179
+ private checkState;
180
+ /** Whether the plan is sold at a price in this rhythm, and one the code's minimum allows. */
181
+ private checkPlanPrice;
182
+ private checkFirstTimeCustomer;
183
+ /**
184
+ * Lazy expiry: sets codes whose validUntil has passed to EXPIRED.
185
+ * Called before every find/preview — defense-in-depth alongside the cron.
186
+ */
187
+ private lazyExpire;
188
+ /**
189
+ * The code with the slots of its expired holds given back, so that what
190
+ * it counts as held is what is held now. One code at a time: this runs on
191
+ * every preview, and a sweep of one code locks one row.
192
+ */
193
+ private findWithLiveHolds;
194
+ /**
195
+ * Why a code the checks passed a moment ago had no slot to take: it may
196
+ * have been paused, deleted or run past its validity in between, and a
197
+ * refusal that says "exhausted" for any of them misleads the customer and
198
+ * the log a support answer is built on.
199
+ */
200
+ private whyNoSlot;
201
+ /** Whether the checkout offer holds a slot of this code that has not expired. */
202
+ private holdsLiveSlot;
203
+ /** The slots of a code held right now, its expired holds given back first. */
204
+ private liveHeldCount;
205
+ private requireHolds;
206
+ private ruleContext;
207
+ /**
208
+ * Lowest applicable plan price. With a whitelist it takes the minimum
209
+ * from the whitelist, otherwise across all marketed plans of the catalog
210
+ * (except non-redeemable).
211
+ */
212
+ private lowestApplicablePlanGross;
213
+ }
214
+
215
+ export { CODE_MAX_LENGTH as C, type PromoServiceConfig as P, type RedeemInput as R, PromoCodesService as a, CODE_MIN_LENGTH as b, CODE_PATTERN as c, type CheckoutHoldInput as d, type PreviewInput as e, type PreviewInvalid as f, type PreviewOptions as g, type PreviewReason as h, type PreviewResult as i, type PreviewValid as j, type PromoCodeStats as k };