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

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/.build-stamp CHANGED
@@ -1 +1 @@
1
- ffbbf3de488fa65a264bc00b14097f9d84d9da3428b766d0c2c6b74ccac9b249
1
+ 785f84b789c4fbc325a4d35f81dec979a2575832412363bbcf2fbbe87995e875
package/dist/index.cjs CHANGED
@@ -664,6 +664,12 @@ var CONTRACT_ERROR_CODES = {
664
664
  CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED",
665
665
  CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED",
666
666
  CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED",
667
+ /**
668
+ * The offer changed between the checks of `conclude` and the transaction
669
+ * that consumed it, so the contract checked is not the one the offer now
670
+ * describes. Nothing was written; load the offer and conclude it again.
671
+ */
672
+ CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED",
667
673
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND",
668
674
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT",
669
675
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED"
@@ -1147,6 +1153,7 @@ var ERROR_MESSAGES_EN = {
1147
1153
  CHECKOUT_OFFER_EXPIRED: "Checkout offer '{offerId}' has expired and cannot be {action}",
1148
1154
  CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout offer '{offerId}' has already been consumed and cannot be {action}",
1149
1155
  CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' must be consumed before the contract is created",
1156
+ CHECKOUT_OFFER_CHANGED: "Checkout offer '{offerId}' changed while it was being concluded. Load it again.",
1150
1157
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' not found",
1151
1158
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "No active subscription contract for tenant {tenantId}",
1152
1159
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' is already closed",
@@ -1336,6 +1343,7 @@ var ERROR_MESSAGES_DE = {
1336
1343
  CHECKOUT_OFFER_EXPIRED: "Checkout-Angebot '{offerId}' ist abgelaufen \u2014 '{action}' ist nicht mehr m\xF6glich",
1337
1344
  CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout-Angebot '{offerId}' wurde bereits eingel\xF6st \u2014 '{action}' ist nicht mehr m\xF6glich",
1338
1345
  CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' muss eingel\xF6st sein, bevor der Vertrag entsteht",
1346
+ CHECKOUT_OFFER_CHANGED: "Checkout-Angebot '{offerId}' hat sich w\xE4hrend des Abschlusses ge\xE4ndert. Bitte neu laden.",
1339
1347
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' nicht gefunden",
1340
1348
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "Kein aktiver Abo-Vertrag f\xFCr Mandant {tenantId}",
1341
1349
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' ist bereits geschlossen",
package/dist/index.d.cts CHANGED
@@ -3085,7 +3085,15 @@ interface SubscriptionContractRepository {
3085
3085
  * instead of drawing an extra pool connection (starvation guard, #70).
3086
3086
  */
3087
3087
  findActiveByTenantId(tenantId: string, asOf?: Date, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
3088
- create(data: CreateSubscriptionContractData): Promise<SubscriptionContractRecord>;
3088
+ /** With `tx`, the contract is written on that transaction and undone with it. */
3089
+ create(data: CreateSubscriptionContractData, tx?: TransactionContext): Promise<SubscriptionContractRecord>;
3090
+ /**
3091
+ * The contract concluded from a checkout offer (`originalOfferId`), or
3092
+ * `null` when none was. An offer is consumed once and so yields one
3093
+ * contract (`SC-MKT-017`); where an application's own path wrote two, the
3094
+ * earliest is returned, so the answer does not depend on read order.
3095
+ */
3096
+ findByOriginalOfferId(offerId: string, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
3089
3097
  terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
3090
3098
  }
3091
3099
  /**
@@ -4030,8 +4038,19 @@ interface CheckoutOfferRepository {
4030
4038
  findById(id: string): Promise<CheckoutOfferRow | null>;
4031
4039
  create(data: CreateCheckoutOfferData): Promise<CheckoutOfferRow>;
4032
4040
  update(id: string, data: UpdateCheckoutOfferData): Promise<CheckoutOfferRow>;
4033
- /** Sets `status = 'consumed'` + `consumedAt = NOW()`. */
4034
- consume(id: string): Promise<CheckoutOfferRow>;
4041
+ /**
4042
+ * Sets `status = 'consumed'` + `consumedAt = NOW()`, and only while the
4043
+ * offer is still `open`: the write carries that condition, so of two
4044
+ * callers consuming at once one succeeds and the other is refused with
4045
+ * `CHECKOUT_OFFER_ALREADY_CONSUMED` (or `CHECKOUT_OFFER_EXPIRED`). A check
4046
+ * before the write cannot decide it, because the status can change in
4047
+ * between.
4048
+ *
4049
+ * With `tx`, the write runs on that transaction, so it is undone with
4050
+ * everything else the transaction wrote. `CheckoutOfferService.conclude`
4051
+ * depends on that; the persistence contract holds both.
4052
+ */
4053
+ consume(id: string, tx?: TransactionContext): Promise<CheckoutOfferRow>;
4035
4054
  }
4036
4055
 
4037
4056
  /** Which changes to list. */
@@ -4461,6 +4480,12 @@ declare const CONTRACT_ERROR_CODES: {
4461
4480
  readonly CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED";
4462
4481
  readonly CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED";
4463
4482
  readonly CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED";
4483
+ /**
4484
+ * The offer changed between the checks of `conclude` and the transaction
4485
+ * that consumed it, so the contract checked is not the one the offer now
4486
+ * describes. Nothing was written; load the offer and conclude it again.
4487
+ */
4488
+ readonly CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED";
4464
4489
  readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
4465
4490
  readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
4466
4491
  readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
@@ -4576,6 +4601,12 @@ declare const PLATFORM_ERROR_CODES: {
4576
4601
  readonly CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED";
4577
4602
  readonly CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED";
4578
4603
  readonly CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED";
4604
+ /**
4605
+ * The offer changed between the checks of `conclude` and the transaction
4606
+ * that consumed it, so the contract checked is not the one the offer now
4607
+ * describes. Nothing was written; load the offer and conclude it again.
4608
+ */
4609
+ readonly CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED";
4579
4610
  readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
4580
4611
  readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
4581
4612
  readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
package/dist/index.d.ts CHANGED
@@ -3085,7 +3085,15 @@ interface SubscriptionContractRepository {
3085
3085
  * instead of drawing an extra pool connection (starvation guard, #70).
3086
3086
  */
3087
3087
  findActiveByTenantId(tenantId: string, asOf?: Date, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
3088
- create(data: CreateSubscriptionContractData): Promise<SubscriptionContractRecord>;
3088
+ /** With `tx`, the contract is written on that transaction and undone with it. */
3089
+ create(data: CreateSubscriptionContractData, tx?: TransactionContext): Promise<SubscriptionContractRecord>;
3090
+ /**
3091
+ * The contract concluded from a checkout offer (`originalOfferId`), or
3092
+ * `null` when none was. An offer is consumed once and so yields one
3093
+ * contract (`SC-MKT-017`); where an application's own path wrote two, the
3094
+ * earliest is returned, so the answer does not depend on read order.
3095
+ */
3096
+ findByOriginalOfferId(offerId: string, tx?: TransactionContext): Promise<SubscriptionContractRecord | null>;
3089
3097
  terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
3090
3098
  }
3091
3099
  /**
@@ -4030,8 +4038,19 @@ interface CheckoutOfferRepository {
4030
4038
  findById(id: string): Promise<CheckoutOfferRow | null>;
4031
4039
  create(data: CreateCheckoutOfferData): Promise<CheckoutOfferRow>;
4032
4040
  update(id: string, data: UpdateCheckoutOfferData): Promise<CheckoutOfferRow>;
4033
- /** Sets `status = 'consumed'` + `consumedAt = NOW()`. */
4034
- consume(id: string): Promise<CheckoutOfferRow>;
4041
+ /**
4042
+ * Sets `status = 'consumed'` + `consumedAt = NOW()`, and only while the
4043
+ * offer is still `open`: the write carries that condition, so of two
4044
+ * callers consuming at once one succeeds and the other is refused with
4045
+ * `CHECKOUT_OFFER_ALREADY_CONSUMED` (or `CHECKOUT_OFFER_EXPIRED`). A check
4046
+ * before the write cannot decide it, because the status can change in
4047
+ * between.
4048
+ *
4049
+ * With `tx`, the write runs on that transaction, so it is undone with
4050
+ * everything else the transaction wrote. `CheckoutOfferService.conclude`
4051
+ * depends on that; the persistence contract holds both.
4052
+ */
4053
+ consume(id: string, tx?: TransactionContext): Promise<CheckoutOfferRow>;
4035
4054
  }
4036
4055
 
4037
4056
  /** Which changes to list. */
@@ -4461,6 +4480,12 @@ declare const CONTRACT_ERROR_CODES: {
4461
4480
  readonly CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED";
4462
4481
  readonly CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED";
4463
4482
  readonly CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED";
4483
+ /**
4484
+ * The offer changed between the checks of `conclude` and the transaction
4485
+ * that consumed it, so the contract checked is not the one the offer now
4486
+ * describes. Nothing was written; load the offer and conclude it again.
4487
+ */
4488
+ readonly CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED";
4464
4489
  readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
4465
4490
  readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
4466
4491
  readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
@@ -4576,6 +4601,12 @@ declare const PLATFORM_ERROR_CODES: {
4576
4601
  readonly CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED";
4577
4602
  readonly CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED";
4578
4603
  readonly CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED";
4604
+ /**
4605
+ * The offer changed between the checks of `conclude` and the transaction
4606
+ * that consumed it, so the contract checked is not the one the offer now
4607
+ * describes. Nothing was written; load the offer and conclude it again.
4608
+ */
4609
+ readonly CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED";
4579
4610
  readonly SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND";
4580
4611
  readonly NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT";
4581
4612
  readonly SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED";
package/dist/index.js CHANGED
@@ -575,6 +575,12 @@ var CONTRACT_ERROR_CODES = {
575
575
  CHECKOUT_OFFER_EXPIRED: "CHECKOUT_OFFER_EXPIRED",
576
576
  CHECKOUT_OFFER_ALREADY_CONSUMED: "CHECKOUT_OFFER_ALREADY_CONSUMED",
577
577
  CHECKOUT_OFFER_NOT_CONSUMED: "CHECKOUT_OFFER_NOT_CONSUMED",
578
+ /**
579
+ * The offer changed between the checks of `conclude` and the transaction
580
+ * that consumed it, so the contract checked is not the one the offer now
581
+ * describes. Nothing was written; load the offer and conclude it again.
582
+ */
583
+ CHECKOUT_OFFER_CHANGED: "CHECKOUT_OFFER_CHANGED",
578
584
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SUBSCRIPTION_CONTRACT_NOT_FOUND",
579
585
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "NO_ACTIVE_SUBSCRIPTION_CONTRACT",
580
586
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SUBSCRIPTION_CONTRACT_ALREADY_CLOSED"
@@ -1058,6 +1064,7 @@ var ERROR_MESSAGES_EN = {
1058
1064
  CHECKOUT_OFFER_EXPIRED: "Checkout offer '{offerId}' has expired and cannot be {action}",
1059
1065
  CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout offer '{offerId}' has already been consumed and cannot be {action}",
1060
1066
  CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' must be consumed before the contract is created",
1067
+ CHECKOUT_OFFER_CHANGED: "Checkout offer '{offerId}' changed while it was being concluded. Load it again.",
1061
1068
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' not found",
1062
1069
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "No active subscription contract for tenant {tenantId}",
1063
1070
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' is already closed",
@@ -1247,6 +1254,7 @@ var ERROR_MESSAGES_DE = {
1247
1254
  CHECKOUT_OFFER_EXPIRED: "Checkout-Angebot '{offerId}' ist abgelaufen \u2014 '{action}' ist nicht mehr m\xF6glich",
1248
1255
  CHECKOUT_OFFER_ALREADY_CONSUMED: "Checkout-Angebot '{offerId}' wurde bereits eingel\xF6st \u2014 '{action}' ist nicht mehr m\xF6glich",
1249
1256
  CHECKOUT_OFFER_NOT_CONSUMED: "CheckoutOffer '{offerId}' muss eingel\xF6st sein, bevor der Vertrag entsteht",
1257
+ CHECKOUT_OFFER_CHANGED: "Checkout-Angebot '{offerId}' hat sich w\xE4hrend des Abschlusses ge\xE4ndert. Bitte neu laden.",
1250
1258
  SUBSCRIPTION_CONTRACT_NOT_FOUND: "SubscriptionContract '{contractId}' nicht gefunden",
1251
1259
  NO_ACTIVE_SUBSCRIPTION_CONTRACT: "Kein aktiver Abo-Vertrag f\xFCr Mandant {tenantId}",
1252
1260
  SUBSCRIPTION_CONTRACT_ALREADY_CLOSED: "SubscriptionContract '{contractId}' ist bereits geschlossen",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasicat/core",
3
- "version": "1.0.0-rc.14",
3
+ "version": "1.0.0-rc.15",
4
4
  "description": "TypeScript contracts for SaaSiCat — capabilities, catalogs, subscriptions, entitlements, admin manifests, persistence ports — and the pure domain logic both server and browser run: error catalogues, plan-diff classification, promo arithmetic, feature requirements.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",