@peable.to/shared-types 0.2.0 → 0.3.1-oxy-one.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.
- package/dist/cjs/billing.js +6 -0
- package/dist/cjs/dispute.js +17 -0
- package/dist/cjs/index.js +16 -1
- package/dist/cjs/money.js +48 -8
- package/dist/cjs/paymentIntent.js +185 -9
- package/dist/cjs/settlement.js +2 -0
- package/dist/cjs/social.js +19 -0
- package/dist/esm/billing.js +3 -0
- package/dist/esm/dispute.js +16 -0
- package/dist/esm/index.js +4 -2
- package/dist/esm/money.js +45 -7
- package/dist/esm/package.json +1 -0
- package/dist/esm/paymentIntent.js +182 -8
- package/dist/esm/settlement.js +1 -0
- package/dist/esm/social.js +18 -1
- package/dist/types/billing.d.ts +86 -0
- package/dist/types/checkoutSession.d.ts +12 -3
- package/dist/types/dispute.d.ts +124 -0
- package/dist/types/event.d.ts +122 -9
- package/dist/types/index.d.ts +8 -5
- package/dist/types/merchant.d.ts +21 -2
- package/dist/types/money.d.ts +31 -3
- package/dist/types/paymentIntent.d.ts +75 -8
- package/dist/types/paymentLink.d.ts +19 -4
- package/dist/types/settlement.d.ts +171 -0
- package/dist/types/social.d.ts +110 -0
- package/dist/types/webhookDelivery.d.ts +38 -2
- package/package.json +4 -2
package/dist/types/money.d.ts
CHANGED
|
@@ -1,7 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The currencies this gateway can denominate a payment in.
|
|
3
|
+
*
|
|
4
|
+
* A closed set, and the database mirrors it as a CHECK
|
|
5
|
+
* (`db/schema/valueSets.ts`). ADR 0001 D4: the scale of an amount is a property
|
|
6
|
+
* of its currency and is NOT implied by the field's type, which is why
|
|
7
|
+
* {@link CURRENCY_DECIMALS} exists and why {@link UNITS_PER_COIN} must never be
|
|
8
|
+
* used to interpret a fiat amount.
|
|
9
|
+
*/
|
|
10
|
+
export declare const CURRENCY_CODES: readonly ["FAIR", "EUR", "USD"];
|
|
11
|
+
export type CurrencyCode = (typeof CURRENCY_CODES)[number];
|
|
12
|
+
/** Whether an arbitrary string is a currency this gateway knows. */
|
|
13
|
+
export declare function isCurrencyCode(value: string): value is CurrencyCode;
|
|
14
|
+
/**
|
|
15
|
+
* How many decimal places each currency's smallest unit represents — i.e. an
|
|
16
|
+
* amount of `1` means `10^-decimals` of one whole unit.
|
|
17
|
+
*
|
|
18
|
+
* FairCoin's 8 is a consensus constant and is pinned against
|
|
19
|
+
* {@link UNITS_PER_COIN} by this package's own tests, so the two spellings of
|
|
20
|
+
* one fact cannot drift.
|
|
21
|
+
*/
|
|
22
|
+
export declare const CURRENCY_DECIMALS: Readonly<Record<CurrencyCode, number>>;
|
|
23
|
+
/** The decimal places of `currency`'s smallest unit. */
|
|
24
|
+
export declare function decimalsFor(currency: CurrencyCode): number;
|
|
1
25
|
export declare const UNITS_PER_COIN = 100000000n;
|
|
2
26
|
/**
|
|
3
|
-
* True only for a canonical non-negative integer string in
|
|
4
|
-
* one or more decimal digits, no sign, no decimal point, no
|
|
5
|
-
* (except the literal "0"). Floats and negatives are rejected.
|
|
27
|
+
* True only for a canonical non-negative integer string in the currency's
|
|
28
|
+
* smallest unit: one or more decimal digits, no sign, no decimal point, no
|
|
29
|
+
* leading zeros (except the literal "0"). Floats and negatives are rejected.
|
|
30
|
+
*
|
|
31
|
+
* Currency-agnostic on purpose — the pattern is about the SPELLING of an
|
|
32
|
+
* amount, not its scale, and the same one is restated as a CHECK in the
|
|
33
|
+
* database (`BASE_UNIT_STRING_PATTERN`), byte-identical.
|
|
6
34
|
*/
|
|
7
35
|
export declare function isBaseUnitString(s: string): boolean;
|
|
@@ -1,21 +1,80 @@
|
|
|
1
|
+
import type { CurrencyCode } from './money';
|
|
1
2
|
import type { NetworkType } from './network';
|
|
2
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Which rail moves the money (ADR 0001 D1).
|
|
5
|
+
*
|
|
6
|
+
* On the INTENT, not on the merchant: one merchant takes both, and a merchant's
|
|
7
|
+
* capabilities are a different question from what this particular payment is.
|
|
8
|
+
* The rail decides which of the fields below mean anything.
|
|
9
|
+
*/
|
|
10
|
+
export type PaymentIntentRail = 'faircoin' | 'card';
|
|
11
|
+
/** {@link PaymentIntentRail} as the tuple the database CHECK reads. */
|
|
12
|
+
export declare const PAYMENT_INTENT_RAILS: readonly PaymentIntentRail[];
|
|
13
|
+
export type PaymentIntentStatus = 'created' | 'awaiting_approval' | 'approved' | 'broadcast' | 'confirming' | 'requires_action' | 'processing' | 'settled' | 'refunded' | 'partially_refunded' | 'expired' | 'failed' | 'rejected';
|
|
14
|
+
/**
|
|
15
|
+
* Which statuses belong to which rail (ADR 0001 D5).
|
|
16
|
+
*
|
|
17
|
+
* The four chain states describe a transaction on a blockchain and the four
|
|
18
|
+
* card states describe an authorization at a card acquirer; neither set is
|
|
19
|
+
* expressible on the other rail. Mapping a card authorization onto `broadcast`
|
|
20
|
+
* would be cheaper and would be a lie — nothing was broadcast, there is no
|
|
21
|
+
* transaction, and `payment_intents_broadcast_requires_txid_check` would then
|
|
22
|
+
* be demanding a txid from a payment that can never have one.
|
|
23
|
+
*
|
|
24
|
+
* `db/schema/payments.ts` renders these two sets into CHECK constraints, so the
|
|
25
|
+
* restriction holds against a write that skipped the application.
|
|
26
|
+
*/
|
|
27
|
+
export declare const CHAIN_ONLY_STATUSES: readonly PaymentIntentStatus[];
|
|
28
|
+
export declare const CARD_ONLY_STATUSES: readonly PaymentIntentStatus[];
|
|
3
29
|
export declare function isValidStatusTransition(from: PaymentIntentStatus, to: PaymentIntentStatus): boolean;
|
|
4
30
|
/** Every legal `PaymentIntentStatus`, derived from `ALLOWED`'s keys — the
|
|
5
31
|
* single source of truth consumed by the Gateway's list-route status filter. */
|
|
6
32
|
export declare const PAYMENT_INTENT_STATUSES: readonly PaymentIntentStatus[];
|
|
33
|
+
/**
|
|
34
|
+
* Whether a payer can still complete a payment against an intent in this
|
|
35
|
+
* status.
|
|
36
|
+
*
|
|
37
|
+
* `settled` answers `false`: it is where paying ENDS. `partially_refunded`
|
|
38
|
+
* answers `false` too — money can still move, but not from the payer.
|
|
39
|
+
*/
|
|
40
|
+
export declare function canStillBePaid(status: PaymentIntentStatus): boolean;
|
|
41
|
+
/**
|
|
42
|
+
* The statuses a payment reaches only AFTER the payer has finished.
|
|
43
|
+
*
|
|
44
|
+
* Exported for the gate below rather than for production use: the property that
|
|
45
|
+
* makes `PAYABLE_STATUSES` checkable is that a payable status reaches `settled`
|
|
46
|
+
* without going through one of these.
|
|
47
|
+
*/
|
|
48
|
+
export declare const POST_SETTLEMENT_STATUSES: readonly PaymentIntentStatus[];
|
|
49
|
+
/**
|
|
50
|
+
* Whether `settled` is reachable from `status` without passing through a
|
|
51
|
+
* post-settlement status. The derivation `canStillBePaid` used to BE, kept as
|
|
52
|
+
* the thing that checks it rather than as the thing that answers it.
|
|
53
|
+
*/
|
|
54
|
+
export declare function reachesSettlementFromPayer(status: PaymentIntentStatus): boolean;
|
|
7
55
|
export interface PaymentIntent {
|
|
8
56
|
id: string;
|
|
9
57
|
object: 'payment_intent';
|
|
10
58
|
status: PaymentIntentStatus;
|
|
11
|
-
/**
|
|
59
|
+
/** Which rail moves this payment. Decides which fields below are populated. */
|
|
60
|
+
rail: PaymentIntentRail;
|
|
61
|
+
/**
|
|
62
|
+
* Amount in the currency's SMALLEST unit as a canonical integer string.
|
|
63
|
+
* Never a float, and never interpretable without `currency`: m⊜ (10^-8 FAIR)
|
|
64
|
+
* on the faircoin rail, cents on a fiat one.
|
|
65
|
+
*/
|
|
12
66
|
amount: string;
|
|
13
|
-
currency:
|
|
14
|
-
network
|
|
15
|
-
|
|
16
|
-
|
|
67
|
+
currency: CurrencyCode;
|
|
68
|
+
/** FairCoin rail only. `null` on a card payment, which has no network. */
|
|
69
|
+
network: NetworkType | null;
|
|
70
|
+
/**
|
|
71
|
+
* Watch-only receive address derived per-intent from the merchant xpub.
|
|
72
|
+
* FairCoin rail only; `null` on a card payment, which reserves no address.
|
|
73
|
+
*/
|
|
74
|
+
address: string | null;
|
|
17
75
|
merchantId: string;
|
|
18
76
|
txid: string | null;
|
|
77
|
+
/** On-chain confirmations. Structurally `0` for the whole life of a card payment. */
|
|
19
78
|
confirmations: number;
|
|
20
79
|
clientSecret: string;
|
|
21
80
|
metadata: Record<string, string>;
|
|
@@ -24,9 +83,17 @@ export interface PaymentIntent {
|
|
|
24
83
|
updatedAt: string;
|
|
25
84
|
}
|
|
26
85
|
export interface CreatePaymentIntentParams {
|
|
27
|
-
/** Amount in
|
|
86
|
+
/** Amount in the currency's smallest unit, as a canonical integer string. */
|
|
28
87
|
amount: string;
|
|
29
|
-
|
|
88
|
+
/**
|
|
89
|
+
* Defaults to `'faircoin'` — the rail this gateway shipped with, so every
|
|
90
|
+
* integration written before ADR 0001 keeps working unchanged.
|
|
91
|
+
*/
|
|
92
|
+
rail?: PaymentIntentRail;
|
|
93
|
+
/** Required on the faircoin rail; refused on the card rail, which has none. */
|
|
94
|
+
network?: NetworkType;
|
|
95
|
+
/** Defaults to `'FAIR'` on the faircoin rail; required on the card rail. */
|
|
96
|
+
currency?: CurrencyCode;
|
|
30
97
|
metadata?: Record<string, string>;
|
|
31
98
|
expiresInSeconds?: number;
|
|
32
99
|
}
|
|
@@ -1,12 +1,20 @@
|
|
|
1
|
+
import type { CurrencyCode } from './money';
|
|
1
2
|
import type { NetworkType } from './network';
|
|
2
3
|
import type { MerchantDisplay } from './merchantDisplay';
|
|
4
|
+
import type { PaymentIntentRail } from './paymentIntent';
|
|
3
5
|
/** The merchant-facing DTO — returned by the merchant-authed CRUD routes. */
|
|
4
6
|
export interface PaymentLink {
|
|
5
7
|
id: string;
|
|
6
8
|
object: 'payment_link';
|
|
7
|
-
/**
|
|
9
|
+
/**
|
|
10
|
+
* Amount in the currency's smallest unit, as a canonical integer string.
|
|
11
|
+
* Never a float, and never interpretable without `currency`.
|
|
12
|
+
*/
|
|
8
13
|
amount: string;
|
|
9
|
-
|
|
14
|
+
currency: CurrencyCode;
|
|
15
|
+
rail: PaymentIntentRail;
|
|
16
|
+
/** FairCoin rail only; `null` on a card link. */
|
|
17
|
+
network: NetworkType | null;
|
|
10
18
|
active: boolean;
|
|
11
19
|
metadata: Record<string, string>;
|
|
12
20
|
/** Optional post-payment redirect target for the checkout page. */
|
|
@@ -21,13 +29,20 @@ export interface PublicPaymentLink {
|
|
|
21
29
|
id: string;
|
|
22
30
|
object: 'payment_link';
|
|
23
31
|
amount: string;
|
|
24
|
-
|
|
32
|
+
currency: CurrencyCode;
|
|
33
|
+
rail: PaymentIntentRail;
|
|
34
|
+
network: NetworkType | null;
|
|
25
35
|
active: boolean;
|
|
26
36
|
merchant: MerchantDisplay;
|
|
27
37
|
}
|
|
28
38
|
export interface CreatePaymentLinkParams {
|
|
29
39
|
amount: string;
|
|
30
|
-
|
|
40
|
+
/** Defaults to `'faircoin'`, so pre-ADR-0001 integrations keep working. */
|
|
41
|
+
rail?: PaymentIntentRail;
|
|
42
|
+
/** Required on the faircoin rail; refused on the card rail. */
|
|
43
|
+
network?: NetworkType;
|
|
44
|
+
/** Defaults to `'FAIR'` on the faircoin rail; required on the card rail. */
|
|
45
|
+
currency?: CurrencyCode;
|
|
31
46
|
metadata?: Record<string, string>;
|
|
32
47
|
successUrl?: string;
|
|
33
48
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import type { CurrencyCode } from './money';
|
|
2
|
+
/** How a provider reports one capability on a seller's account. */
|
|
3
|
+
export type CapabilityStatus = 'active' | 'pending' | 'inactive';
|
|
4
|
+
/** Where one settlement stands. */
|
|
5
|
+
export type TransferStatus = 'pending' | 'paid' | 'partially_reversed' | 'reversed' | 'failed';
|
|
6
|
+
/** Where one reversal of a settlement stands. */
|
|
7
|
+
export type TransferReversalStatus = 'pending' | 'succeeded' | 'failed';
|
|
8
|
+
export interface ConnectedAccount {
|
|
9
|
+
id: string;
|
|
10
|
+
object: 'connected_account';
|
|
11
|
+
/** The merchant's OWN id for this seller — how they address it. */
|
|
12
|
+
externalRef: string;
|
|
13
|
+
/** ISO 3166-1 alpha-2, upper-case. */
|
|
14
|
+
country: string;
|
|
15
|
+
defaultCurrency: string | null;
|
|
16
|
+
/**
|
|
17
|
+
* Whether this seller can receive a settlement right now.
|
|
18
|
+
*
|
|
19
|
+
* A CONVENIENCE, not the authority: every field it is derived from is here
|
|
20
|
+
* too, and a marketplace with its own readiness policy reads those instead.
|
|
21
|
+
* Offering only this boolean would make the gateway the authority on a
|
|
22
|
+
* question that belongs to the merchant.
|
|
23
|
+
*/
|
|
24
|
+
payable: boolean;
|
|
25
|
+
payoutsEnabled: boolean;
|
|
26
|
+
chargesEnabled: boolean;
|
|
27
|
+
/**
|
|
28
|
+
* `null` means the capability was never REQUESTED, which is a different fact
|
|
29
|
+
* from the provider declining it (`inactive`). Collapsing the two makes "why
|
|
30
|
+
* is this seller stuck" unanswerable.
|
|
31
|
+
*/
|
|
32
|
+
transfersCapability: CapabilityStatus | null;
|
|
33
|
+
cardPaymentsCapability: CapabilityStatus | null;
|
|
34
|
+
/**
|
|
35
|
+
* COUNTS of outstanding requirements, never the requirements themselves and
|
|
36
|
+
* never their values. The gateway records that a seller owes a document; it
|
|
37
|
+
* does not learn what the document says.
|
|
38
|
+
*/
|
|
39
|
+
requirements: {
|
|
40
|
+
currentlyDue: number;
|
|
41
|
+
eventuallyDue: number;
|
|
42
|
+
pastDue: number;
|
|
43
|
+
pendingVerification: number;
|
|
44
|
+
};
|
|
45
|
+
disabledReasonCodes: readonly string[];
|
|
46
|
+
lastSyncedAt: string | null;
|
|
47
|
+
createdAt: string;
|
|
48
|
+
updatedAt: string;
|
|
49
|
+
}
|
|
50
|
+
export interface Transfer {
|
|
51
|
+
id: string;
|
|
52
|
+
object: 'transfer';
|
|
53
|
+
/** The merchant's OWN id for what this settles. Their idempotency. */
|
|
54
|
+
externalRef: string;
|
|
55
|
+
/** The `ca_…` of the seller — never their account id at the provider. */
|
|
56
|
+
connectedAccountId: string;
|
|
57
|
+
/** The `pi_…` this settlement was funded by — never an internal primary key. */
|
|
58
|
+
paymentIntentId: string;
|
|
59
|
+
amount: string;
|
|
60
|
+
currency: string;
|
|
61
|
+
/**
|
|
62
|
+
* CUMULATIVE, in the same units as `amount` — never one reversal's figure.
|
|
63
|
+
*
|
|
64
|
+
* A caller deciding whether a settlement is fully reversed must not have to
|
|
65
|
+
* add up reversals it may not have all seen, which is why this is the
|
|
66
|
+
* provider's own total rather than a sum of the reversals below.
|
|
67
|
+
*/
|
|
68
|
+
amountReversed: string;
|
|
69
|
+
status: TransferStatus;
|
|
70
|
+
failureMessage: string | null;
|
|
71
|
+
createdAt: string;
|
|
72
|
+
updatedAt: string;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* One reversal operation, returned beside the settlement it acted on.
|
|
76
|
+
*
|
|
77
|
+
* It exists as an object because an AMOUNT IS NOT AN IDENTITY: two reversals of
|
|
78
|
+
* one settlement for the same amount are two operations, and a caller needs to
|
|
79
|
+
* be able to tell which one a response is about.
|
|
80
|
+
*/
|
|
81
|
+
export interface TransferReversal {
|
|
82
|
+
id: string;
|
|
83
|
+
object: 'transfer_reversal';
|
|
84
|
+
/** The merchant's own id for this reversal — their `Idempotency-Key`. */
|
|
85
|
+
externalRef: string;
|
|
86
|
+
amount: string;
|
|
87
|
+
currency: string;
|
|
88
|
+
status: TransferReversalStatus;
|
|
89
|
+
failureMessage: string | null;
|
|
90
|
+
createdAt: string;
|
|
91
|
+
}
|
|
92
|
+
/** What `POST /v1/transfers/:id/reversals` answers: the transfer, and the leg. */
|
|
93
|
+
export interface TransferWithReversal extends Transfer {
|
|
94
|
+
reversal: TransferReversal;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* What a payment actually came to, as the PROVIDER reports it.
|
|
98
|
+
*
|
|
99
|
+
* ## Every figure is nullable, and that is the contract
|
|
100
|
+
*
|
|
101
|
+
* The difference between "the fee was zero" and "the fee is not known yet" is
|
|
102
|
+
* the whole reason this shape exists. A report that renders an unknown as `0`
|
|
103
|
+
* is one a merchant reconciles against and cannot explain — and zero is a
|
|
104
|
+
* number somebody will subtract. `status` says which of the three situations
|
|
105
|
+
* produced the nulls.
|
|
106
|
+
*
|
|
107
|
+
* ## What it does NOT say
|
|
108
|
+
*
|
|
109
|
+
* It reports what the provider took. It does **not** attribute that cost to an
|
|
110
|
+
* entity: a fee paid by the operator of a Peable deployment is not
|
|
111
|
+
* automatically an expense of the marketplace running on it, and that is a
|
|
112
|
+
* commercial decision no contract can make. Nothing here implies one.
|
|
113
|
+
*
|
|
114
|
+
* `gross` is not the payment's `amount`: a partial capture, a refund or a
|
|
115
|
+
* currency conversion all make them differ, which is why it is reported rather
|
|
116
|
+
* than assumed.
|
|
117
|
+
*/
|
|
118
|
+
export interface Settlement {
|
|
119
|
+
object: 'settlement';
|
|
120
|
+
/** The `pi_…` this describes. */
|
|
121
|
+
paymentIntentId: string;
|
|
122
|
+
/**
|
|
123
|
+
* - `available` — settled; these figures are final.
|
|
124
|
+
* - `pending` — a settlement record exists and is not final yet.
|
|
125
|
+
* - `unknown` — there is none to read. **Not zero.**
|
|
126
|
+
*/
|
|
127
|
+
status: 'available' | 'pending' | 'unknown';
|
|
128
|
+
/** Minor units, as canonical integer strings, in `currency`. */
|
|
129
|
+
gross: string | null;
|
|
130
|
+
fee: string | null;
|
|
131
|
+
net: string | null;
|
|
132
|
+
/** The SETTLEMENT currency, which may differ from the payment's. */
|
|
133
|
+
currency: string | null;
|
|
134
|
+
/** When the funds become available, ISO-8601. */
|
|
135
|
+
availableOn: string | null;
|
|
136
|
+
/** Present only when a conversion happened. `null` is not a rate of 1. */
|
|
137
|
+
exchangeRate: number | null;
|
|
138
|
+
}
|
|
139
|
+
/** Where one refund stands — the MONEY's own lifecycle, not the payment's. */
|
|
140
|
+
export type RefundStatus = 'pending' | 'succeeded' | 'failed';
|
|
141
|
+
/**
|
|
142
|
+
* Who created a refund.
|
|
143
|
+
*
|
|
144
|
+
* `provider` means it appeared at the acquirer — a dashboard refund, or the
|
|
145
|
+
* network resolving a dispute — and was imported. Such a refund carries no
|
|
146
|
+
* `externalRef`, because the merchant did not make it and has no id for it.
|
|
147
|
+
*/
|
|
148
|
+
export type RefundOrigin = 'merchant' | 'provider';
|
|
149
|
+
export interface Refund {
|
|
150
|
+
id: string;
|
|
151
|
+
object: 'refund';
|
|
152
|
+
/** `null` on an IMPORTED refund; see {@link RefundOrigin}. */
|
|
153
|
+
externalRef: string | null;
|
|
154
|
+
origin: RefundOrigin;
|
|
155
|
+
paymentIntentId: string;
|
|
156
|
+
amount: string;
|
|
157
|
+
currency: CurrencyCode | string;
|
|
158
|
+
status: RefundStatus;
|
|
159
|
+
/**
|
|
160
|
+
* Where the PAYMENT stands after this refund.
|
|
161
|
+
*
|
|
162
|
+
* On the refund deliberately: a caller that has just refunded needs to know
|
|
163
|
+
* whether the payment is now `partially_refunded` or `refunded`, and making
|
|
164
|
+
* them re-read the intent is a round trip whose answer can move on before it
|
|
165
|
+
* arrives.
|
|
166
|
+
*/
|
|
167
|
+
paymentStatus: string;
|
|
168
|
+
failureCode: string | null;
|
|
169
|
+
createdAt: string;
|
|
170
|
+
updatedAt: string;
|
|
171
|
+
}
|
package/dist/types/social.d.ts
CHANGED
|
@@ -1,3 +1,59 @@
|
|
|
1
|
+
import type { NetworkType } from './network';
|
|
2
|
+
/**
|
|
3
|
+
* Longest `SocialPaymentSource.app` the gateway accepts. An app slug, not a
|
|
4
|
+
* label — 32 characters is more than any Oxy app id needs and short enough that
|
|
5
|
+
* the column can never become a place to put prose.
|
|
6
|
+
*
|
|
7
|
+
* Published with the contract because it is what a request is REFUSED for: a
|
|
8
|
+
* caller that cannot read the bound from the types finds it out with a 422.
|
|
9
|
+
*/
|
|
10
|
+
export declare const SOCIAL_SOURCE_APP_MAX_LENGTH = 32;
|
|
11
|
+
/**
|
|
12
|
+
* Longest `SocialPaymentSource.ref` the gateway accepts.
|
|
13
|
+
*
|
|
14
|
+
* The bound is the whole defence here, because the value is opaque: Peable
|
|
15
|
+
* never parses, resolves or links a `ref`, so nothing downstream would notice
|
|
16
|
+
* it growing. 128 characters holds any id an app mints (a uuid, a snowflake, a
|
|
17
|
+
* base64 hash) and refuses a payload.
|
|
18
|
+
*/
|
|
19
|
+
export declare const SOCIAL_SOURCE_REF_MAX_LENGTH = 128;
|
|
20
|
+
/**
|
|
21
|
+
* Display-only context for one social payment: which app the payer was in, and
|
|
22
|
+
* that app's own id for what the payment was for (a Mention post, say).
|
|
23
|
+
*
|
|
24
|
+
* **Opaque to Peable, by design.** `ref` is never parsed, resolved, joined or
|
|
25
|
+
* shown to anyone but the two parties — the gateway stores a string and hands
|
|
26
|
+
* the same string back. That is what keeps "tip a post" from widening what the
|
|
27
|
+
* payment gateway knows about a user: it learns that an id exists, not what it
|
|
28
|
+
* names. The app that minted the `ref` is the only thing that can resolve it,
|
|
29
|
+
* and it already knows.
|
|
30
|
+
*
|
|
31
|
+
* It affects NOTHING about the money. The address a payer is shown comes from
|
|
32
|
+
* the recipient's identity key and the reservation cursor, neither of which
|
|
33
|
+
* this is an input to; a request carrying a source and one carrying none
|
|
34
|
+
* reserve the same index.
|
|
35
|
+
*/
|
|
36
|
+
export interface SocialPaymentSource {
|
|
37
|
+
/** The calling app, e.g. `'mention'`. At most {@link SOCIAL_SOURCE_APP_MAX_LENGTH} characters. */
|
|
38
|
+
app: string;
|
|
39
|
+
/**
|
|
40
|
+
* That app's own opaque id for what the payment was for, e.g. a post id. At
|
|
41
|
+
* most {@link SOCIAL_SOURCE_REF_MAX_LENGTH} characters. Absent when the app
|
|
42
|
+
* has no single thing to name.
|
|
43
|
+
*/
|
|
44
|
+
ref?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Body of `POST /v1/social/:username/next_address` (spec §4.4 step 3).
|
|
48
|
+
*
|
|
49
|
+
* `source` is OPTIONAL and stays that way: a plain person-to-person payment is
|
|
50
|
+
* for nothing in particular, and a required field would make every caller
|
|
51
|
+
* invent an answer.
|
|
52
|
+
*/
|
|
53
|
+
export interface SocialNextAddressRequest {
|
|
54
|
+
network: NetworkType;
|
|
55
|
+
source?: SocialPaymentSource;
|
|
56
|
+
}
|
|
1
57
|
/** Response of `POST /v1/social/:username/next_address` (spec §4.4 step 3). */
|
|
2
58
|
export interface SocialNextAddressResponse {
|
|
3
59
|
address: string;
|
|
@@ -23,6 +79,16 @@ export interface SocialReceiveCursorResponse {
|
|
|
23
79
|
* caller's stable default address and is never reserved through this flow.
|
|
24
80
|
*/
|
|
25
81
|
reservedThrough: number;
|
|
82
|
+
/**
|
|
83
|
+
* The identity public key (hex) those addresses were derived from, as the
|
|
84
|
+
* backend saw it. A device compares it with the key it derives from itself:
|
|
85
|
+
* if they differ, its watch window is in the wrong tree and widening it only
|
|
86
|
+
* watches more addresses nobody is paying into.
|
|
87
|
+
*
|
|
88
|
+
* `null` means exactly one thing: this caller has no cursor, so no address
|
|
89
|
+
* has ever been reserved for them. Every cursor that exists names its key.
|
|
90
|
+
*/
|
|
91
|
+
identityPublicKey: string | null;
|
|
26
92
|
}
|
|
27
93
|
/** Where a transaction's counterparty identity came from (spec §4.8). */
|
|
28
94
|
export type EnrichmentKind = 'merchant' | 'user' | 'unknown';
|
|
@@ -48,3 +114,47 @@ export interface EnrichRequest {
|
|
|
48
114
|
export interface EnrichResponse {
|
|
49
115
|
data: Record<string, EnrichmentResult>;
|
|
50
116
|
}
|
|
117
|
+
/** Which side of a social payment the caller was on. */
|
|
118
|
+
export type SocialPaymentDirection = 'sent' | 'received';
|
|
119
|
+
/**
|
|
120
|
+
* One social payment as the CALLER saw it, for `GET /v1/social/me/payments`.
|
|
121
|
+
*
|
|
122
|
+
* The address-free view, and the only payment history a surface without a key
|
|
123
|
+
* can ask for: deriving addresses needs a seed, so a browser cannot use the
|
|
124
|
+
* address-list endpoints (`POST /v1/enrich`, the cursor) at all. `direction` is
|
|
125
|
+
* the field that cannot be recovered from the address alone — the backend knows
|
|
126
|
+
* it because the attribution names both parties, and resolving it here is what
|
|
127
|
+
* keeps the caller from having to learn its own user id to compare against.
|
|
128
|
+
*
|
|
129
|
+
* Carries NO amount. An attribution records which address was minted for a
|
|
130
|
+
* payment relationship, not what was paid; the amount lives on-chain, and the
|
|
131
|
+
* client reads it from the Explorer against `address`.
|
|
132
|
+
*/
|
|
133
|
+
export interface SocialPayment {
|
|
134
|
+
/** The single-use social-receive address minted for this payment. */
|
|
135
|
+
address: string;
|
|
136
|
+
direction: SocialPaymentDirection;
|
|
137
|
+
/**
|
|
138
|
+
* The other party. Reuses the enrichment contract, including its degradation:
|
|
139
|
+
* a failed identity lookup answers `{ kind: 'unknown' }` rather than dropping
|
|
140
|
+
* the payment, so a history never silently loses rows to an Oxy outage.
|
|
141
|
+
*/
|
|
142
|
+
counterparty: EnrichmentResult;
|
|
143
|
+
/**
|
|
144
|
+
* What the payment was for, as the paying app named it at reservation time.
|
|
145
|
+
* Absent for a plain person-to-person payment, which is most of them —
|
|
146
|
+
* present only when the payer's app sent one, and never invented here.
|
|
147
|
+
*
|
|
148
|
+
* Display-only, exactly like `counterparty`: rendering it is all a client may
|
|
149
|
+
* do with it, and a client that cannot resolve `source.ref` (because it is
|
|
150
|
+
* not the app that minted it) shows the payment without the context rather
|
|
151
|
+
* than dropping the payment.
|
|
152
|
+
*/
|
|
153
|
+
source?: SocialPaymentSource;
|
|
154
|
+
/** ISO-8601. When the address was minted, which is when the payment was set up. */
|
|
155
|
+
createdAt: string;
|
|
156
|
+
}
|
|
157
|
+
/** Response of `GET /v1/social/me/payments`, newest first. */
|
|
158
|
+
export interface SocialPaymentsResponse {
|
|
159
|
+
payments: SocialPayment[];
|
|
160
|
+
}
|
|
@@ -1,15 +1,51 @@
|
|
|
1
1
|
import type { WebhookEventType } from './event';
|
|
2
|
+
/**
|
|
3
|
+
* Where one webhook delivery stands (ADR 0001 D7).
|
|
4
|
+
*
|
|
5
|
+
* Was `'delivered' | 'failed'` — the two outcomes an inline, best-effort
|
|
6
|
+
* delivery could report once it had already given up. Delivery is now a durable
|
|
7
|
+
* outbox, so a delivery exists BEFORE any attempt and this set has to say so.
|
|
8
|
+
*
|
|
9
|
+
* - `pending` — enqueued and will be attempted. `nextAttemptAt` says when.
|
|
10
|
+
* - `delivered` — terminal success.
|
|
11
|
+
* - `failed` — the endpoint REFUSED it (a 4xx, a blocked address). No retry
|
|
12
|
+
* can fix that, so none is made.
|
|
13
|
+
* - `dead` — every attempt failed transiently and the budget ran out. The
|
|
14
|
+
* envelope is kept and can be redelivered by hand.
|
|
15
|
+
*
|
|
16
|
+
* ⚠️ Widening a published union is a breaking change for a consumer that
|
|
17
|
+
* switches exhaustively on it. It is the honest shape: the previous one could
|
|
18
|
+
* not describe a delivery that had not been attempted yet, which is now the
|
|
19
|
+
* state every delivery starts in.
|
|
20
|
+
*/
|
|
21
|
+
export type WebhookDeliveryStatus = 'pending' | 'delivered' | 'failed' | 'dead';
|
|
2
22
|
export interface WebhookDelivery {
|
|
3
23
|
id: string;
|
|
4
24
|
object: 'webhook_delivery';
|
|
5
25
|
merchantId: string;
|
|
6
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The `pi_…` this delivery is about — `null` when the event is not about a
|
|
28
|
+
* payment.
|
|
29
|
+
*
|
|
30
|
+
* Nullable since `connected_account.updated`, which is about a SELLER. The
|
|
31
|
+
* alternative was to name an unrelated payment to keep the field a string,
|
|
32
|
+
* which is worse than a null: a consumer correlating on it would attach a
|
|
33
|
+
* seller's readiness change to a payment that has nothing to do with it.
|
|
34
|
+
*/
|
|
35
|
+
intentId: string | null;
|
|
7
36
|
eventId: string;
|
|
8
37
|
eventType: WebhookEventType;
|
|
9
38
|
url: string;
|
|
10
39
|
attempts: number;
|
|
11
40
|
delivered: boolean;
|
|
12
|
-
lastStatus:
|
|
41
|
+
lastStatus: WebhookDeliveryStatus;
|
|
42
|
+
/**
|
|
43
|
+
* Why the last attempt did not succeed — operator-facing, never a secret.
|
|
44
|
+
* Absent while pending with no attempts, and after a success.
|
|
45
|
+
*/
|
|
46
|
+
lastError?: string;
|
|
47
|
+
/** When the next attempt is due, ISO-8601. Absent once the delivery is terminal. */
|
|
48
|
+
nextAttemptAt?: string;
|
|
13
49
|
createdAt: string;
|
|
14
50
|
updatedAt: string;
|
|
15
51
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@peable.to/shared-types",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.1-oxy-one.0",
|
|
4
4
|
"description": "Shared TypeScript types for the Peable Gateway — the wire contract shared by the backend, SDK, and frontend.",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
"source": "src/index.ts",
|
|
9
9
|
"sideEffects": false,
|
|
10
10
|
"publishConfig": {
|
|
11
|
-
"access": "public"
|
|
11
|
+
"access": "public",
|
|
12
|
+
"registry": "https://registry.npmjs.org/",
|
|
13
|
+
"tag": "oxy-one"
|
|
12
14
|
},
|
|
13
15
|
"exports": {
|
|
14
16
|
".": {
|