@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,6 +1,6 @@
1
1
  import {
2
2
  DiscoveryScanner
3
- } from "./chunk-WXYJHZCN.js";
3
+ } from "./chunk-JVAEKTJ4.js";
4
4
  import {
5
5
  DEFINES_QUOTA_KEY,
6
6
  DISCOVERY_SNAPSHOT_TOKEN,
@@ -13,6 +13,7 @@ import { mkdirSync, writeFileSync } from "fs";
13
13
  import { dirname } from "path";
14
14
  import { Inject, Injectable, Logger, Optional } from "@nestjs/common";
15
15
  import { DiscoveryService, MetadataScanner, Reflector } from "@nestjs/core";
16
+ import { canonicalJson } from "@saasicat/core";
16
17
  function _ts_decorate(decorators, target, key, desc) {
17
18
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
18
19
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -288,23 +289,10 @@ function computeSnapshotHash(snapshot) {
288
289
  features: snapshot.features,
289
290
  quotas: snapshot.quotas
290
291
  };
291
- const json = canonicalStringify(stableInput);
292
+ const json = canonicalJson(stableInput);
292
293
  return `sha256-${createHash("sha256").update(json).digest("hex")}`;
293
294
  }
294
295
  __name(computeSnapshotHash, "computeSnapshotHash");
295
- function canonicalStringify(value) {
296
- return JSON.stringify(value, (_key, val) => {
297
- if (val && typeof val === "object" && !Array.isArray(val)) {
298
- const sorted = {};
299
- for (const k of Object.keys(val).sort()) {
300
- sorted[k] = val[k];
301
- }
302
- return sorted;
303
- }
304
- return val;
305
- });
306
- }
307
- __name(canonicalStringify, "canonicalStringify");
308
296
 
309
297
  export {
310
298
  DISCOVERY_APP_INFO_TOKEN,
@@ -0,0 +1,26 @@
1
+ import {
2
+ __name
3
+ } from "./chunk-SHUYVCID.js";
4
+
5
+ // src/billing/bundle-price.ts
6
+ function resolveBundlePriceNet(bundleVersion, planKey, billingCycle) {
7
+ const override = (bundleVersion.pricingOverrides ?? []).find((o) => o.planId === planKey);
8
+ const yearly = billingCycle === "YEARLY";
9
+ const raw = yearly ? override?.yearlyNet !== void 0 ? override.yearlyNet : bundleVersion.yearlyNet : override?.monthlyNet !== void 0 ? override.monthlyNet : bundleVersion.monthlyNet;
10
+ if (raw === null || raw === void 0) return null;
11
+ const parsed = Number.parseFloat(raw);
12
+ return Number.isFinite(parsed) ? parsed : null;
13
+ }
14
+ __name(resolveBundlePriceNet, "resolveBundlePriceNet");
15
+ function cyclesSoldFor(planVersion) {
16
+ const cycles = [];
17
+ if (planVersion.monthlyNet != null) cycles.push("MONTHLY");
18
+ if (planVersion.yearlyNet != null) cycles.push("YEARLY");
19
+ return cycles;
20
+ }
21
+ __name(cyclesSoldFor, "cyclesSoldFor");
22
+
23
+ export {
24
+ resolveBundlePriceNet,
25
+ cyclesSoldFor
26
+ };
@@ -0,0 +1,301 @@
1
+ import {
2
+ PLAN_CATALOG_SETTINGS_TOKEN
3
+ } from "./chunk-FEQZCWUL.js";
4
+ import {
5
+ codedError
6
+ } from "./chunk-J7NJRK3K.js";
7
+ import {
8
+ __name
9
+ } from "./chunk-SHUYVCID.js";
10
+
11
+ // src/subscriber/subscriber.tokens.ts
12
+ var SUBSCRIBER_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriberRepository");
13
+
14
+ // src/subscriber/subscriber.service.ts
15
+ import { ConflictException, Inject, Injectable, NotFoundException, UnprocessableEntityException as UnprocessableEntityException2 } from "@nestjs/common";
16
+ import { SUBSCRIBER_ERROR_CODES as SUBSCRIBER_ERROR_CODES2, contractPartiesOf } from "@saasicat/core";
17
+
18
+ // src/subscriber/subscriber-details.ts
19
+ import { UnprocessableEntityException } from "@nestjs/common";
20
+ import { SUBSCRIBER_ERROR_CODES, LEGAL_IDENTITY_FIELDS } from "@saasicat/core";
21
+ var COUNTRY_CODE = /^[A-Z]{2}$/;
22
+ var MAX_EMAIL_LENGTH = 254;
23
+ var INVOICE_ADDRESS_FIELDS = [
24
+ "addressLine1",
25
+ "postalCode",
26
+ "city",
27
+ "country"
28
+ ];
29
+ var CONTACT_FIELDS = [
30
+ "addressLine1",
31
+ "addressLine2",
32
+ "postalCode",
33
+ "city",
34
+ "country",
35
+ "invoiceEmail"
36
+ ];
37
+ function settleNewSubscriberDetails(details) {
38
+ return {
39
+ legalName: settleLegalName(details.legalName),
40
+ vatId: settleText("vatId", details.vatId),
41
+ taxNumber: settleText("taxNumber", details.taxNumber),
42
+ ...settleContact(details, CONTACT_FIELDS)
43
+ };
44
+ }
45
+ __name(settleNewSubscriberDetails, "settleNewSubscriberDetails");
46
+ function settleContactChange(change) {
47
+ const identity = LEGAL_IDENTITY_FIELDS.find((field) => change[field] !== void 0);
48
+ if (identity) {
49
+ throw new UnprocessableEntityException(codedError(SUBSCRIBER_ERROR_CODES.SUBSCRIBER_IDENTITY_NOT_A_CONTACT, {
50
+ field: identity
51
+ }));
52
+ }
53
+ const named = CONTACT_FIELDS.filter((field) => change[field] !== void 0);
54
+ return settleContact(change, named);
55
+ }
56
+ __name(settleContactChange, "settleContactChange");
57
+ function settleIdentityCorrection(correction) {
58
+ const values = {};
59
+ for (const field of LEGAL_IDENTITY_FIELDS) {
60
+ if (correction[field] === void 0) continue;
61
+ values[field] = settleIdentityValue(field, correction[field]);
62
+ }
63
+ return values;
64
+ }
65
+ __name(settleIdentityCorrection, "settleIdentityCorrection");
66
+ function settleIdentityValue(field, value) {
67
+ return field === "legalName" ? settleLegalName(value) : settleText(field, value);
68
+ }
69
+ __name(settleIdentityValue, "settleIdentityValue");
70
+ function settleLegalName(value) {
71
+ const legalName = settleText("legalName", value);
72
+ if (legalName === null) {
73
+ throw new UnprocessableEntityException(codedError(SUBSCRIBER_ERROR_CODES.SUBSCRIBER_LEGAL_NAME_REQUIRED));
74
+ }
75
+ return legalName;
76
+ }
77
+ __name(settleLegalName, "settleLegalName");
78
+ function settleContact(source, fields) {
79
+ const contact = {};
80
+ for (const field of fields) {
81
+ contact[field] = settleContactValue(field, source[field]);
82
+ }
83
+ return contact;
84
+ }
85
+ __name(settleContact, "settleContact");
86
+ function settleContactValue(field, value) {
87
+ const text = settleText(field, value);
88
+ if (text === null) return null;
89
+ if (field === "country") {
90
+ const country = text.toUpperCase();
91
+ if (!COUNTRY_CODE.test(country)) throw invalid(field);
92
+ return country;
93
+ }
94
+ if (field === "invoiceEmail" && !isEmailShaped(text)) throw invalid(field);
95
+ return text;
96
+ }
97
+ __name(settleContactValue, "settleContactValue");
98
+ function settleText(field, value) {
99
+ if (value === void 0 || value === null) return null;
100
+ if (typeof value !== "string") throw invalid(field);
101
+ const trimmed = value.trim();
102
+ return trimmed === "" ? null : trimmed;
103
+ }
104
+ __name(settleText, "settleText");
105
+ function isEmailShaped(value) {
106
+ if (value.length > MAX_EMAIL_LENGTH) return false;
107
+ const at = value.indexOf("@");
108
+ if (at <= 0 || at !== value.lastIndexOf("@")) return false;
109
+ const domain = value.slice(at + 1);
110
+ const dot = domain.lastIndexOf(".");
111
+ if (dot <= 0 || dot === domain.length - 1) return false;
112
+ return !/\s/.test(value);
113
+ }
114
+ __name(isEmailShaped, "isEmailShaped");
115
+ function invalid(field) {
116
+ return new UnprocessableEntityException(codedError(SUBSCRIBER_ERROR_CODES.SUBSCRIBER_DETAIL_INVALID, {
117
+ field
118
+ }));
119
+ }
120
+ __name(invalid, "invalid");
121
+
122
+ // src/subscriber/subscriber.service.ts
123
+ function _ts_decorate(decorators, target, key, desc) {
124
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
125
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
126
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
127
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
128
+ }
129
+ __name(_ts_decorate, "_ts_decorate");
130
+ function _ts_metadata(k, v) {
131
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
132
+ }
133
+ __name(_ts_metadata, "_ts_metadata");
134
+ function _ts_param(paramIndex, decorator) {
135
+ return function(target, key) {
136
+ decorator(target, key, paramIndex);
137
+ };
138
+ }
139
+ __name(_ts_param, "_ts_param");
140
+ var KEPT_BY_A_TENANT = [
141
+ ...INVOICE_ADDRESS_FIELDS,
142
+ "invoiceEmail"
143
+ ];
144
+ var SubscriberService = class {
145
+ static {
146
+ __name(this, "SubscriberService");
147
+ }
148
+ repo;
149
+ settings;
150
+ constructor(repo, settings) {
151
+ this.repo = repo;
152
+ this.settings = settings;
153
+ }
154
+ /**
155
+ * Creates the tenant's subscriber and assigns its customer number, behind
156
+ * the prefix `config/saas.yaml` names. With `tx` it is written on that
157
+ * transaction and undone with it — pass the one the tenant is created on.
158
+ *
159
+ * Refused with `SUBSCRIBER_ALREADY_EXISTS` when the tenant has one: a second
160
+ * party for the same tenant is not a correction of the first.
161
+ */
162
+ async createForTenant(tenantId, details, tx) {
163
+ const settled = settleNewSubscriberDetails(details);
164
+ const created = await this.repo.createForTenant({
165
+ ...settled,
166
+ tenantId,
167
+ customerNumberPrefix: this.settings.subscribers?.customerNumberPrefix ?? ""
168
+ }, tx);
169
+ if (!created) {
170
+ throw new ConflictException(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_ALREADY_EXISTS, {
171
+ tenantId
172
+ }));
173
+ }
174
+ return created;
175
+ }
176
+ /** The tenant's subscriber, or `null` when it has none. */
177
+ findByTenantId(tenantId, tx) {
178
+ return this.repo.findByTenantId(tenantId, tx);
179
+ }
180
+ /** The tenant's subscriber, refused with `SUBSCRIBER_REQUIRED` when it has none. */
181
+ async requireForTenant(tenantId, tx) {
182
+ const subscriber = await this.repo.findByTenantId(tenantId, tx);
183
+ if (!subscriber) throw subscriberRequired(tenantId);
184
+ return subscriber;
185
+ }
186
+ /**
187
+ * Who a contract concluded for this tenant now is between: its subscriber
188
+ * as the record stands, and the issuer as the running configuration names
189
+ * it. Refused with `SUBSCRIBER_REQUIRED` when the tenant has no subscriber.
190
+ */
191
+ async contractPartiesFor(tenantId, tx) {
192
+ const subscriber = await this.requireForTenant(tenantId, tx);
193
+ return contractPartiesOf(subscriber, this.settings.issuer);
194
+ }
195
+ async getById(subscriberId) {
196
+ const subscriber = await this.repo.findById(subscriberId);
197
+ if (!subscriber) throw subscriberNotFound(subscriberId);
198
+ return subscriber;
199
+ }
200
+ /**
201
+ * Changes how the subscriber is reached — the address, the country, the
202
+ * invoice email — at any time. A contract keeps the copy it was concluded
203
+ * with; what comes later reads the new details. The legal name and the tax
204
+ * identifiers are refused here: they change by `correctIdentity`.
205
+ */
206
+ async changeContact(subscriberId, change) {
207
+ return this.writeContact(subscriberId, settleContactChange(change));
208
+ }
209
+ /**
210
+ * A tenant's own change of how its subscriber is reached, from its billing
211
+ * area. The address and the invoice email can be changed but not cleared —
212
+ * `SUBSCRIBER_DETAIL_INVALID` names the field — since without them nothing
213
+ * can be invoiced. The legal name and the tax identifiers are refused as
214
+ * with `changeContact`: they are the party, and only the operator corrects
215
+ * them.
216
+ */
217
+ async changeContactOfTenant(tenantId, change) {
218
+ const subscriber = await this.requireForTenant(tenantId);
219
+ const settled = settleContactChange(change);
220
+ const cleared = KEPT_BY_A_TENANT.find((field) => settled[field] === null);
221
+ if (cleared) {
222
+ throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_DETAIL_INVALID, {
223
+ field: cleared
224
+ }));
225
+ }
226
+ return this.writeContact(subscriber.id, settled);
227
+ }
228
+ /** Writes contact details already settled; settling twice would check one copy and write another. */
229
+ async writeContact(subscriberId, settled) {
230
+ const updated = await this.repo.updateContact(subscriberId, settled);
231
+ if (!updated) throw subscriberNotFound(subscriberId);
232
+ return updated;
233
+ }
234
+ /**
235
+ * Corrects the legal identity of the same legal entity — a misspelt name, a
236
+ * wrong tax identifier, a change of name that entity went through — and
237
+ * records the values it replaced, the reason and who made it. A contract
238
+ * keeps the copy it was concluded with.
239
+ *
240
+ * The operator declares what the change is, because nothing here can tell:
241
+ * another legal entity taking over is a transfer, and is refused with
242
+ * `SUBSCRIBER_TAKEOVER_IS_A_TRANSFER` rather than recorded as an edit.
243
+ */
244
+ async correctIdentity(subscriberId, correction) {
245
+ if (correction.kind !== "correction") {
246
+ throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_TAKEOVER_IS_A_TRANSFER));
247
+ }
248
+ const reason = typeof correction.reason === "string" ? correction.reason.trim() : "";
249
+ if (reason === "") {
250
+ throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_CORRECTION_REASON_REQUIRED));
251
+ }
252
+ const correctedBy = typeof correction.correctedBy === "string" ? correction.correctedBy.trim() : "";
253
+ if (correctedBy === "") {
254
+ throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_CORRECTION_ACTOR_REQUIRED));
255
+ }
256
+ const result = await this.repo.correctIdentity(subscriberId, {
257
+ corrected: settleIdentityCorrection(correction),
258
+ reason,
259
+ correctedBy,
260
+ correctedAt: /* @__PURE__ */ new Date()
261
+ });
262
+ if (!result) throw subscriberNotFound(subscriberId);
263
+ if (!result.correction) {
264
+ throw new UnprocessableEntityException2(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_CORRECTION_CHANGES_NOTHING));
265
+ }
266
+ return result.correction;
267
+ }
268
+ /** Every correction of the subscriber's legal identity, the latest first. */
269
+ listCorrections(subscriberId) {
270
+ return this.repo.listCorrections(subscriberId);
271
+ }
272
+ };
273
+ SubscriberService = _ts_decorate([
274
+ Injectable(),
275
+ _ts_param(0, Inject(SUBSCRIBER_REPOSITORY_TOKEN)),
276
+ _ts_param(1, Inject(PLAN_CATALOG_SETTINGS_TOKEN)),
277
+ _ts_metadata("design:type", Function),
278
+ _ts_metadata("design:paramtypes", [
279
+ typeof SubscriberRepository === "undefined" ? Object : SubscriberRepository,
280
+ typeof PlanCatalogSettings === "undefined" ? Object : PlanCatalogSettings
281
+ ])
282
+ ], SubscriberService);
283
+ function subscriberRequired(tenantId) {
284
+ return new ConflictException(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_REQUIRED, {
285
+ tenantId
286
+ }));
287
+ }
288
+ __name(subscriberRequired, "subscriberRequired");
289
+ function subscriberNotFound(subscriberId) {
290
+ return new NotFoundException(codedError(SUBSCRIBER_ERROR_CODES2.SUBSCRIBER_NOT_FOUND, {
291
+ subscriberId
292
+ }));
293
+ }
294
+ __name(subscriberNotFound, "subscriberNotFound");
295
+
296
+ export {
297
+ INVOICE_ADDRESS_FIELDS,
298
+ settleNewSubscriberDetails,
299
+ SUBSCRIBER_REPOSITORY_TOKEN,
300
+ SubscriberService
301
+ };