@peable.to/shared-types 0.12.0 → 0.14.0

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.
@@ -1,2 +1,78 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DISPUTE_FILE_EVIDENCE_FIELDS = exports.DISPUTE_TEXT_EVIDENCE_FIELDS = exports.DISPUTE_REASONS = void 0;
4
+ exports.normalizeDisputeReason = normalizeDisputeReason;
5
+ /**
6
+ * Why the cardholder disputed — Stripe's enum. A network reason code the
7
+ * provider does not map to one of these reads `general`; the row keeps the
8
+ * provider's own word, so nothing is lost by the normalisation.
9
+ */
10
+ exports.DISPUTE_REASONS = [
11
+ 'bank_cannot_process',
12
+ 'check_returned',
13
+ 'credit_not_processed',
14
+ 'customer_initiated',
15
+ 'debit_not_authorized',
16
+ 'duplicate',
17
+ 'fraudulent',
18
+ 'general',
19
+ 'incorrect_account_details',
20
+ 'insufficient_funds',
21
+ 'noncompliant',
22
+ 'product_not_received',
23
+ 'product_unacceptable',
24
+ 'subscription_canceled',
25
+ 'unrecognized',
26
+ ];
27
+ /** Map any provider reason onto {@link DisputeReason}: unknown or absent is `general`. */
28
+ function normalizeDisputeReason(reason) {
29
+ return exports.DISPUTE_REASONS.includes(reason ?? '')
30
+ ? reason
31
+ : 'general';
32
+ }
33
+ /**
34
+ * The TEXT evidence fields — the network's names, spelled the way the rest of
35
+ * these contracts spell things, never a Peable paraphrase: a merchant assembling
36
+ * a defence is reading their acquirer's guidance, and renamed fields would make
37
+ * that guidance not apply.
38
+ *
39
+ * Declared ONCE. The route's schema is `satisfies Record<DisputeTextEvidenceField, …>`
40
+ * and the Stripe adapter's name map is a total `Record`, so a field added here
41
+ * does not compile until both carry it — the drift that would let a merchant
42
+ * send a field the network never sees.
43
+ */
44
+ exports.DISPUTE_TEXT_EVIDENCE_FIELDS = [
45
+ 'access_activity_log',
46
+ 'billing_address',
47
+ 'cancellation_policy_disclosure',
48
+ 'cancellation_rebuttal',
49
+ 'customer_email_address',
50
+ 'customer_name',
51
+ 'customer_purchase_ip',
52
+ 'duplicate_charge_explanation',
53
+ 'product_description',
54
+ 'refund_policy_disclosure',
55
+ 'refund_refusal_explanation',
56
+ 'service_date',
57
+ 'shipping_address',
58
+ 'shipping_carrier',
59
+ 'shipping_date',
60
+ 'shipping_tracking_number',
61
+ 'uncategorized_text',
62
+ ];
63
+ /**
64
+ * The FILE evidence fields. Each names a `file_…` of purpose `dispute_evidence`
65
+ * uploaded by the same merchant; its bytes go to the provider when the response
66
+ * is submitted, and only then.
67
+ */
68
+ exports.DISPUTE_FILE_EVIDENCE_FIELDS = [
69
+ 'cancellation_policy',
70
+ 'customer_communication',
71
+ 'customer_signature',
72
+ 'duplicate_charge_documentation',
73
+ 'receipt',
74
+ 'refund_policy',
75
+ 'service_documentation',
76
+ 'shipping_documentation',
77
+ 'uncategorized_file',
78
+ ];
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ // Files (`file_…`) — bytes a merchant gives Orbit for one stated purpose
3
+ // (ADR 0016: Orbit owns the object; the storage is Oxy Files, a binding that
4
+ // never reaches the wire). Stripe's Files API, with Oxy Files underneath.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.FILE_PURPOSE_POLICIES = exports.FILE_STATUSES = exports.FILE_TYPES = exports.FILE_PURPOSES = void 0;
7
+ /**
8
+ * What a file is FOR. Decided at upload and never changed: the purpose is what
9
+ * sets the type and size policy, who may see the bytes, and which objects may
10
+ * reference the file — a `business_logo` is public, a `dispute_evidence` file
11
+ * is private and can only be attached to the merchant's own disputes.
12
+ */
13
+ exports.FILE_PURPOSES = [
14
+ 'dispute_evidence',
15
+ 'business_logo',
16
+ 'identity_document',
17
+ 'additional_verification',
18
+ ];
19
+ /** The stored format, by its conventional extension (Stripe's `type`). */
20
+ exports.FILE_TYPES = ['pdf', 'png', 'jpg'];
21
+ /**
22
+ * Whether the bytes can be used right now.
23
+ *
24
+ * - `available` — Oxy serves the file; it can be shown or forwarded.
25
+ * - `withheld` — the file still exists and is not being served (its owner
26
+ * trashed it or made it private); it can come back.
27
+ * - `removed` — Oxy said the file is gone for good (deleted, taken down, lost).
28
+ * The object stays so whatever referenced it can say why it stopped working.
29
+ */
30
+ exports.FILE_STATUSES = ['available', 'withheld', 'removed'];
31
+ /**
32
+ * The upload policy of each purpose: the formats it takes, recognised from the
33
+ * bytes and never from a client's `Content-Type`, and the largest file.
34
+ *
35
+ * The provider's own ceilings, restated where the upload is parsed, so a file
36
+ * the card network would refuse is refused at upload — not at the one-shot
37
+ * dispute submission it was meant for.
38
+ */
39
+ exports.FILE_PURPOSE_POLICIES = Object.freeze({
40
+ dispute_evidence: { types: ['pdf', 'png', 'jpg'], max_bytes: 5 * 1024 * 1024 },
41
+ business_logo: { types: ['png', 'jpg'], max_bytes: 512 * 1024 },
42
+ identity_document: { types: ['pdf', 'png', 'jpg'], max_bytes: 10 * 1024 * 1024 },
43
+ additional_verification: { types: ['pdf', 'png', 'jpg'], max_bytes: 10 * 1024 * 1024 },
44
+ });
package/dist/cjs/index.js CHANGED
@@ -1,12 +1,14 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.TAX_LOCATION_EVIDENCE_TYPES = exports.TAX_REGISTRATION_SCHEMES = exports.PEABLE_BILLING_AUTHORITY_KEYS = exports.canonicalBillingTaxQuote = exports.canonicalBillingAuthority = exports.BILLING_SUBSCRIPTION_STATUSES = exports.SOCIAL_SOURCE_REF_MAX_LENGTH = exports.SOCIAL_SOURCE_APP_MAX_LENGTH = exports.MERCHANT_ENVIRONMENTS = exports.verifyWebhook = exports.signWebhook = exports.CATALOG_LIMITS = exports.COUPON_DURATIONS = exports.TRANSFORM_QUANTITY_ROUNDS = exports.PRICE_TAX_BEHAVIORS = exports.RECURRING_USAGE_TYPES = exports.RECURRING_INTERVALS = exports.PRICE_TYPES = exports.PRICE_TIERS_MODES = exports.PRICE_BILLING_SCHEMES = exports.WEBHOOK_SECRET_ROLL_MAX_EXPIRES_IN_SECONDS = exports.WEBHOOK_ENDPOINTS_MAX_PER_MERCHANT = exports.WEBHOOK_ENDPOINT_DISABLED_REASONS = exports.WEBHOOK_ENDPOINT_STATUSES = exports.PEABLE_API_VERSION = exports.SETUP_INTENT_STATUSES = exports.isValidStatusTransition = exports.canStillBePaid = exports.canExpire = exports.TERMINAL_STATUSES = exports.PAYMENT_INTENT_STATUSES = exports.PAYMENT_INTENT_SETUP_FUTURE_USAGES = exports.PAYMENT_INTENT_RAILS = exports.PAYMENT_INTENT_CAPTURE_METHODS = exports.PAYMENT_INTENT_CANCELLATION_REASONS = exports.MERCHANT_CANCELLATION_REASONS = exports.EXPIRABLE_STATUSES = exports.CARD_ONLY_STATUSES = exports.isCurrencyCode = exports.decimalsFor = exports.CURRENCY_DECIMALS = exports.CURRENCY_CODES = exports.isBaseUnitString = exports.UNITS_PER_COIN = void 0;
3
+ exports.verifyWebhook = exports.signWebhook = exports.SIMULATED_FAIRCOIN_OUTCOMES = exports.REQUEST_LOG_RETENTION_DAYS = exports.REQUEST_LOG_METHODS = exports.PAYMENT_METHOD_CURRENCIES = exports.PAYMENT_METHOD_CONFIGURATION_TYPES = exports.CARD_RAIL_PAYMENT_METHOD_TYPES = exports.FILE_TYPES = exports.FILE_STATUSES = exports.FILE_PURPOSE_POLICIES = exports.FILE_PURPOSES = exports.normalizeDisputeReason = exports.DISPUTE_TEXT_EVIDENCE_FIELDS = exports.DISPUTE_REASONS = exports.DISPUTE_FILE_EVIDENCE_FIELDS = exports.CATALOG_LIMITS = exports.COUPON_DURATIONS = exports.TRANSFORM_QUANTITY_ROUNDS = exports.PRICE_TAX_BEHAVIORS = exports.RECURRING_USAGE_TYPES = exports.RECURRING_INTERVALS = exports.PRICE_TYPES = exports.PRICE_TIERS_MODES = exports.PRICE_BILLING_SCHEMES = exports.WEBHOOK_SECRET_ROLL_MAX_EXPIRES_IN_SECONDS = exports.WEBHOOK_ENDPOINTS_MAX_PER_MERCHANT = exports.WEBHOOK_ENDPOINT_DISABLED_REASONS = exports.WEBHOOK_ENDPOINT_STATUSES = exports.PEABLE_API_VERSION = exports.SETUP_INTENT_STATUSES = exports.isValidStatusTransition = exports.canStillBePaid = exports.canExpire = exports.TERMINAL_STATUSES = exports.PAYMENT_INTENT_STATUSES = exports.PAYMENT_INTENT_SETUP_FUTURE_USAGES = exports.PAYMENT_INTENT_RAILS = exports.PAYMENT_INTENT_CAPTURE_METHODS = exports.PAYMENT_INTENT_CANCELLATION_REASONS = exports.MERCHANT_CANCELLATION_REASONS = exports.EXPIRABLE_STATUSES = exports.CARD_ONLY_STATUSES = exports.isCurrencyCode = exports.decimalsFor = exports.FIAT_CURRENCY_CODES = exports.CURRENCY_DECIMALS = exports.CURRENCY_CODES = exports.isBaseUnitString = exports.UNITS_PER_COIN = void 0;
4
+ exports.TAX_LOCATION_EVIDENCE_TYPES = exports.TAX_REGISTRATION_SCHEMES = exports.PEABLE_BILLING_AUTHORITY_KEYS = exports.canonicalBillingTaxQuote = exports.canonicalBillingAuthority = exports.BILLING_SUBSCRIPTION_STATUSES = exports.SOCIAL_SOURCE_REF_MAX_LENGTH = exports.SOCIAL_SOURCE_APP_MAX_LENGTH = exports.MERCHANT_ENVIRONMENTS = void 0;
4
5
  // @peable.to/shared-types — public API for the Peable Gateway contract.
