@revstackhq/providers-core 0.2.0 → 0.3.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/index.d.ts +222 -193
- package/dist/index.js +76 -9
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -16,16 +16,19 @@ interface ProviderContext {
|
|
|
16
16
|
* Indicates if the operation is running in Sandbox/Test mode.
|
|
17
17
|
*/
|
|
18
18
|
isTestMode: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Optional: Idempotency key for duplicate request prevention.
|
|
21
|
+
*/
|
|
22
|
+
idempotencyKey?: string;
|
|
19
23
|
}
|
|
20
24
|
|
|
21
25
|
/**
|
|
22
|
-
* src/types/models.ts
|
|
23
26
|
* * Normalized data models for the Revstack ecosystem.
|
|
24
27
|
* These types represent the "Internal Source of Truth" for the OS.
|
|
25
28
|
*/
|
|
26
29
|
declare enum PaymentStatus {
|
|
27
30
|
Pending = "pending",
|
|
28
|
-
Authorized = "authorized",// Funds held but not captured
|
|
31
|
+
Authorized = "authorized",// Funds held but not captured yet
|
|
29
32
|
Succeeded = "succeeded",
|
|
30
33
|
Failed = "failed",
|
|
31
34
|
Refunded = "refunded",
|
|
@@ -38,68 +41,59 @@ type PaymentMethodDetails = {
|
|
|
38
41
|
brand?: string;
|
|
39
42
|
last4?: string;
|
|
40
43
|
email?: string;
|
|
44
|
+
expiryMonth?: number;
|
|
45
|
+
expiryYear?: number;
|
|
46
|
+
cardHolderName?: string;
|
|
41
47
|
};
|
|
42
48
|
type Payment = {
|
|
43
|
-
/** Unique ID in Revstack (UUID) */
|
|
44
49
|
id: string;
|
|
45
|
-
/** The slug of the provider (e.g., 'stripe') */
|
|
46
50
|
providerId: string;
|
|
47
|
-
/** The ID generated by the provider (e.g., 'pi_12345') */
|
|
48
51
|
externalId: string;
|
|
49
|
-
/** Total amount in lowest currency unit (e.g., cents) */
|
|
50
52
|
amount: number;
|
|
51
|
-
/**
|
|
53
|
+
/** * Financial breakdown, vital for invoicing and tax calculation.
|
|
54
|
+
*/
|
|
55
|
+
amountDetails?: {
|
|
56
|
+
subtotal: number;
|
|
57
|
+
tax: number;
|
|
58
|
+
shipping: number;
|
|
59
|
+
discount: number;
|
|
60
|
+
fee?: number;
|
|
61
|
+
};
|
|
52
62
|
amountRefunded: number;
|
|
53
|
-
/** ISO 4217 Currency Code (e.g., 'USD') */
|
|
54
63
|
currency: string;
|
|
55
64
|
status: PaymentStatus;
|
|
56
65
|
method?: PaymentMethodDetails;
|
|
57
66
|
description?: string;
|
|
58
|
-
/** Revstack internal Customer ID */
|
|
59
67
|
customerId?: string;
|
|
60
|
-
/** Provider-specific Customer ID (e.g., 'cus_999') */
|
|
61
68
|
externalCustomerId?: string;
|
|
62
|
-
/** * The fee charged by the provider for this transaction.
|
|
63
|
-
* Crucial for Net Revenue calculations.
|
|
64
|
-
*/
|
|
65
|
-
fee?: number;
|
|
66
|
-
/** ISO Date String */
|
|
67
69
|
createdAt: string;
|
|
68
|
-
/** ISO Date String */
|
|
69
70
|
updatedAt?: string;
|
|
70
71
|
metadata?: Record<string, any>;
|
|
71
|
-
/** Optional: The raw object from the provider for debugging/audit */
|
|
72
72
|
raw?: any;
|
|
73
73
|
};
|
|
74
74
|
declare enum SubscriptionStatus {
|
|
75
75
|
Trialing = "trialing",
|
|
76
76
|
Active = "active",
|
|
77
|
-
PastDue = "past_due"
|
|
77
|
+
PastDue = "past_due",
|
|
78
78
|
Canceled = "canceled",
|
|
79
|
-
Unpaid = "unpaid"
|
|
80
|
-
Incomplete = "incomplete"
|
|
79
|
+
Unpaid = "unpaid",
|
|
80
|
+
Incomplete = "incomplete",
|
|
81
81
|
IncompleteExpired = "incomplete_expired",
|
|
82
82
|
Paused = "paused"
|
|
83
83
|
}
|
|
84
|
-
type SubscriptionInterval = "day" | "week" | "month" | "year";
|
|
85
84
|
type Subscription = {
|
|
86
85
|
id: string;
|
|
87
86
|
providerId: string;
|
|
88
87
|
externalId: string;
|
|
89
88
|
status: SubscriptionStatus;
|
|
90
|
-
/** Internal Plan ID */
|
|
91
89
|
planId?: string;
|
|
92
|
-
/** Provider Plan/Price ID (e.g., 'price_Hk123') */
|
|
93
90
|
externalPlanId?: string;
|
|
94
91
|
amount: number;
|
|
95
92
|
currency: string;
|
|
96
|
-
interval:
|
|
93
|
+
interval: "day" | "week" | "month" | "year";
|
|
97
94
|
customerId: string;
|
|
98
|
-
/** Start of the current billing period (ISO Date) */
|
|
99
95
|
currentPeriodStart: string;
|
|
100
|
-
/** End of the current billing period (ISO Date) */
|
|
101
96
|
currentPeriodEnd: string;
|
|
102
|
-
/** If true, the subscription will cancel at the end of the current period */
|
|
103
97
|
cancelAtPeriodEnd: boolean;
|
|
104
98
|
canceledAt?: string;
|
|
105
99
|
startedAt: string;
|
|
@@ -108,222 +102,211 @@ type Subscription = {
|
|
|
108
102
|
trialEnd?: string;
|
|
109
103
|
metadata?: Record<string, any>;
|
|
110
104
|
};
|
|
105
|
+
type SubscriptionInterval = "day" | "week" | "month" | "year";
|
|
106
|
+
type CreateCustomerInput = {
|
|
107
|
+
email: string;
|
|
108
|
+
name?: string;
|
|
109
|
+
phone?: string;
|
|
110
|
+
description?: string;
|
|
111
|
+
address?: Address;
|
|
112
|
+
metadata?: Record<string, any>;
|
|
113
|
+
};
|
|
114
|
+
type UpdateCustomerInput = Partial<CreateCustomerInput>;
|
|
111
115
|
type CreatePaymentInput = {
|
|
112
116
|
amount: number;
|
|
113
117
|
currency: string;
|
|
114
118
|
customerId?: string;
|
|
115
119
|
paymentMethodId?: string;
|
|
116
120
|
description?: string;
|
|
121
|
+
capture?: boolean;
|
|
122
|
+
billingAddress?: Address;
|
|
123
|
+
shippingAddress?: Address;
|
|
117
124
|
metadata?: Record<string, any>;
|
|
118
|
-
/** Pass-through options for the specific provider */
|
|
119
125
|
providerOptions?: any;
|
|
120
126
|
};
|
|
121
|
-
type
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
nextAction?: {
|
|
125
|
-
type: "redirect" | "modal";
|
|
126
|
-
url: string;
|
|
127
|
-
};
|
|
128
|
-
};
|
|
129
|
-
type CreateSubscriptionInput = {
|
|
130
|
-
customerId: string;
|
|
131
|
-
planId?: string;
|
|
132
|
-
priceId?: string;
|
|
127
|
+
type RefundPaymentInput = {
|
|
128
|
+
paymentId: string;
|
|
129
|
+
externalPaymentId?: string;
|
|
133
130
|
amount?: number;
|
|
134
|
-
|
|
135
|
-
trialDays?: number;
|
|
131
|
+
reason?: "duplicate" | "fraudulent" | "requested_by_customer";
|
|
136
132
|
metadata?: Record<string, any>;
|
|
137
133
|
};
|
|
138
|
-
type
|
|
139
|
-
|
|
134
|
+
type SetupPaymentMethodInput = {
|
|
135
|
+
customerId: string;
|
|
136
|
+
returnUrl: string;
|
|
137
|
+
metadata?: Record<string, any>;
|
|
140
138
|
};
|
|
141
139
|
type CheckoutSessionInput = {
|
|
142
140
|
customerId?: string;
|
|
143
|
-
|
|
141
|
+
customerEmail?: string;
|
|
142
|
+
setupFutureUsage?: boolean;
|
|
144
143
|
lineItems: {
|
|
145
144
|
name: string;
|
|
146
145
|
amount: number;
|
|
147
146
|
quantity: number;
|
|
148
147
|
currency: string;
|
|
149
148
|
images?: string[];
|
|
149
|
+
taxRates?: string[];
|
|
150
150
|
}[];
|
|
151
151
|
successUrl: string;
|
|
152
152
|
cancelUrl: string;
|
|
153
|
-
|
|
153
|
+
billingAddressCollection?: "auto" | "required";
|
|
154
|
+
mode: "payment" | "subscription" | "setup";
|
|
154
155
|
metadata?: Record<string, any>;
|
|
155
156
|
};
|
|
157
|
+
type CreateSubscriptionInput = {
|
|
158
|
+
customerId: string;
|
|
159
|
+
planId?: string;
|
|
160
|
+
priceId?: string;
|
|
161
|
+
quantity?: number;
|
|
162
|
+
trialDays?: number;
|
|
163
|
+
metadata?: Record<string, any>;
|
|
164
|
+
};
|
|
165
|
+
type PaymentResult = {
|
|
166
|
+
payment: Payment;
|
|
167
|
+
/**
|
|
168
|
+
* Action required to complete the payment (e.g., 3DS Redirect).
|
|
169
|
+
*/
|
|
170
|
+
nextAction?: {
|
|
171
|
+
type: "redirect" | "modal";
|
|
172
|
+
url: string;
|
|
173
|
+
};
|
|
174
|
+
};
|
|
175
|
+
type SubscriptionResult = {
|
|
176
|
+
subscription: Subscription;
|
|
177
|
+
};
|
|
156
178
|
type CheckoutSessionResult = {
|
|
157
179
|
id: string;
|
|
158
180
|
url: string;
|
|
159
181
|
expiresAt?: string;
|
|
160
182
|
};
|
|
183
|
+
type PaginationOptions = {
|
|
184
|
+
limit?: number;
|
|
185
|
+
cursor?: string;
|
|
186
|
+
startingAfter?: string;
|
|
187
|
+
page?: number;
|
|
188
|
+
};
|
|
189
|
+
type PaginatedResult<T> = {
|
|
190
|
+
data: T[];
|
|
191
|
+
hasMore: boolean;
|
|
192
|
+
nextCursor?: string;
|
|
193
|
+
};
|
|
194
|
+
type Address = {
|
|
195
|
+
line1: string;
|
|
196
|
+
line2?: string;
|
|
197
|
+
city: string;
|
|
198
|
+
state?: string;
|
|
199
|
+
postalCode: string;
|
|
200
|
+
country: string;
|
|
201
|
+
};
|
|
202
|
+
type Customer = {
|
|
203
|
+
id: string;
|
|
204
|
+
providerId: string;
|
|
205
|
+
externalId: string;
|
|
206
|
+
email: string;
|
|
207
|
+
name?: string;
|
|
208
|
+
phone?: string;
|
|
209
|
+
metadata?: Record<string, any>;
|
|
210
|
+
createdAt: string;
|
|
211
|
+
};
|
|
212
|
+
type PaymentMethod = {
|
|
213
|
+
id: string;
|
|
214
|
+
customerId: string;
|
|
215
|
+
externalId: string;
|
|
216
|
+
type: "card" | "bank_transfer" | "wallet";
|
|
217
|
+
details: PaymentMethodDetails;
|
|
218
|
+
isDefault: boolean;
|
|
219
|
+
metadata?: Record<string, any>;
|
|
220
|
+
};
|
|
161
221
|
|
|
162
|
-
/**
|
|
163
|
-
* src/interfaces/features.ts
|
|
164
|
-
* * Defines the specific capabilities a provider can implement.
|
|
165
|
-
* This adheres to the Interface Segregation Principle.
|
|
166
|
-
*/
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Contract for providers that support one-time payments.
|
|
170
|
-
*/
|
|
171
222
|
interface IPaymentFeature {
|
|
172
223
|
createPayment(ctx: ProviderContext, input: CreatePaymentInput): Promise<PaymentResult>;
|
|
173
|
-
getPayment(ctx: ProviderContext, id: string): Promise<
|
|
224
|
+
getPayment(ctx: ProviderContext, id: string): Promise<Payment>;
|
|
225
|
+
refundPayment(ctx: ProviderContext, input: RefundPaymentInput): Promise<Payment>;
|
|
226
|
+
listPayments?(ctx: ProviderContext, pagination: PaginationOptions): Promise<PaginatedResult<Payment>>;
|
|
174
227
|
}
|
|
175
|
-
/**
|
|
176
|
-
* Contract for providers that support native recurring billing.
|
|
177
|
-
* (e.g., Stripe, Paddle, but NOT simple bank transfers).
|
|
178
|
-
*/
|
|
179
228
|
interface ISubscriptionFeature {
|
|
180
229
|
createSubscription(ctx: ProviderContext, input: CreateSubscriptionInput): Promise<SubscriptionResult>;
|
|
181
230
|
cancelSubscription(ctx: ProviderContext, id: string, reason?: string): Promise<SubscriptionResult>;
|
|
182
|
-
pauseSubscription(ctx: ProviderContext, id: string
|
|
183
|
-
resumeSubscription(ctx: ProviderContext, id: string
|
|
231
|
+
pauseSubscription(ctx: ProviderContext, id: string): Promise<SubscriptionResult>;
|
|
232
|
+
resumeSubscription(ctx: ProviderContext, id: string): Promise<SubscriptionResult>;
|
|
233
|
+
getSubscription(ctx: ProviderContext, id: string): Promise<Subscription>;
|
|
184
234
|
}
|
|
185
|
-
/**
|
|
186
|
-
* Contract for providers that offer a hosted checkout page.
|
|
187
|
-
*/
|
|
188
235
|
interface ICheckoutFeature {
|
|
189
236
|
createCheckoutSession(ctx: ProviderContext, input: CheckoutSessionInput): Promise<CheckoutSessionResult>;
|
|
190
237
|
}
|
|
238
|
+
interface ICustomerFeature {
|
|
239
|
+
createCustomer(ctx: ProviderContext, input: CreateCustomerInput): Promise<Customer>;
|
|
240
|
+
updateCustomer(ctx: ProviderContext, id: string, input: UpdateCustomerInput): Promise<Customer>;
|
|
241
|
+
deleteCustomer(ctx: ProviderContext, id: string): Promise<boolean>;
|
|
242
|
+
getCustomer(ctx: ProviderContext, id: string): Promise<Customer>;
|
|
243
|
+
}
|
|
244
|
+
interface IPaymentMethodFeature {
|
|
245
|
+
listPaymentMethods(ctx: ProviderContext, customerId: string): Promise<PaymentMethod[]>;
|
|
246
|
+
deletePaymentMethod(ctx: ProviderContext, id: string): Promise<boolean>;
|
|
247
|
+
}
|
|
191
248
|
/**
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* (usually by throwing a 'Not Implemented' error via the BaseProvider).
|
|
249
|
+
* Unified interface that all providers must satisfy.
|
|
250
|
+
* (Even if they just throw 'Not Implemented' errors for unsupported features).
|
|
195
251
|
*/
|
|
196
|
-
interface IProvider extends IPaymentFeature, ISubscriptionFeature, ICheckoutFeature {
|
|
252
|
+
interface IProvider extends IPaymentFeature, ISubscriptionFeature, ICheckoutFeature, ICustomerFeature, IPaymentMethodFeature {
|
|
197
253
|
}
|
|
198
254
|
|
|
199
|
-
type EventType = "PAYMENT_SUCCEEDED" | "PAYMENT_FAILED" | "REFUND_PROCESSED" | "SUBSCRIPTION_CREATED" | "SUBSCRIPTION_UPDATED" | "SUBSCRIPTION_CANCELED" | "DISPUTE_CREATED" | "DISPUTE_RESOLVED";
|
|
200
|
-
/**
|
|
201
|
-
* A normalized event ready to be consumed by the Revstack Core.
|
|
202
|
-
*/
|
|
255
|
+
type EventType = "PAYMENT_SUCCEEDED" | "PAYMENT_FAILED" | "PAYMENT_AUTHORIZED" | "PAYMENT_CAPTURED" | "REFUND_PROCESSED" | "REFUND_FAILED" | "SUBSCRIPTION_CREATED" | "SUBSCRIPTION_UPDATED" | "SUBSCRIPTION_CANCELED" | "DISPUTE_CREATED" | "DISPUTE_RESOLVED" | "MANDATE_CREATED";
|
|
203
256
|
interface RevstackEvent {
|
|
204
|
-
/** The standardized event type */
|
|
205
257
|
type: EventType;
|
|
206
|
-
/** The provider's original event ID */
|
|
207
258
|
providerEventId: string;
|
|
208
|
-
/** ISO timestamp of when the event happened */
|
|
209
259
|
createdAt: Date;
|
|
210
|
-
/** The raw original payload (for debugging) */
|
|
211
|
-
originalPayload: any;
|
|
212
|
-
/** * The primary resource affected (Payment ID, Subscription ID).
|
|
213
|
-
* Used to link the event to internal records.
|
|
214
|
-
*/
|
|
215
260
|
resourceId: string;
|
|
216
|
-
|
|
261
|
+
originalPayload: any;
|
|
217
262
|
metadata?: Record<string, any>;
|
|
218
263
|
}
|
|
219
264
|
interface WebhookResponse {
|
|
220
|
-
/** HTTP Status code to return to the provider (e.g., 200) */
|
|
221
265
|
statusCode: number;
|
|
222
|
-
/** Body to return (e.g., { received: true }) */
|
|
223
266
|
body: any;
|
|
224
267
|
}
|
|
225
268
|
|
|
226
|
-
/**
|
|
227
|
-
* Defines how the checkout flow is presented to the user.
|
|
228
|
-
*/
|
|
229
269
|
type CheckoutStrategy = "redirect" | "native_sdk" | "sdui";
|
|
230
270
|
/**
|
|
231
271
|
* Defines who orchestrates the recurring billing logic.
|
|
232
272
|
*/
|
|
233
273
|
type SubscriptionMode = "native" | "virtual";
|
|
234
|
-
interface
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
supported: boolean;
|
|
239
|
-
/**
|
|
240
|
-
* The primary UX strategy used to collect payment details.
|
|
241
|
-
* The frontend uses this to determine which adapter to load.
|
|
242
|
-
*/
|
|
243
|
-
strategy: CheckoutStrategy;
|
|
244
|
-
}
|
|
245
|
-
interface PaymentCapabilities {
|
|
246
|
-
/**
|
|
247
|
-
* If true, the provider supports processing standard One-Time Payments.
|
|
248
|
-
* This is the fundamental capability of any payment provider.
|
|
249
|
-
*/
|
|
250
|
-
supported: boolean;
|
|
251
|
-
/**
|
|
252
|
-
* Advanced transactional features supported by the provider.
|
|
253
|
-
*/
|
|
254
|
-
features: {
|
|
255
|
-
/**
|
|
256
|
-
* Can the provider process full refunds via API?
|
|
257
|
-
*/
|
|
258
|
-
refunds: boolean;
|
|
259
|
-
/**
|
|
260
|
-
* Can the provider process partial refunds (returning a specific amount)?
|
|
261
|
-
*/
|
|
262
|
-
partialRefunds: boolean;
|
|
263
|
-
/**
|
|
264
|
-
* Supports "Authorization & Capture" flow.
|
|
265
|
-
* Useful for e-commerce (shipping) or rentals, where funds are held first
|
|
266
|
-
* and charged later.
|
|
267
|
-
*/
|
|
268
|
-
capture: boolean;
|
|
269
|
-
/**
|
|
270
|
-
* Can the provider fetch or list disputes/chargebacks via API?
|
|
271
|
-
*/
|
|
272
|
-
disputes: boolean;
|
|
274
|
+
interface ProviderCapabilities {
|
|
275
|
+
checkout: {
|
|
276
|
+
supported: boolean;
|
|
277
|
+
strategy: "redirect" | "native_sdk" | "sdui";
|
|
273
278
|
};
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
* (Only relevant if mode is 'native').
|
|
305
|
-
*/
|
|
306
|
-
proration?: boolean;
|
|
279
|
+
payments: {
|
|
280
|
+
supported: boolean;
|
|
281
|
+
features: {
|
|
282
|
+
refunds: boolean;
|
|
283
|
+
partialRefunds: boolean;
|
|
284
|
+
capture: boolean;
|
|
285
|
+
disputes: boolean;
|
|
286
|
+
};
|
|
287
|
+
};
|
|
288
|
+
subscriptions: {
|
|
289
|
+
supported: boolean;
|
|
290
|
+
mode: "native" | "virtual";
|
|
291
|
+
features: {
|
|
292
|
+
pause: boolean;
|
|
293
|
+
resume: boolean;
|
|
294
|
+
cancellation: boolean;
|
|
295
|
+
proration?: boolean;
|
|
296
|
+
};
|
|
297
|
+
};
|
|
298
|
+
customers: {
|
|
299
|
+
supported: boolean;
|
|
300
|
+
features: {
|
|
301
|
+
create: boolean;
|
|
302
|
+
update: boolean;
|
|
303
|
+
delete: boolean;
|
|
304
|
+
};
|
|
305
|
+
};
|
|
306
|
+
webhooks: {
|
|
307
|
+
supported: boolean;
|
|
308
|
+
verification: "signature" | "secret" | "none";
|
|
307
309
|
};
|
|
308
|
-
}
|
|
309
|
-
interface WebhookCapabilities {
|
|
310
|
-
/**
|
|
311
|
-
* Does the provider send asynchronous events (webhooks)?
|
|
312
|
-
*/
|
|
313
|
-
supported: boolean;
|
|
314
|
-
/**
|
|
315
|
-
* How the webhook payload is verified for security.
|
|
316
|
-
* - 'signature': HMAC/RSA signature header (Best).
|
|
317
|
-
* - 'secret': Simple shared secret in header/body.
|
|
318
|
-
* - 'none': No verification (Insecure).
|
|
319
|
-
*/
|
|
320
|
-
verification: "signature" | "secret" | "none";
|
|
321
|
-
}
|
|
322
|
-
interface ProviderCapabilities {
|
|
323
|
-
checkout: CheckoutCapabilities;
|
|
324
|
-
payments: PaymentCapabilities;
|
|
325
|
-
subscriptions: SubscriptionCapabilities;
|
|
326
|
-
webhooks: WebhookCapabilities;
|
|
327
310
|
}
|
|
328
311
|
|
|
329
312
|
/**
|
|
@@ -400,25 +383,25 @@ declare function createError(code: RevstackErrorCode, message: string, provider?
|
|
|
400
383
|
declare function isRevstackError(error: unknown): error is RevstackError;
|
|
401
384
|
|
|
402
385
|
interface InstallInput {
|
|
403
|
-
/**
|
|
404
|
-
* La configuración ingresada por el usuario en el formulario (API Keys, etc).
|
|
405
|
-
*/
|
|
406
386
|
config: Record<string, any>;
|
|
407
387
|
/**
|
|
408
|
-
*
|
|
409
|
-
* El Core la genera: https://api.revstack.os/webhooks/{provider}/{merchantId}
|
|
388
|
+
* The absolute URL where Revstack expects to receive events for this merchant.
|
|
410
389
|
*/
|
|
411
390
|
webhookUrl: string;
|
|
412
391
|
}
|
|
413
392
|
interface InstallResult {
|
|
414
393
|
success: boolean;
|
|
415
|
-
/**
|
|
416
|
-
* Datos finales a guardar en la DB.
|
|
417
|
-
* Aquí el provider puede inyectar datos generados (como el webhookSecret).
|
|
418
|
-
*/
|
|
419
394
|
data?: Record<string, any>;
|
|
420
395
|
error?: RevstackError;
|
|
421
396
|
}
|
|
397
|
+
interface UninstallInput {
|
|
398
|
+
config: Record<string, any>;
|
|
399
|
+
data: Record<string, any>;
|
|
400
|
+
}
|
|
401
|
+
interface UninstallResult {
|
|
402
|
+
success: boolean;
|
|
403
|
+
error?: RevstackError;
|
|
404
|
+
}
|
|
422
405
|
|
|
423
406
|
declare enum ProviderCategory {
|
|
424
407
|
Card = "card",// Stripe, Adyen, dLocal
|
|
@@ -455,6 +438,16 @@ interface ConfigFieldDefinition {
|
|
|
455
438
|
value: string;
|
|
456
439
|
}[];
|
|
457
440
|
}
|
|
441
|
+
interface DataFieldDefinition {
|
|
442
|
+
/**
|
|
443
|
+
* If true, the value of this field will be encrypted in the DB.
|
|
444
|
+
*/
|
|
445
|
+
secure: boolean;
|
|
446
|
+
/**
|
|
447
|
+
* Description for internal documentation (optional)
|
|
448
|
+
*/
|
|
449
|
+
description?: string;
|
|
450
|
+
}
|
|
458
451
|
/**
|
|
459
452
|
* The Provider Manifest.
|
|
460
453
|
* Acts as the source of truth for the provider's metadata and capabilities.
|
|
@@ -498,6 +491,11 @@ interface ProviderManifest {
|
|
|
498
491
|
* Key is the internal config key (e.g., 'apiKey').
|
|
499
492
|
*/
|
|
500
493
|
configSchema: Record<string, ConfigFieldDefinition>;
|
|
494
|
+
/**
|
|
495
|
+
* Defines the fields that the provider generates and stores internally (Outputs).
|
|
496
|
+
* The Core uses this to know which fields to encrypt in the 'data' column.
|
|
497
|
+
*/
|
|
498
|
+
dataSchema?: Record<string, DataFieldDefinition>;
|
|
501
499
|
/**
|
|
502
500
|
* What this provider can do. Used for feature flagging in the core.
|
|
503
501
|
*/
|
|
@@ -515,6 +513,16 @@ interface ProviderManifest {
|
|
|
515
513
|
* Specific providers (e.g., Stripe) will override only the methods they actually support.
|
|
516
514
|
*/
|
|
517
515
|
declare abstract class BaseProvider implements IProvider {
|
|
516
|
+
getPayment(ctx: ProviderContext, id: string): Promise<Payment>;
|
|
517
|
+
refundPayment(ctx: ProviderContext, input: RefundPaymentInput): Promise<Payment>;
|
|
518
|
+
listPayments?(ctx: ProviderContext, pagination: PaginationOptions): Promise<PaginatedResult<Payment>>;
|
|
519
|
+
getSubscription(ctx: ProviderContext, id: string): Promise<Subscription>;
|
|
520
|
+
createCustomer(ctx: ProviderContext, input: CreateCustomerInput): Promise<Customer>;
|
|
521
|
+
updateCustomer(ctx: ProviderContext, id: string, input: UpdateCustomerInput): Promise<Customer>;
|
|
522
|
+
deleteCustomer(ctx: ProviderContext, id: string): Promise<boolean>;
|
|
523
|
+
getCustomer(ctx: ProviderContext, id: string): Promise<Customer>;
|
|
524
|
+
listPaymentMethods(ctx: ProviderContext, customerId: string): Promise<PaymentMethod[]>;
|
|
525
|
+
deletePaymentMethod(ctx: ProviderContext, id: string): Promise<boolean>;
|
|
518
526
|
/**
|
|
519
527
|
* The static manifest definition.
|
|
520
528
|
* Defines capabilities, metadata, and config schema (UI).
|
|
@@ -531,6 +539,17 @@ declare abstract class BaseProvider implements IProvider {
|
|
|
531
539
|
* @returns The success status and the data to be stored (encrypted by Core).
|
|
532
540
|
*/
|
|
533
541
|
abstract onInstall(ctx: ProviderContext, input: InstallInput): Promise<InstallResult>;
|
|
542
|
+
/**
|
|
543
|
+
* Called when a merchant uninstalls this provider.
|
|
544
|
+
* * RESPONSIBILITY:
|
|
545
|
+
* 1. Instantiate the provider SDK with the input config.
|
|
546
|
+
* 2. Validate credentials (e.g., make a 'ping' or 'get balance' request).
|
|
547
|
+
* 3. Return the success status.
|
|
548
|
+
* * @param ctx - The execution context (includes environment info).
|
|
549
|
+
* @param input - The input data provided by the user in the UI.
|
|
550
|
+
* @returns The success status.
|
|
551
|
+
*/
|
|
552
|
+
abstract onUninstall(ctx: ProviderContext, input: UninstallInput): Promise<boolean>;
|
|
534
553
|
/**
|
|
535
554
|
* Verifies the cryptographic signature of an incoming webhook.
|
|
536
555
|
* * SECURITY CRITICAL:
|
|
@@ -540,7 +559,7 @@ declare abstract class BaseProvider implements IProvider {
|
|
|
540
559
|
* @param headers - The request headers.
|
|
541
560
|
* @param secret - The webhook signing secret stored in the DB.
|
|
542
561
|
*/
|
|
543
|
-
abstract verifyWebhookSignature(payload: string | Buffer, headers: Record<string, string | string[] | undefined>, secret: string): Promise<boolean>;
|
|
562
|
+
abstract verifyWebhookSignature(ctx: ProviderContext, payload: string | Buffer, headers: Record<string, string | string[] | undefined>, secret: string): Promise<boolean>;
|
|
544
563
|
/**
|
|
545
564
|
* Transforms a raw provider payload into a standardized Revstack Event.
|
|
546
565
|
* * This acts as the "Translation Layer" or "Adapter" for incoming events.
|
|
@@ -561,10 +580,6 @@ declare abstract class BaseProvider implements IProvider {
|
|
|
561
580
|
* * @throws Error if not implemented by the specific provider.
|
|
562
581
|
*/
|
|
563
582
|
createPayment(ctx: ProviderContext, input: CreatePaymentInput): Promise<PaymentResult>;
|
|
564
|
-
/**
|
|
565
|
-
* Retrieve details of a payment by its ID.
|
|
566
|
-
*/
|
|
567
|
-
getPayment(ctx: ProviderContext, id: string): Promise<PaymentResult>;
|
|
568
583
|
/**
|
|
569
584
|
* Create a recurring subscription.
|
|
570
585
|
* Override this if manifest.capabilities.subscriptions.native is true.
|
|
@@ -589,4 +604,18 @@ declare abstract class BaseProvider implements IProvider {
|
|
|
589
604
|
*/
|
|
590
605
|
declare function validateAndCastConfig(rawConfig: Record<string, any>, schema: Record<string, ConfigFieldDefinition>): Record<string, any>;
|
|
591
606
|
|
|
592
|
-
|
|
607
|
+
/**
|
|
608
|
+
* Generic HMAC signature verification.
|
|
609
|
+
* usable by ~80% of providers (Shopify, MercadoPago, PayPal, etc.)
|
|
610
|
+
*/
|
|
611
|
+
declare function verifyHmacSignature(payload: string, secret: string, signature: string, algorithm?: "sha256" | "sha1", encoding?: "hex" | "base64"): boolean;
|
|
612
|
+
|
|
613
|
+
interface SmokeConfig {
|
|
614
|
+
provider: IProvider;
|
|
615
|
+
ctx: ProviderContext;
|
|
616
|
+
scenarios: Record<string, (ctx: ProviderContext) => Promise<any>>;
|
|
617
|
+
manifest: ProviderManifest;
|
|
618
|
+
}
|
|
619
|
+
declare function runSmoke(config: SmokeConfig): Promise<void>;
|
|
620
|
+
|
|
621
|
+
export { type Address, BaseProvider, CATEGORY_LABELS, type CheckoutSessionInput, type CheckoutSessionResult, type CheckoutStrategy, type ConfigFieldDefinition, type ConfigFieldType, type CreateCustomerInput, type CreatePaymentInput, type CreateSubscriptionInput, type Customer, type DataFieldDefinition, type EventType, type ICheckoutFeature, type ICustomerFeature, type IPaymentFeature, type IPaymentMethodFeature, type IProvider, type ISubscriptionFeature, type InstallInput, type InstallResult, type PaginatedResult, type PaginationOptions, type Payment, type PaymentMethod, type PaymentMethodDetails, type PaymentResult, PaymentStatus, type ProviderCapabilities, ProviderCategory, type ProviderContext, type ProviderManifest, type RefundPaymentInput, RevstackError, RevstackErrorCode, type RevstackEvent, type SetupPaymentMethodInput, type SmokeConfig, type Subscription, type SubscriptionInterval, type SubscriptionMode, type SubscriptionResult, SubscriptionStatus, type UninstallInput, type UninstallResult, type UpdateCustomerInput, type WebhookResponse, createError, isRevstackError, runSmoke, validateAndCastConfig, verifyHmacSignature };
|
package/dist/index.js
CHANGED
|
@@ -164,6 +164,36 @@ var CATEGORY_LABELS = {
|
|
|
164
164
|
|
|
165
165
|
// src/base.ts
|
|
166
166
|
var BaseProvider = class {
|
|
167
|
+
getPayment(ctx, id) {
|
|
168
|
+
throw new Error("Method not implemented.");
|
|
169
|
+
}
|
|
170
|
+
refundPayment(ctx, input) {
|
|
171
|
+
throw new Error("Method not implemented.");
|
|
172
|
+
}
|
|
173
|
+
listPayments(ctx, pagination) {
|
|
174
|
+
throw new Error("Method not implemented.");
|
|
175
|
+
}
|
|
176
|
+
getSubscription(ctx, id) {
|
|
177
|
+
throw new Error("Method not implemented.");
|
|
178
|
+
}
|
|
179
|
+
createCustomer(ctx, input) {
|
|
180
|
+
throw new Error("Method not implemented.");
|
|
181
|
+
}
|
|
182
|
+
updateCustomer(ctx, id, input) {
|
|
183
|
+
throw new Error("Method not implemented.");
|
|
184
|
+
}
|
|
185
|
+
deleteCustomer(ctx, id) {
|
|
186
|
+
throw new Error("Method not implemented.");
|
|
187
|
+
}
|
|
188
|
+
getCustomer(ctx, id) {
|
|
189
|
+
throw new Error("Method not implemented.");
|
|
190
|
+
}
|
|
191
|
+
listPaymentMethods(ctx, customerId) {
|
|
192
|
+
throw new Error("Method not implemented.");
|
|
193
|
+
}
|
|
194
|
+
deletePaymentMethod(ctx, id) {
|
|
195
|
+
throw new Error("Method not implemented.");
|
|
196
|
+
}
|
|
167
197
|
/**
|
|
168
198
|
* Returns the HTTP response that should be sent back to the Provider
|
|
169
199
|
* after receiving a webhook.
|
|
@@ -186,14 +216,6 @@ var BaseProvider = class {
|
|
|
186
216
|
`Provider '${this.manifest.slug}' does not support createPayment.`
|
|
187
217
|
);
|
|
188
218
|
}
|
|
189
|
-
/**
|
|
190
|
-
* Retrieve details of a payment by its ID.
|
|
191
|
-
*/
|
|
192
|
-
async getPayment(ctx, id) {
|
|
193
|
-
throw new Error(
|
|
194
|
-
`Provider '${this.manifest.slug}' does not support getPayment.`
|
|
195
|
-
);
|
|
196
|
-
}
|
|
197
219
|
// ===========================================================================
|
|
198
220
|
// SUBSCRIPTION FEATURE IMPLEMENTATION (IProvider)
|
|
199
221
|
// ===========================================================================
|
|
@@ -281,6 +303,49 @@ function validateAndCastConfig(rawConfig, schema) {
|
|
|
281
303
|
}
|
|
282
304
|
return processedConfig;
|
|
283
305
|
}
|
|
306
|
+
|
|
307
|
+
// src/utils/crypto.ts
|
|
308
|
+
import * as crypto from "crypto";
|
|
309
|
+
function verifyHmacSignature(payload, secret, signature, algorithm = "sha256", encoding = "hex") {
|
|
310
|
+
if (!payload || !secret || !signature) return false;
|
|
311
|
+
const hmac = crypto.createHmac(algorithm, secret);
|
|
312
|
+
const digest = hmac.update(payload).digest(encoding);
|
|
313
|
+
return crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(digest));
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// src/smoke-runner.ts
|
|
317
|
+
async function runSmoke(config) {
|
|
318
|
+
const method = process.argv[2] || "onInstall";
|
|
319
|
+
const providerName = config.manifest.name;
|
|
320
|
+
console.log(`
|
|
321
|
+
\u{1F6AC} \x1B[36mSmoking Provider:\x1B[0m ${providerName}`);
|
|
322
|
+
console.log(`\u{1F449} \x1B[33mMethod:\x1B[0m ${method}
|
|
323
|
+
`);
|
|
324
|
+
if (method === "list") {
|
|
325
|
+
console.log("\u{1F4CB} Available scenarios:");
|
|
326
|
+
console.log(
|
|
327
|
+
Object.keys(config.scenarios).map((k) => ` - ${k}`).join("\n")
|
|
328
|
+
);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
const scenario = config.scenarios[method];
|
|
332
|
+
if (!scenario) {
|
|
333
|
+
console.error(`\u274C \x1B[31mError:\x1B[0m Scenario '${method}' not found.`);
|
|
334
|
+
console.log(` Run 'list' to see available scenarios.`);
|
|
335
|
+
process.exit(1);
|
|
336
|
+
}
|
|
337
|
+
try {
|
|
338
|
+
console.time("\u23F1\uFE0F Execution time");
|
|
339
|
+
const result = await scenario(config.ctx);
|
|
340
|
+
console.timeEnd("\u23F1\uFE0F Execution time");
|
|
341
|
+
console.log("\n\u2705 \x1B[32mSUCCESS RESULT:\x1B[0m");
|
|
342
|
+
console.dir(result, { depth: null, colors: true });
|
|
343
|
+
} catch (e) {
|
|
344
|
+
console.error("\n\u{1F525} \x1B[31mFAILED:\x1B[0m");
|
|
345
|
+
console.error(e);
|
|
346
|
+
process.exit(1);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
284
349
|
export {
|
|
285
350
|
BaseProvider,
|
|
286
351
|
CATEGORY_LABELS,
|
|
@@ -291,5 +356,7 @@ export {
|
|
|
291
356
|
SubscriptionStatus,
|
|
292
357
|
createError,
|
|
293
358
|
isRevstackError,
|
|
294
|
-
|
|
359
|
+
runSmoke,
|
|
360
|
+
validateAndCastConfig,
|
|
361
|
+
verifyHmacSignature
|
|
295
362
|
};
|