@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 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
- /** Amount refunded so far */
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",// Payment failed, in grace period
77
+ PastDue = "past_due",
78
78
  Canceled = "canceled",
79
- Unpaid = "unpaid",// Grace period ended, service cut
80
- Incomplete = "incomplete",// Created but waiting for first payment (3DS)
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: SubscriptionInterval;
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 PaymentResult = {
122
- payment: Payment;
123
- /** If the payment requires 3DS or redirect */
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
- currency?: string;
135
- trialDays?: number;
131
+ reason?: "duplicate" | "fraudulent" | "requested_by_customer";
136
132
  metadata?: Record<string, any>;
137
133
  };
138
- type SubscriptionResult = {
139
- subscription: Subscription;
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
- /** Items to purchase */
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
- mode: "payment" | "subscription";
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<PaymentResult>;
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, reason?: string): Promise<SubscriptionResult>;
183
- resumeSubscription(ctx: ProviderContext, id: string, reason?: string): Promise<SubscriptionResult>;
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
- * The unified contract that all Revstack Providers must technically satisfy.
193
- * * Even if a provider doesn't support a feature, it must implement the interface
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
- /** Additional context */
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 CheckoutCapabilities {
235
- /**
236
- * If true, this provider can be used in the Hosted Checkout flow.
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
- interface SubscriptionCapabilities {
276
- /**
277
- * If true, the provider supports recurring billing flows.
278
- */
279
- supported: boolean;
280
- /**
281
- * The engine responsible for recurrence logic.
282
- * - 'native': We delegate logic to the provider.
283
- * - 'virtual': We emulate logic using one-time payments.
284
- */
285
- mode: SubscriptionMode;
286
- /**
287
- * Specific lifecycle actions supported by the provider.
288
- */
289
- features: {
290
- /**
291
- * Can a subscription be paused temporarily without canceling it?
292
- */
293
- pause: boolean;
294
- /**
295
- * Can a paused subscription be resumed?
296
- */
297
- resume: boolean;
298
- /**
299
- * Can a subscription be canceled via API?
300
- */
301
- cancellation: boolean;
302
- /**
303
- * Does the provider support native proration for upgrades/downgrades?
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
- * La URL absoluta donde Revstack espera recibir los eventos para este merchant.
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
- export { BaseProvider, CATEGORY_LABELS, type CheckoutCapabilities, type CheckoutSessionInput, type CheckoutSessionResult, type CheckoutStrategy, type ConfigFieldDefinition, type ConfigFieldType, type CreatePaymentInput, type CreateSubscriptionInput, type EventType, type ICheckoutFeature, type IPaymentFeature, type IProvider, type ISubscriptionFeature, type InstallInput, type InstallResult, type Payment, type PaymentCapabilities, type PaymentMethodDetails, type PaymentResult, PaymentStatus, type ProviderCapabilities, ProviderCategory, type ProviderContext, type ProviderManifest, RevstackError, RevstackErrorCode, type RevstackEvent, type Subscription, type SubscriptionCapabilities, type SubscriptionInterval, type SubscriptionMode, type SubscriptionResult, SubscriptionStatus, type WebhookCapabilities, type WebhookResponse, createError, isRevstackError, validateAndCastConfig };
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
- validateAndCastConfig
359
+ runSmoke,
360
+ validateAndCastConfig,
361
+ verifyHmacSignature
295
362
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revstackhq/providers-core",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",