5
6
  var money_1 = require("./money");
6
7
  Object.defineProperty(exports, "UNITS_PER_COIN", { enumerable: true, get: function () { return money_1.UNITS_PER_COIN; } });
7
8
  Object.defineProperty(exports, "isBaseUnitString", { enumerable: true, get: function () { return money_1.isBaseUnitString; } });
8
9
  Object.defineProperty(exports, "CURRENCY_CODES", { enumerable: true, get: function () { return money_1.CURRENCY_CODES; } });
9
10
  Object.defineProperty(exports, "CURRENCY_DECIMALS", { enumerable: true, get: function () { return money_1.CURRENCY_DECIMALS; } });
11
+ Object.defineProperty(exports, "FIAT_CURRENCY_CODES", { enumerable: true, get: function () { return money_1.FIAT_CURRENCY_CODES; } });
10
12
  Object.defineProperty(exports, "decimalsFor", { enumerable: true, get: function () { return money_1.decimalsFor; } });
11
13
  Object.defineProperty(exports, "isCurrencyCode", { enumerable: true, get: function () { return money_1.isCurrencyCode; } });
12
14
  var paymentIntent_1 = require("./paymentIntent");
@@ -41,6 +43,25 @@ Object.defineProperty(exports, "PRICE_TAX_BEHAVIORS", { enumerable: true, get: f
41
43
  Object.defineProperty(exports, "TRANSFORM_QUANTITY_ROUNDS", { enumerable: true, get: function () { return catalog_1.TRANSFORM_QUANTITY_ROUNDS; } });
42
44
  Object.defineProperty(exports, "COUPON_DURATIONS", { enumerable: true, get: function () { return catalog_1.COUPON_DURATIONS; } });
43
45
  Object.defineProperty(exports, "CATALOG_LIMITS", { enumerable: true, get: function () { return catalog_1.CATALOG_LIMITS; } });
46
+ var dispute_1 = require("./dispute");
47
+ Object.defineProperty(exports, "DISPUTE_FILE_EVIDENCE_FIELDS", { enumerable: true, get: function () { return dispute_1.DISPUTE_FILE_EVIDENCE_FIELDS; } });
48
+ Object.defineProperty(exports, "DISPUTE_REASONS", { enumerable: true, get: function () { return dispute_1.DISPUTE_REASONS; } });
49
+ Object.defineProperty(exports, "DISPUTE_TEXT_EVIDENCE_FIELDS", { enumerable: true, get: function () { return dispute_1.DISPUTE_TEXT_EVIDENCE_FIELDS; } });
50
+ Object.defineProperty(exports, "normalizeDisputeReason", { enumerable: true, get: function () { return dispute_1.normalizeDisputeReason; } });
51
+ var file_1 = require("./file");
52
+ Object.defineProperty(exports, "FILE_PURPOSES", { enumerable: true, get: function () { return file_1.FILE_PURPOSES; } });
53
+ Object.defineProperty(exports, "FILE_PURPOSE_POLICIES", { enumerable: true, get: function () { return file_1.FILE_PURPOSE_POLICIES; } });
54
+ Object.defineProperty(exports, "FILE_STATUSES", { enumerable: true, get: function () { return file_1.FILE_STATUSES; } });
55
+ Object.defineProperty(exports, "FILE_TYPES", { enumerable: true, get: function () { return file_1.FILE_TYPES; } });
56
+ var paymentMethodConfiguration_1 = require("./paymentMethodConfiguration");
57
+ Object.defineProperty(exports, "CARD_RAIL_PAYMENT_METHOD_TYPES", { enumerable: true, get: function () { return paymentMethodConfiguration_1.CARD_RAIL_PAYMENT_METHOD_TYPES; } });
58
+ Object.defineProperty(exports, "PAYMENT_METHOD_CONFIGURATION_TYPES", { enumerable: true, get: function () { return paymentMethodConfiguration_1.PAYMENT_METHOD_CONFIGURATION_TYPES; } });
59
+ Object.defineProperty(exports, "PAYMENT_METHOD_CURRENCIES", { enumerable: true, get: function () { return paymentMethodConfiguration_1.PAYMENT_METHOD_CURRENCIES; } });
60
+ var requestLog_1 = require("./requestLog");
61
+ Object.defineProperty(exports, "REQUEST_LOG_METHODS", { enumerable: true, get: function () { return requestLog_1.REQUEST_LOG_METHODS; } });
62
+ Object.defineProperty(exports, "REQUEST_LOG_RETENTION_DAYS", { enumerable: true, get: function () { return requestLog_1.REQUEST_LOG_RETENTION_DAYS; } });
63
+ var testHelpers_1 = require("./testHelpers");
64
+ Object.defineProperty(exports, "SIMULATED_FAIRCOIN_OUTCOMES", { enumerable: true, get: function () { return testHelpers_1.SIMULATED_FAIRCOIN_OUTCOMES; } });
44
65
  var webhookSigner_1 = require("./webhookSigner");
45
66
  Object.defineProperty(exports, "signWebhook", { enumerable: true, get: function () { return webhookSigner_1.signWebhook; } });
46
67
  Object.defineProperty(exports, "verifyWebhook", { enumerable: true, get: function () { return webhookSigner_1.verifyWebhook; } });
package/dist/cjs/money.js CHANGED
@@ -3,12 +3,16 @@
3
3
  // canonical integer string in the currency's SMALLEST unit — m⊜ for FairCoin,
4
4
  // cents for a fiat currency — so no float ever touches one.
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.UNITS_PER_COIN = exports.CURRENCY_DECIMALS = exports.CURRENCY_CODES = void 0;
6
+ exports.UNITS_PER_COIN = exports.FIAT_CURRENCY_CODES = exports.CURRENCY_DECIMALS = exports.CURRENCY_CODES = void 0;
7
7
  exports.isCurrencyCode = isCurrencyCode;
8
8
  exports.decimalsFor = decimalsFor;
9
9
  exports.isBaseUnitString = isBaseUnitString;
10
10
  /**
11
- * The currencies this gateway can denominate a payment in.
11
+ * The currencies this gateway can denominate a payment in: FairCoin on the
12
+ * chain rail, and on the card rail the fiat set the provider settles for the
13
+ * payment methods Orbit offers (cards, wallets, SEPA Debit, iDEAL, Bancontact,
14
+ * EPS). A local method narrows it further per payment
15
+ * (`PAYMENT_METHOD_CURRENCIES` in `paymentMethodConfiguration.ts`).
12
16
  *
13
17
  * A closed set, and the database mirrors it as a CHECK
14
18
  * (`db/schema/valueSets.ts`). ADR 0001 D4: the scale of an amount is a property
@@ -16,7 +20,21 @@ exports.isBaseUnitString = isBaseUnitString;
16
20
  * {@link CURRENCY_DECIMALS} exists and why {@link UNITS_PER_COIN} must never be
17
21
  * used to interpret a fiat amount.
18
22
  */
19
- exports.CURRENCY_CODES = ['FAIR', 'EUR', 'USD'];
23
+ exports.CURRENCY_CODES = [
24
+ 'FAIR',
25
+ 'EUR',
26
+ 'USD',
27
+ 'GBP',
28
+ 'CHF',
29
+ 'SEK',
30
+ 'NOK',
31
+ 'DKK',
32
+ 'PLN',
33
+ 'CZK',
34
+ 'CAD',
35
+ 'AUD',
36
+ 'JPY',
37
+ ];
20
38
  /** Whether an arbitrary string is a currency this gateway knows. */
21
39
  function isCurrencyCode(value) {
22
40
  return exports.CURRENCY_CODES.includes(value);
@@ -25,7 +43,7 @@ function isCurrencyCode(value) {
25
43
  * How many decimal places each currency's smallest unit represents — i.e. an
26
44
  * amount of `1` means `10^-decimals` of one whole unit.
27
45
  *
28
- * FairCoin's 8 is a consensus constant and is pinned against
46
+ * ISO 4217's minor units for every fiat member (JPY has none). FairCoin's 8 is a consensus constant and is pinned against
29
47
  * {@link UNITS_PER_COIN} by this package's own tests, so the two spellings of
30
48
  * one fact cannot drift.
31
49
  */
@@ -33,7 +51,21 @@ exports.CURRENCY_DECIMALS = Object.freeze({
33
51
  FAIR: 8,
34
52
  EUR: 2,
35
53
  USD: 2,
54
+ GBP: 2,
55
+ CHF: 2,
56
+ SEK: 2,
57
+ NOK: 2,
58
+ DKK: 2,
59
+ PLN: 2,
60
+ CZK: 2,
61
+ CAD: 2,
62
+ AUD: 2,
63
+ // A zero-decimal currency: an amount of `1` is one yen, never a hundredth of
64
+ // one. The provider counts JPY the same way, so the base unit crosses as is.
65
+ JPY: 0,
36
66
  });
67
+ /** The fiat members — every currency the card rail can denominate a payment in. */
68
+ exports.FIAT_CURRENCY_CODES = exports.CURRENCY_CODES.filter((code) => code !== 'FAIR');
37
69
  /** The decimal places of `currency`'s smallest unit. */
38
70
  function decimalsFor(currency) {
39
71
  return exports.CURRENCY_DECIMALS[currency];
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PAYMENT_METHOD_CURRENCIES = exports.CARD_RAIL_PAYMENT_METHOD_TYPES = exports.PAYMENT_METHOD_CONFIGURATION_TYPES = void 0;
4
+ // Payment method breadth on the card rail — which methods a merchant's payers
5
+ // are offered (`pmc_…`), and the web domains wallets may run on (`pmd_…`).
6
+ // Both are Orbit's objects; the provider's configuration and domain are
7
+ // bindings behind them (ADR 0016). Card data and bank credentials are entered
8
+ // in the provider's hosted fields and never reach Peable (PCI SAQ-A).
9
+ const money_1 = require("./money");
10
+ /**
11
+ * The methods a configuration can turn on.
12
+ *
13
+ * `apple_pay` and `google_pay` are WALLETS over a card: a payment made with one
14
+ * is a `card` payment, so they appear here and never in a PaymentIntent's
15
+ * `payment_method_types`. `bizum` is listed because merchants ask for it and the
16
+ * honest answer is a reason, not an absence: the provider does not offer it.
17
+ *
18
+ * Deliberately absent: the provider's own consumer wallet (its brand on Orbit's
19
+ * checkout, `payment-provider-boundary.md`) and giropay (discontinued by the
20
+ * scheme).
21
+ */
22
+ exports.PAYMENT_METHOD_CONFIGURATION_TYPES = [
23
+ 'card',
24
+ 'apple_pay',
25
+ 'google_pay',
26
+ 'sepa_debit',
27
+ 'ideal',
28
+ 'bancontact',
29
+ 'eps',
30
+ 'bizum',
31
+ ];
32
+ /** The card-rail types a PaymentIntent can carry in `payment_method_types`. */
33
+ exports.CARD_RAIL_PAYMENT_METHOD_TYPES = [
34
+ 'card',
35
+ 'sepa_debit',
36
+ 'ideal',
37
+ 'bancontact',
38
+ 'eps',
39
+ ];
40
+ /**
41
+ * The currencies each method can take a payment in. A method is offered on a
42
+ * payment only when its currency is listed — so iDEAL never appears on a USD
43
+ * payment, and a payer is never shown a method that would fail.
44
+ */
45
+ exports.PAYMENT_METHOD_CURRENCIES = Object.freeze({
46
+ card: money_1.FIAT_CURRENCY_CODES,
47
+ apple_pay: money_1.FIAT_CURRENCY_CODES,
48
+ google_pay: money_1.FIAT_CURRENCY_CODES,
49
+ sepa_debit: ['EUR'],
50
+ ideal: ['EUR'],
51
+ bancontact: ['EUR'],
52
+ eps: ['EUR'],
53
+ bizum: ['EUR'],
54
+ });
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.REQUEST_LOG_RETENTION_DAYS = exports.REQUEST_LOG_METHODS = void 0;
4
+ /**
5
+ * One merchant API request, as Peable recorded it (`req_…`) — the request log
6
+ * Orbit and `peable logs tail` read.
7
+ *
8
+ * Its `id` IS the `Request-Id` that request was answered with, so the id a
9
+ * merchant quotes to support and the log row are the same thing.
10
+ *
11
+ * Deliberately thin: method, path (no query string), status, duration and the
12
+ * `Idempotency-Key` it carried. No body, no headers, no query string, no
13
+ * caller address — a log a merchant can read is a log that must not hold what
14
+ * a request carried. Kept 30 days.
15
+ */
16
+ exports.REQUEST_LOG_METHODS = ['GET', 'POST', 'DELETE', 'PATCH', 'PUT'];
17
+ /** How long a request log is kept (and served). */
18
+ exports.REQUEST_LOG_RETENTION_DAYS = 30;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * Test helpers (`/v1/test_helpers/*`) — test mode only.
4
+ *
5
+ * They drive a test-mode object through the SAME state machine a real payment
6
+ * moves through, so a merchant can exercise their integration end to end
7
+ * without a wallet or a card: every transition a helper makes is one the
8
+ * gateway would make, with the same events and webhooks.
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.SIMULATED_FAIRCOIN_OUTCOMES = void 0;
12
+ /**
13
+ * What `simulate_faircoin_payment` pretends the payer did.
14
+ *
15
+ * - `settled` — paid the full amount, which is then seen in the mempool and
16
+ * confirmed: `broadcast → confirming → settled`
17
+ * (`payment_intent.confirming`, then `payment_intent.settled`).
18
+ * - `underpaid` — sent less than the amount: `broadcast → failed`
19
+ * (`payment_intent.failed`).
20
+ */
21
+ exports.SIMULATED_FAIRCOIN_OUTCOMES = ['settled', 'underpaid'];
@@ -1 +1,74 @@
1
- export {};
1
+ /**
2
+ * Why the cardholder disputed — Stripe's enum. A network reason code the
3
+ * provider does not map to one of these reads `general`; the row keeps the
4
+ * provider's own word, so nothing is lost by the normalisation.
5
+ */
6
+ export const DISPUTE_REASONS = [
7
+ 'bank_cannot_process',
8
+ 'check_returned',
9
+ 'credit_not_processed',
10
+ 'customer_initiated',
11
+ 'debit_not_authorized',
12
+ 'duplicate',
13
+ 'fraudulent',
14
+ 'general',
15
+ 'incorrect_account_details',
16
+ 'insufficient_funds',
17
+ 'noncompliant',
18
+ 'product_not_received',
19
+ 'product_unacceptable',
20
+ 'subscription_canceled',
21
+ 'unrecognized',
22
+ ];
23
+ /** Map any provider reason onto {@link DisputeReason}: unknown or absent is `general`. */
24
+ export function normalizeDisputeReason(reason) {
25
+ return DISPUTE_REASONS.includes(reason ?? '')
26
+ ? reason
27
+ : 'general';
28
+ }
29
+ /**
30
+ * The TEXT evidence fields — the network's names, spelled the way the rest of
31
+ * these contracts spell things, never a Peable paraphrase: a merchant assembling
32
+ * a defence is reading their acquirer's guidance, and renamed fields would make
33
+ * that guidance not apply.
34
+ *
35
+ * Declared ONCE. The route's schema is `satisfies Record<DisputeTextEvidenceField, …>`
36
+ * and the Stripe adapter's name map is a total `Record`, so a field added here
37
+ * does not compile until both carry it — the drift that would let a merchant
38
+ * send a field the network never sees.
39
+ */
40
+ export const DISPUTE_TEXT_EVIDENCE_FIELDS = [
41
+ 'access_activity_log',
42
+ 'billing_address',
43
+ 'cancellation_policy_disclosure',
44
+ 'cancellation_rebuttal',
45
+ 'customer_email_address',
46
+ 'customer_name',
47
+ 'customer_purchase_ip',
48
+ 'duplicate_charge_explanation',
49
+ 'product_description',
50
+ 'refund_policy_disclosure',
51
+ 'refund_refusal_explanation',
52
+ 'service_date',
53
+ 'shipping_address',
54
+ 'shipping_carrier',
55
+ 'shipping_date',
56
+ 'shipping_tracking_number',
57
+ 'uncategorized_text',
58
+ ];
59
+ /**
60
+ * The FILE evidence fields. Each names a `file_…` of purpose `dispute_evidence`
61
+ * uploaded by the same merchant; its bytes go to the provider when the response
62
+ * is submitted, and only then.
63
+ */
64
+ export const DISPUTE_FILE_EVIDENCE_FIELDS = [
65
+ 'cancellation_policy',
66
+ 'customer_communication',
67
+ 'customer_signature',
68
+ 'duplicate_charge_documentation',
69
+ 'receipt',
70
+ 'refund_policy',
71
+ 'service_documentation',
72
+ 'shipping_documentation',
73
+ 'uncategorized_file',
74
+ ];
@@ -0,0 +1,41 @@
1
+ // Files (`file_…`) — bytes a merchant gives Orbit for one stated purpose
2
+ // (ADR 0016: Orbit owns the object; the storage is Oxy Files, a binding that
3
+ // never reaches the wire). Stripe's Files API, with Oxy Files underneath.
4
+ /**
5
+ * What a file is FOR. Decided at upload and never changed: the purpose is what
6
+ * sets the type and size policy, who may see the bytes, and which objects may
7
+ * reference the file — a `business_logo` is public, a `dispute_evidence` file
8
+ * is private and can only be attached to the merchant's own disputes.
9
+ */
10
+ export const FILE_PURPOSES = [
11
+ 'dispute_evidence',
12
+ 'business_logo',
13
+ 'identity_document',
14
+ 'additional_verification',
15
+ ];
16
+ /** The stored format, by its conventional extension (Stripe's `type`). */
17
+ export const FILE_TYPES = ['pdf', 'png', 'jpg'];
18
+ /**
19
+ * Whether the bytes can be used right now.
20
+ *
21
+ * - `available` — Oxy serves the file; it can be shown or forwarded.
22
+ * - `withheld` — the file still exists and is not being served (its owner
23
+ * trashed it or made it private); it can come back.
24
+ * - `removed` — Oxy said the file is gone for good (deleted, taken down, lost).
25
+ * The object stays so whatever referenced it can say why it stopped working.
26
+ */
27
+ export const FILE_STATUSES = ['available', 'withheld', 'removed'];
28
+ /**
29
+ * The upload policy of each purpose: the formats it takes, recognised from the
30
+ * bytes and never from a client's `Content-Type`, and the largest file.
31
+ *
32
+ * The provider's own ceilings, restated where the upload is parsed, so a file
33
+ * the card network would refuse is refused at upload — not at the one-shot
34
+ * dispute submission it was meant for.
35
+ */
36
+ export const FILE_PURPOSE_POLICIES = Object.freeze({
37
+ dispute_evidence: { types: ['pdf', 'png', 'jpg'], max_bytes: 5 * 1024 * 1024 },
38
+ business_logo: { types: ['png', 'jpg'], max_bytes: 512 * 1024 },
39
+ identity_document: { types: ['pdf', 'png', 'jpg'], max_bytes: 10 * 1024 * 1024 },
40
+ additional_verification: { types: ['pdf', 'png', 'jpg'], max_bytes: 10 * 1024 * 1024 },
41
+ });
package/dist/esm/index.js CHANGED
@@ -1,10 +1,15 @@
1
1
  // @peable.to/shared-types — public API for the Peable Gateway contract.
2
- export { UNITS_PER_COIN, isBaseUnitString, CURRENCY_CODES, CURRENCY_DECIMALS, decimalsFor, isCurrencyCode, } from './money.js';
2
+ export { UNITS_PER_COIN, isBaseUnitString, CURRENCY_CODES, CURRENCY_DECIMALS, FIAT_CURRENCY_CODES, decimalsFor, isCurrencyCode, } from './money.js';
3
3
  export { CARD_ONLY_STATUSES, EXPIRABLE_STATUSES, MERCHANT_CANCELLATION_REASONS, PAYMENT_INTENT_CANCELLATION_REASONS, PAYMENT_INTENT_CAPTURE_METHODS, PAYMENT_INTENT_RAILS, PAYMENT_INTENT_SETUP_FUTURE_USAGES, PAYMENT_INTENT_STATUSES, TERMINAL_STATUSES, canExpire, canStillBePaid, isValidStatusTransition, } from './paymentIntent.js';
4
4
  export { SETUP_INTENT_STATUSES, } from './setupIntent.js';
5
5
  export { PEABLE_API_VERSION, } from './event.js';
6
6
  export { WEBHOOK_ENDPOINT_STATUSES, WEBHOOK_ENDPOINT_DISABLED_REASONS, WEBHOOK_ENDPOINTS_MAX_PER_MERCHANT, WEBHOOK_SECRET_ROLL_MAX_EXPIRES_IN_SECONDS, } from './webhookEndpoint.js';
7
7
  export { PRICE_BILLING_SCHEMES, PRICE_TIERS_MODES, PRICE_TYPES, RECURRING_INTERVALS, RECURRING_USAGE_TYPES, PRICE_TAX_BEHAVIORS, TRANSFORM_QUANTITY_ROUNDS, COUPON_DURATIONS, CATALOG_LIMITS, } from './catalog.js';
8
+ export { DISPUTE_FILE_EVIDENCE_FIELDS, DISPUTE_REASONS, DISPUTE_TEXT_EVIDENCE_FIELDS, normalizeDisputeReason, } from './dispute.js';
9
+ export { FILE_PURPOSES, FILE_PURPOSE_POLICIES, FILE_STATUSES, FILE_TYPES, } from './file.js';
10
+ export { CARD_RAIL_PAYMENT_METHOD_TYPES, PAYMENT_METHOD_CONFIGURATION_TYPES, PAYMENT_METHOD_CURRENCIES, } from './paymentMethodConfiguration.js';
11
+ export { REQUEST_LOG_METHODS, REQUEST_LOG_RETENTION_DAYS, } from './requestLog.js';
12
+ export { SIMULATED_FAIRCOIN_OUTCOMES, } from './testHelpers.js';
8
13
  export { signWebhook, verifyWebhook } from './webhookSigner.js';
9
14
  export { MERCHANT_ENVIRONMENTS, } from './merchant.js';
10
15
  export { SOCIAL_SOURCE_APP_MAX_LENGTH, SOCIAL_SOURCE_REF_MAX_LENGTH, } from './social.js';
package/dist/esm/money.js CHANGED
@@ -2,7 +2,11 @@
2
2
  // canonical integer string in the currency's SMALLEST unit — m⊜ for FairCoin,
3
3
  // cents for a fiat currency — so no float ever touches one.
4
4
  /**
5
- * The currencies this gateway can denominate a payment in.
5
+ * The currencies this gateway can denominate a payment in: FairCoin on the
6
+ * chain rail, and on the card rail the fiat set the provider settles for the
7
+ * payment methods Orbit offers (cards, wallets, SEPA Debit, iDEAL, Bancontact,
8
+ * EPS). A local method narrows it further per payment
9
+ * (`PAYMENT_METHOD_CURRENCIES` in `paymentMethodConfiguration.ts`).
6
10
  *
7
11
  * A closed set, and the database mirrors it as a CHECK
8
12
  * (`db/schema/valueSets.ts`). ADR 0001 D4: the scale of an amount is a property
@@ -10,7 +14,21 @@
10
14
  * {@link CURRENCY_DECIMALS} exists and why {@link UNITS_PER_COIN} must never be
11
15
  * used to interpret a fiat amount.
12
16
  */
13
- export const CURRENCY_CODES = ['FAIR', 'EUR', 'USD'];
17
+ export const CURRENCY_CODES = [
18
+ 'FAIR',
19
+ 'EUR',
20
+ 'USD',
21
+ 'GBP',
22
+ 'CHF',
23
+ 'SEK',
24
+ 'NOK',
25
+ 'DKK',
26
+ 'PLN',
27
+ 'CZK',
28
+ 'CAD',
29
+ 'AUD',
30
+ 'JPY',
31
+ ];
14
32
  /** Whether an arbitrary string is a currency this gateway knows. */
15
33
  export function isCurrencyCode(value) {
16
34
  return CURRENCY_CODES.includes(value);
@@ -19,7 +37,7 @@ export function isCurrencyCode(value) {
19
37
  * How many decimal places each currency's smallest unit represents — i.e. an
20
38
  * amount of `1` means `10^-decimals` of one whole unit.
21
39
  *
22
- * FairCoin's 8 is a consensus constant and is pinned against
40
+ * ISO 4217's minor units for every fiat member (JPY has none). FairCoin's 8 is a consensus constant and is pinned against
23
41
  * {@link UNITS_PER_COIN} by this package's own tests, so the two spellings of
24
42
  * one fact cannot drift.
25
43
  */
@@ -27,7 +45,21 @@ export const CURRENCY_DECIMALS = Object.freeze({
27
45
  FAIR: 8,
28
46
  EUR: 2,
29
47
  USD: 2,
48
+ GBP: 2,
49
+ CHF: 2,
50
+ SEK: 2,
51
+ NOK: 2,
52
+ DKK: 2,
53
+ PLN: 2,
54
+ CZK: 2,
55
+ CAD: 2,
56
+ AUD: 2,
57
+ // A zero-decimal currency: an amount of `1` is one yen, never a hundredth of
58
+ // one. The provider counts JPY the same way, so the base unit crosses as is.
59
+ JPY: 0,
30
60
  });
61
+ /** The fiat members — every currency the card rail can denominate a payment in. */
62
+ export const FIAT_CURRENCY_CODES = CURRENCY_CODES.filter((code) => code !== 'FAIR');
31
63
  /** The decimal places of `currency`'s smallest unit. */
32
64
  export function decimalsFor(currency) {
33
65
  return CURRENCY_DECIMALS[currency];
@@ -0,0 +1,51 @@
1
+ // Payment method breadth on the card rail — which methods a merchant's payers
2
+ // are offered (`pmc_…`), and the web domains wallets may run on (`pmd_…`).
3
+ // Both are Orbit's objects; the provider's configuration and domain are
4
+ // bindings behind them (ADR 0016). Card data and bank credentials are entered
5
+ // in the provider's hosted fields and never reach Peable (PCI SAQ-A).
6
+ import { FIAT_CURRENCY_CODES } from './money.js';
7
+ /**
8
+ * The methods a configuration can turn on.
9
+ *
10
+ * `apple_pay` and `google_pay` are WALLETS over a card: a payment made with one
11
+ * is a `card` payment, so they appear here and never in a PaymentIntent's
12
+ * `payment_method_types`. `bizum` is listed because merchants ask for it and the
13
+ * honest answer is a reason, not an absence: the provider does not offer it.
14
+ *
15
+ * Deliberately absent: the provider's own consumer wallet (its brand on Orbit's
16
+ * checkout, `payment-provider-boundary.md`) and giropay (discontinued by the
17
+ * scheme).
18
+ */
19
+ export const PAYMENT_METHOD_CONFIGURATION_TYPES = [
20
+ 'card',
21
+ 'apple_pay',
22
+ 'google_pay',
23
+ 'sepa_debit',
24
+ 'ideal',
25
+ 'bancontact',
26
+ 'eps',
27
+ 'bizum',
28
+ ];
29
+ /** The card-rail types a PaymentIntent can carry in `payment_method_types`. */
30
+ export const CARD_RAIL_PAYMENT_METHOD_TYPES = [
31
+ 'card',
32
+ 'sepa_debit',
33
+ 'ideal',
34
+ 'bancontact',
35
+ 'eps',
36
+ ];
37
+ /**
38
+ * The currencies each method can take a payment in. A method is offered on a
39
+ * payment only when its currency is listed — so iDEAL never appears on a USD
40
+ * payment, and a payer is never shown a method that would fail.
41
+ */
42
+ export const PAYMENT_METHOD_CURRENCIES = Object.freeze({
43
+ card: FIAT_CURRENCY_CODES,
44
+ apple_pay: FIAT_CURRENCY_CODES,
45
+ google_pay: FIAT_CURRENCY_CODES,
46
+ sepa_debit: ['EUR'],
47
+ ideal: ['EUR'],
48
+ bancontact: ['EUR'],
49
+ eps: ['EUR'],
50
+ bizum: ['EUR'],
51
+ });
@@ -0,0 +1,15 @@
1
+ /**
2
+ * One merchant API request, as Peable recorded it (`req_…`) — the request log
3
+ * Orbit and `peable logs tail` read.
4
+ *
5
+ * Its `id` IS the `Request-Id` that request was answered with, so the id a
6
+ * merchant quotes to support and the log row are the same thing.
7
+ *
8
+ * Deliberately thin: method, path (no query string), status, duration and the
9
+ * `Idempotency-Key` it carried. No body, no headers, no query string, no
10
+ * caller address — a log a merchant can read is a log that must not hold what
11
+ * a request carried. Kept 30 days.
12
+ */
13
+ export const REQUEST_LOG_METHODS = ['GET', 'POST', 'DELETE', 'PATCH', 'PUT'];
14
+ /** How long a request log is kept (and served). */
15
+ export const REQUEST_LOG_RETENTION_DAYS = 30;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Test helpers (`/v1/test_helpers/*`) — test mode only.
3
+ *
4
+ * They drive a test-mode object through the SAME state machine a real payment
5
+ * moves through, so a merchant can exercise their integration end to end
6
+ * without a wallet or a card: every transition a helper makes is one the
7
+ * gateway would make, with the same events and webhooks.
8
+ */
9
+ /**
10
+ * What `simulate_faircoin_payment` pretends the payer did.
11
+ *
12
+ * - `settled` — paid the full amount, which is then seen in the mempool and
13
+ * confirmed: `broadcast → confirming → settled`
14
+ * (`payment_intent.confirming`, then `payment_intent.settled`).
15
+ * - `underpaid` — sent less than the amount: `broadcast → failed`
16
+ * (`payment_intent.failed`).
17
+ */
18
+ export const SIMULATED_FAIRCOIN_OUTCOMES = ['settled', 'underpaid'];