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

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.js CHANGED
@@ -599,7 +599,10 @@ var SUBSCRIBER_ERROR_CODES = {
599
599
  SUBSCRIBER_ALREADY_EXISTS: "SUBSCRIBER_ALREADY_EXISTS",
600
600
  SUBSCRIBER_NOT_FOUND: "SUBSCRIBER_NOT_FOUND",
601
601
  SUBSCRIBER_LEGAL_NAME_REQUIRED: "SUBSCRIBER_LEGAL_NAME_REQUIRED",
602
- /** A detail that has a form — the country, the invoice email — is not in it. Carries `field`. */
602
+ /**
603
+ * A detail that has a form — the country, the invoice email — is not in it,
604
+ * or one sign-up requires — the billing address — is missing. Carries `field`.
605
+ */
603
606
  SUBSCRIBER_DETAIL_INVALID: "SUBSCRIBER_DETAIL_INVALID",
604
607
  /** A contact change named a field of the legal identity. Carries `field`. */
605
608
  SUBSCRIBER_IDENTITY_NOT_A_CONTACT: "SUBSCRIBER_IDENTITY_NOT_A_CONTACT",
@@ -634,6 +637,12 @@ var AUTH_ERROR_CODES = {
634
637
  /** Neither `tenantId` nor `userId` could be resolved from the request. */
635
638
  TENANT_CONTEXT_MISSING: "TENANT_CONTEXT_MISSING",
636
639
  TENANT_ADMIN_REQUIRED: "TENANT_ADMIN_REQUIRED",
640
+ /**
641
+ * The tenant's billing area — its payment method, and later its invoices
642
+ * and account — needs the billing permission, which the application maps
643
+ * to its roles and the tenant's administrator holds by default.
644
+ */
645
+ BILLING_PERMISSION_REQUIRED: "BILLING_PERMISSION_REQUIRED",
637
646
  SUPER_ADMIN_REQUIRED: "SUPER_ADMIN_REQUIRED",
638
647
  /** TOTP MFA has never been set up for this user. */
639
648
  MFA_NOT_SET_UP: "MFA_NOT_SET_UP",
@@ -661,6 +670,22 @@ var PROMO_ERROR_CODES = {
661
670
  PROMO_WOULD_PRODUCE_ZERO_INVOICE: "PROMO_WOULD_PRODUCE_ZERO_INVOICE",
662
671
  PROMO_MAX_REDEMPTIONS_LOWERED: "PROMO_MAX_REDEMPTIONS_LOWERED"
663
672
  };
673
+ var PAYMENT_ERROR_CODES = {
674
+ /**
675
+ * No gateway account takes new payment methods:
676
+ * `config/saas.yaml#payments.newPaymentMethods` names none.
677
+ */
678
+ PAYMENTS_NOT_CONFIGURED: "PAYMENTS_NOT_CONFIGURED",
679
+ /** A callback arrived for an account `config/saas.yaml#payments.accounts` does not name. Carries `account`. */
680
+ PAYMENT_GATEWAY_ACCOUNT_UNKNOWN: "PAYMENT_GATEWAY_ACCOUNT_UNKNOWN",
681
+ /** A callback the gateway did not send: its signature does not verify. */
682
+ PAYMENT_CALLBACK_REJECTED: "PAYMENT_CALLBACK_REJECTED",
683
+ /**
684
+ * A success or cancel URL at an origin `config/saas.yaml#payments.returnUrlOrigins`
685
+ * does not name. Carries `field`.
686
+ */
687
+ PAYMENT_RETURN_URL_NOT_ALLOWED: "PAYMENT_RETURN_URL_NOT_ALLOWED"
688
+ };
664
689
  var SETTINGS_ERROR_CODES = {
665
690
  /** No recorded change has this id, or the installation keeps no record at all. */
666
691
  SETTINGS_CHANGE_NOT_FOUND: "SETTINGS_CHANGE_NOT_FOUND"
@@ -674,6 +699,7 @@ var PLATFORM_ERROR_CODES = {
674
699
  ...CONTRACT_ERROR_CODES,
675
700
  ...SUBSCRIBER_ERROR_CODES,
676
701
  ...REGISTRATION_ERROR_CODES,
702
+ ...PAYMENT_ERROR_CODES,
677
703
  ...SETTINGS_ERROR_CODES
678
704
  };
679
705
 
@@ -753,6 +779,19 @@ function selectChargeableBundles(planFeatures, selectedBundles) {
753
779
  }
754
780
  }
755
781
 
782
+ // src/payment-gateway.types.ts
783
+ var PAYMENT_CALLBACK_REJECTED = "PAYMENT_CALLBACK_REJECTED";
784
+ var PaymentCallbackRejectedError = class extends Error {
785
+ code = PAYMENT_CALLBACK_REJECTED;
786
+ constructor(reason) {
787
+ super(`Payment callback rejected: ${reason}`);
788
+ this.name = "PaymentCallbackRejectedError";
789
+ }
790
+ };
791
+ function isPaymentCallbackRejectedError(err) {
792
+ return err instanceof Error && err.code === PAYMENT_CALLBACK_REJECTED;
793
+ }
794
+
756
795
  // src/registration.types.ts
757
796
  var PENDING_EMAIL_TTL_HOURS = 72;
758
797
  var PENDING_ONBOARDING_TTL_DAYS = 14;
@@ -916,7 +955,17 @@ function issuerPartyOf(issuer) {
916
955
  };
917
956
  }
918
957
  function subscriberFromRegistration(pending) {
919
- return { legalName: pending.tenantName, invoiceEmail: pending.email };
958
+ return {
959
+ legalName: pending.tenantName,
960
+ invoiceEmail: pending.email,
961
+ addressLine1: pending.addressLine1,
962
+ addressLine2: pending.addressLine2,
963
+ postalCode: pending.postalCode,
964
+ city: pending.city,
965
+ country: pending.country,
966
+ vatId: pending.vatId,
967
+ taxNumber: pending.taxNumber
968
+ };
920
969
  }
921
970
  function toIdentityValues(value) {
922
971
  if (value === null || typeof value !== "object" || Array.isArray(value)) return {};
@@ -930,6 +979,59 @@ function toIdentityValues(value) {
930
979
  return values;
931
980
  }
932
981
 
982
+ // src/subscriber-payment-method-mapping.ts
983
+ var PAYMENT_METHOD_TYPES = ["card", "sepa_debit"];
984
+ var STATUSES = ["ACTIVE", "REPLACED"];
985
+ function toSubscriberPaymentMethodRecord(row) {
986
+ return {
987
+ id: row.id,
988
+ subscriberId: row.subscriberId,
989
+ gatewayAccount: row.gatewayAccount,
990
+ provider: row.provider,
991
+ customerRef: row.customerRef,
992
+ paymentMethodRef: row.paymentMethodRef,
993
+ type: oneOf(PAYMENT_METHOD_TYPES, row.type, "type", row.id),
994
+ brand: row.brand,
995
+ last4: row.last4,
996
+ expiryMonth: row.expiryMonth,
997
+ expiryYear: row.expiryYear,
998
+ country: row.country,
999
+ bankCode: row.bankCode,
1000
+ mandateReference: row.mandateReference,
1001
+ status: oneOf(STATUSES, row.status, "status", row.id),
1002
+ confirmedAt: row.confirmedAt,
1003
+ replacedAt: row.replacedAt,
1004
+ createdAt: row.createdAt
1005
+ };
1006
+ }
1007
+ function subscriberPaymentMethodColumns(data) {
1008
+ return {
1009
+ subscriberId: data.subscriberId,
1010
+ gatewayAccount: data.gatewayAccount,
1011
+ provider: data.provider,
1012
+ customerRef: data.customerRef,
1013
+ paymentMethodRef: data.paymentMethodRef,
1014
+ type: data.type,
1015
+ brand: data.brand,
1016
+ last4: data.last4,
1017
+ expiryMonth: data.expiryMonth,
1018
+ expiryYear: data.expiryYear,
1019
+ country: data.country,
1020
+ bankCode: data.bankCode,
1021
+ mandateReference: data.mandateReference,
1022
+ confirmedAt: data.confirmedAt
1023
+ };
1024
+ }
1025
+ function oneOf(allowed, value, column, id) {
1026
+ const match = allowed.find((entry) => entry === value);
1027
+ if (match === void 0) {
1028
+ throw new Error(
1029
+ `subscriber_payment_methods row '${id}' holds ${column} '${value}', which is none of ${allowed.join(", ")}.`
1030
+ );
1031
+ }
1032
+ return match;
1033
+ }
1034
+
933
1035
  // src/subscription-contract-mapping.ts
934
1036
  function toSubscriptionContractRecord(row, lineItems) {
935
1037
  return {
@@ -1080,6 +1182,7 @@ var ERROR_MESSAGES_EN = {
1080
1182
  NO_TENANT_ASSIGNED: "No tenant assigned",
1081
1183
  TENANT_CONTEXT_MISSING: "No tenant ID found on the request",
1082
1184
  TENANT_ADMIN_REQUIRED: "This action requires the TENANT_ADMIN role.",
1185
+ BILLING_PERMISSION_REQUIRED: "This part of the billing area requires the billing permission.",
1083
1186
  SUPER_ADMIN_REQUIRED: "Only the SUPER_ADMIN role is allowed",
1084
1187
  MFA_NOT_SET_UP: "Run the MFA setup via the CLI first.",
1085
1188
  MFA_REQUIRED: "TOTP code required in the X-Mfa-Code header.",
@@ -1247,6 +1350,11 @@ var ERROR_MESSAGES_EN = {
1247
1350
  PLAN_NOT_AVAILABLE: "This plan is not available.",
1248
1351
  PLAN_NOT_SELECTED: "Please select a plan first.",
1249
1352
  MODEL_NOT_AVAILABLE: "This option is not available.",
1353
+ // ── payments ──
1354
+ PAYMENTS_NOT_CONFIGURED: "Payment methods cannot be set up here yet.",
1355
+ PAYMENT_GATEWAY_ACCOUNT_UNKNOWN: "No payment gateway account is configured under '{account}'.",
1356
+ PAYMENT_CALLBACK_REJECTED: "The payment callback could not be verified.",
1357
+ PAYMENT_RETURN_URL_NOT_ALLOWED: "The {field} leads to a site this installation does not return to.",
1250
1358
  // ── entitlement (code lives in upsell.types.ts) ──
1251
1359
  [FEATURE_NOT_LICENSED]: "Feature {featureKeys} is not included in the current plan.",
1252
1360
  // ── settings ──
@@ -1281,6 +1389,7 @@ var ERROR_MESSAGES_DE = {
1281
1389
  NO_TENANT_ASSIGNED: "Kein Mandant zugeordnet",
1282
1390
  TENANT_CONTEXT_MISSING: "Am Request wurde keine Mandanten-ID gefunden",
1283
1391
  TENANT_ADMIN_REQUIRED: "Diese Aktion erfordert die Rolle TENANT_ADMIN.",
1392
+ BILLING_PERMISSION_REQUIRED: "Dieser Teil der Abrechnung erfordert die Abrechnungs-Berechtigung.",
1284
1393
  SUPER_ADMIN_REQUIRED: "Nur die Rolle SUPER_ADMIN ist zugelassen",
1285
1394
  MFA_NOT_SET_UP: "Richte MFA zuerst \xFCber die CLI ein.",
1286
1395
  MFA_REQUIRED: "TOTP-Code im Header X-Mfa-Code erforderlich.",
@@ -1448,6 +1557,11 @@ var ERROR_MESSAGES_DE = {
1448
1557
  PLAN_NOT_AVAILABLE: "Dieser Plan steht nicht zur Verf\xFCgung.",
1449
1558
  PLAN_NOT_SELECTED: "Bitte w\xE4hle zuerst einen Plan aus.",
1450
1559
  MODEL_NOT_AVAILABLE: "Diese Option steht nicht zur Verf\xFCgung.",
1560
+ // ── payments ──
1561
+ PAYMENTS_NOT_CONFIGURED: "Zahlungsmethoden k\xF6nnen hier noch nicht hinterlegt werden.",
1562
+ PAYMENT_GATEWAY_ACCOUNT_UNKNOWN: "Unter '{account}' ist kein Konto eines Zahlungsanbieters eingerichtet.",
1563
+ PAYMENT_CALLBACK_REJECTED: "Die R\xFCckmeldung des Zahlungsanbieters lie\xDF sich nicht pr\xFCfen.",
1564
+ PAYMENT_RETURN_URL_NOT_ALLOWED: "Die {field} f\xFChrt auf eine Seite, zu der diese Installation nicht zur\xFCckleitet.",
1451
1565
  // ── entitlement (code lives in upsell.types.ts) ──
1452
1566
  [FEATURE_NOT_LICENSED]: "Das Feature {featureKeys} ist im aktuellen Plan nicht enthalten.",
1453
1567
  // ── settings ──
@@ -1471,11 +1585,14 @@ export {
1471
1585
  OTP_TTL_MINUTES,
1472
1586
  OTP_VERIFY_MAX_ATTEMPTS,
1473
1587
  PASSWORD_RESET_TTL_MINUTES,
1588
+ PAYMENT_ERROR_CODES,
1589
+ PAYMENT_METHOD_TYPES,
1474
1590
  PENDING_CHECKOUT_TTL_DAYS,
1475
1591
  PENDING_EMAIL_TTL_HOURS,
1476
1592
  PENDING_ONBOARDING_TTL_DAYS,
1477
1593
  PLATFORM_ERROR_CODES,
1478
1594
  PROMO_ERROR_CODES,
1595
+ PaymentCallbackRejectedError,
1479
1596
  PersistenceCapabilityError,
1480
1597
  PlatformUserExistsError,
1481
1598
  REGISTRATION_ERROR_CODES,
@@ -1504,6 +1621,7 @@ export {
1504
1621
  formatErrorMessage,
1505
1622
  identityCorrectionDelta,
1506
1623
  isBundleRedundant,
1624
+ isPaymentCallbackRejectedError,
1507
1625
  isPlatformUserExistsError,
1508
1626
  isVersionEditable,
1509
1627
  keepOneRecommended,
@@ -1520,11 +1638,13 @@ export {
1520
1638
  settingsSubtreeOf,
1521
1639
  startOfUtcDay,
1522
1640
  subscriberFromRegistration,
1641
+ subscriberPaymentMethodColumns,
1523
1642
  toBundleStemRow,
1524
1643
  toContractLineItemRecord,
1525
1644
  toPlanRow,
1526
1645
  toPlanVersionRow,
1527
1646
  toSubscriberCorrectionRecord,
1647
+ toSubscriberPaymentMethodRecord,
1528
1648
  toSubscriberRecord,
1529
1649
  toSubscriptionContractRecord
1530
1650
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasicat/core",
3
- "version": "1.0.0-rc.16",
3
+ "version": "1.0.0-rc.18",
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",