recurrente-js 1.0.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/api/recurrente-webhooks.d.ts +71 -0
- package/dist/api/recurrente-webhooks.js +122 -0
- package/dist/api/recurrente.d.ts +131 -0
- package/dist/api/recurrente.js +355 -0
- package/dist/config/axiosInstance.d.ts +3 -0
- package/dist/config/axiosInstance.js +55 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +8 -0
- package/dist/types/globals.d.ts +1277 -0
- package/dist/types/globals.js +7 -0
- package/dist/utils/conversion.d.ts +25 -0
- package/dist/utils/conversion.js +58 -0
- package/dist/webhooks.d.ts +1 -0
- package/dist/webhooks.js +7 -0
- package/package.json +43 -0
- package/readme.md +353 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { PaymentIntentSucceeded, PaymentIntentFailed, SubscriptionCreate, SubscriptionPastDue, SubscriptionPaused, SubscriptionCancel, RecurrenteWebhookEvent } from '../types/globals';
|
|
2
|
+
/**
|
|
3
|
+
* A handler function type definition.
|
|
4
|
+
* @template T The type of the webhook event.
|
|
5
|
+
*/
|
|
6
|
+
type WebhookHandler<T> = (event: T) => void;
|
|
7
|
+
/**
|
|
8
|
+
* Mapping of event types to corresponding event interfaces.
|
|
9
|
+
*/
|
|
10
|
+
interface EventTypeMapping {
|
|
11
|
+
'payment_intent.succeeded': PaymentIntentSucceeded;
|
|
12
|
+
'payment_intent.failed': PaymentIntentFailed;
|
|
13
|
+
'subscription.create': SubscriptionCreate;
|
|
14
|
+
'subscription.past_due': SubscriptionPastDue;
|
|
15
|
+
'subscription.paused': SubscriptionPaused;
|
|
16
|
+
'subscription.cancel': SubscriptionCancel;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Verifies the Svix webhook signature and parses the event.
|
|
20
|
+
*
|
|
21
|
+
* @param payload - The raw request body as a string.
|
|
22
|
+
* @param headers - The request headers.
|
|
23
|
+
* @returns The verified and parsed event.
|
|
24
|
+
* @throws {Error} If the signature verification fails.
|
|
25
|
+
*/
|
|
26
|
+
declare function verifySvixSignature(payload: string, headers: Record<string, string | string[] | undefined>): RecurrenteWebhookEvent;
|
|
27
|
+
/**
|
|
28
|
+
* Registers a custom webhook handler for a specific event type.
|
|
29
|
+
*
|
|
30
|
+
* @template T The type of the webhook event.
|
|
31
|
+
* @param {keyof EventTypeMapping} eventType - The type of the event (e.g., 'payment_intent.succeeded').
|
|
32
|
+
* @param {WebhookHandler<EventTypeMapping[T]>} handler - The custom handler function to register for this event type.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* registerWebhookHandler('payment_intent.succeeded', (event) => {
|
|
36
|
+
* console.log(`Payment succeeded for: ${event.customer.email}`);
|
|
37
|
+
* // Custom logic for a successful payment
|
|
38
|
+
* });
|
|
39
|
+
*/
|
|
40
|
+
declare function registerWebhookHandler<T extends keyof EventTypeMapping>(eventType: T, handler: WebhookHandler<EventTypeMapping[T]>): void;
|
|
41
|
+
/**
|
|
42
|
+
* Handles a verified webhook event by dispatching it to the appropriate registered or default handler.
|
|
43
|
+
*
|
|
44
|
+
* **Important Note:** Before calling this function, you must verify the webhook signature using `verifySvixSignature`
|
|
45
|
+
* to ensure the event is authentic and has not been tampered with.
|
|
46
|
+
*
|
|
47
|
+
* @param {RecurrenteWebhookEvent} event - The verified webhook event object sent by Recurrente.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* app.post('/webhook', (req, res) => {
|
|
51
|
+
* try {
|
|
52
|
+
* const payload = req.body;
|
|
53
|
+
* const headers = req.headers;
|
|
54
|
+
*
|
|
55
|
+
* // Verify the signature and obtain the event
|
|
56
|
+
* const event = verifySvixSignature(payload, headers);
|
|
57
|
+
*
|
|
58
|
+
* // Handle the verified event
|
|
59
|
+
* handleWebhookEvent(event);
|
|
60
|
+
*
|
|
61
|
+
* res.status(200).send('Webhook processed');
|
|
62
|
+
* } catch (error) {
|
|
63
|
+
* console.error('Error processing webhook:', error);
|
|
64
|
+
* res.status(400).send('Invalid webhook signature');
|
|
65
|
+
* }
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* @throws {Error} If no handler is found for the event type.
|
|
69
|
+
*/
|
|
70
|
+
declare function handleWebhookEvent(event: RecurrenteWebhookEvent): void;
|
|
71
|
+
export { handleWebhookEvent, verifySvixSignature, registerWebhookHandler };
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.handleWebhookEvent = handleWebhookEvent;
|
|
7
|
+
exports.verifySvixSignature = verifySvixSignature;
|
|
8
|
+
exports.registerWebhookHandler = registerWebhookHandler;
|
|
9
|
+
const svix_1 = require("svix");
|
|
10
|
+
const conversion_1 = require("../utils/conversion");
|
|
11
|
+
const dotenv_1 = __importDefault(require("dotenv"));
|
|
12
|
+
// Load environment variables from .env file if they are not already set
|
|
13
|
+
dotenv_1.default.config();
|
|
14
|
+
/**
|
|
15
|
+
* A record to store the user-registered webhook handlers.
|
|
16
|
+
* Each event type is mapped to its corresponding handler function.
|
|
17
|
+
*/
|
|
18
|
+
const userHandlers = {
|
|
19
|
+
'payment_intent.succeeded': (event) => {
|
|
20
|
+
console.log('Default PaymentIntentSucceeded Handler:', event);
|
|
21
|
+
},
|
|
22
|
+
'payment_intent.failed': (event) => {
|
|
23
|
+
console.log('Default PaymentIntentFailed Handler:', event);
|
|
24
|
+
},
|
|
25
|
+
'subscription.create': (event) => {
|
|
26
|
+
console.log('Default SubscriptionCreate Handler:', event);
|
|
27
|
+
},
|
|
28
|
+
'subscription.past_due': (event) => {
|
|
29
|
+
console.log('Default SubscriptionPastDue Handler:', event);
|
|
30
|
+
},
|
|
31
|
+
'subscription.paused': (event) => {
|
|
32
|
+
console.log('Default SubscriptionPaused Handler:', event);
|
|
33
|
+
},
|
|
34
|
+
'subscription.cancel': (event) => {
|
|
35
|
+
console.log('Default SubscriptionCancel Handler:', event);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
/**
|
|
39
|
+
* Verifies the Svix webhook signature and parses the event.
|
|
40
|
+
*
|
|
41
|
+
* @param payload - The raw request body as a string.
|
|
42
|
+
* @param headers - The request headers.
|
|
43
|
+
* @returns The verified and parsed event.
|
|
44
|
+
* @throws {Error} If the signature verification fails.
|
|
45
|
+
*/
|
|
46
|
+
function verifySvixSignature(payload, headers) {
|
|
47
|
+
const signingSecret = process.env.RECURRENTE_SVIX_SIGNING_SECRET;
|
|
48
|
+
if (!signingSecret) {
|
|
49
|
+
throw new Error('Missing signing secret');
|
|
50
|
+
}
|
|
51
|
+
const svixHeaders = {
|
|
52
|
+
'svix-id': headers['svix-id'],
|
|
53
|
+
'svix-timestamp': headers['svix-timestamp'],
|
|
54
|
+
'svix-signature': headers['svix-signature'],
|
|
55
|
+
};
|
|
56
|
+
const svix = new svix_1.Webhook(signingSecret);
|
|
57
|
+
try {
|
|
58
|
+
// Verify the signature and parse the event
|
|
59
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
60
|
+
const event = svix.verify(payload, svixHeaders);
|
|
61
|
+
// Convert snake_case keys to camelCase
|
|
62
|
+
const camelCasedEvent = (0, conversion_1.toCamelCase)(event);
|
|
63
|
+
return camelCasedEvent;
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
throw new Error('Invalid webhook signature');
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Registers a custom webhook handler for a specific event type.
|
|
71
|
+
*
|
|
72
|
+
* @template T The type of the webhook event.
|
|
73
|
+
* @param {keyof EventTypeMapping} eventType - The type of the event (e.g., 'payment_intent.succeeded').
|
|
74
|
+
* @param {WebhookHandler<EventTypeMapping[T]>} handler - The custom handler function to register for this event type.
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* registerWebhookHandler('payment_intent.succeeded', (event) => {
|
|
78
|
+
* console.log(`Payment succeeded for: ${event.customer.email}`);
|
|
79
|
+
* // Custom logic for a successful payment
|
|
80
|
+
* });
|
|
81
|
+
*/
|
|
82
|
+
function registerWebhookHandler(eventType, handler) {
|
|
83
|
+
userHandlers[eventType] = handler;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Handles a verified webhook event by dispatching it to the appropriate registered or default handler.
|
|
87
|
+
*
|
|
88
|
+
* **Important Note:** Before calling this function, you must verify the webhook signature using `verifySvixSignature`
|
|
89
|
+
* to ensure the event is authentic and has not been tampered with.
|
|
90
|
+
*
|
|
91
|
+
* @param {RecurrenteWebhookEvent} event - The verified webhook event object sent by Recurrente.
|
|
92
|
+
*
|
|
93
|
+
* @example
|
|
94
|
+
* app.post('/webhook', (req, res) => {
|
|
95
|
+
* try {
|
|
96
|
+
* const payload = req.body;
|
|
97
|
+
* const headers = req.headers;
|
|
98
|
+
*
|
|
99
|
+
* // Verify the signature and obtain the event
|
|
100
|
+
* const event = verifySvixSignature(payload, headers);
|
|
101
|
+
*
|
|
102
|
+
* // Handle the verified event
|
|
103
|
+
* handleWebhookEvent(event);
|
|
104
|
+
*
|
|
105
|
+
* res.status(200).send('Webhook processed');
|
|
106
|
+
* } catch (error) {
|
|
107
|
+
* console.error('Error processing webhook:', error);
|
|
108
|
+
* res.status(400).send('Invalid webhook signature');
|
|
109
|
+
* }
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* @throws {Error} If no handler is found for the event type.
|
|
113
|
+
*/
|
|
114
|
+
function handleWebhookEvent(event) {
|
|
115
|
+
const handler = userHandlers[event.eventType];
|
|
116
|
+
if (handler) {
|
|
117
|
+
handler(event);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
throw new Error(`No handler registered for event type: ${event.eventType}`);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { ProductSubscription, CreateSubscriptionResponse, SubscriptionStatusResponse, CreateProductRequest, CreateProductResponse, GetProductResponse, GetAllProductsResponse, UpdateProductRequest } from '../types/globals';
|
|
2
|
+
/**
|
|
3
|
+
* Recurrente API utility for managing product subscriptions, cancellations, and product deletions.
|
|
4
|
+
*
|
|
5
|
+
* The `recurrente` object provides methods to create, cancel, retrieve, and delete subscriptions and products,
|
|
6
|
+
* making it easy to integrate Recurrente's payment services into your project.
|
|
7
|
+
*
|
|
8
|
+
* @namespace recurrente
|
|
9
|
+
* @property {Function} test - Test endpoint.
|
|
10
|
+
* @property {Function} createProduct - Creates a new product with a one-time payment.
|
|
11
|
+
* @property {Function} getProduct - Retrieves details of a specific product by its ID.
|
|
12
|
+
* @property {Function} getAllProducts - Retrieves a paginated list of all products.
|
|
13
|
+
* @property {Function} updateProduct - Updates an existing product by its ID.
|
|
14
|
+
* @property {Function} deleteProduct - Deletes a product by its ID.
|
|
15
|
+
* @property {Function} createSubscription - Creates a new subscription for a product.
|
|
16
|
+
* @property {Function} cancelSubscription - Cancels an existing subscription by its ID.
|
|
17
|
+
* @property {Function} getSubscription - Retrieves details of a specific subscription by its ID.
|
|
18
|
+
*/
|
|
19
|
+
declare const recurrente: {
|
|
20
|
+
/**
|
|
21
|
+
* Makes a GET request to the '/test' endpoint.
|
|
22
|
+
*
|
|
23
|
+
* **FOR DEVELOPMENT PURPOSES ONLY TO TEST**
|
|
24
|
+
*
|
|
25
|
+
* This method is included for testing internal API functionality.
|
|
26
|
+
*
|
|
27
|
+
* @function
|
|
28
|
+
* @memberof recurrente
|
|
29
|
+
* @returns {Promise<{message: string}>} A message indicating the success or failure of the request.
|
|
30
|
+
* @throws {ErrorResponse} Throws an error if the request fails.
|
|
31
|
+
*/
|
|
32
|
+
test: () => Promise<{
|
|
33
|
+
message: string;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Creates a new product with a one-time payment.
|
|
37
|
+
*
|
|
38
|
+
* This function takes the product data, converts it to snake_case,
|
|
39
|
+
* and sends it to the API to create a one-time payment product.
|
|
40
|
+
* It returns the created product's details.
|
|
41
|
+
*
|
|
42
|
+
* @function
|
|
43
|
+
* @memberof recurrente
|
|
44
|
+
* @see createProduct
|
|
45
|
+
* @param {CreateProductRequest} productData - The details of the product to create.
|
|
46
|
+
* @returns {Promise<CreateProductResponse>} A promise that resolves with the created product's details.
|
|
47
|
+
* @throws {ErrorResponse} Throws an error if the product creation fails.
|
|
48
|
+
*/
|
|
49
|
+
createProduct: (productData: CreateProductRequest) => Promise<CreateProductResponse>;
|
|
50
|
+
/**
|
|
51
|
+
* Retrieves details of a specific product by its ID.
|
|
52
|
+
*
|
|
53
|
+
* This function fetches details of an existing product by making a GET request
|
|
54
|
+
* using the product ID.
|
|
55
|
+
*
|
|
56
|
+
* @function
|
|
57
|
+
* @memberof recurrente
|
|
58
|
+
* @see getProduct
|
|
59
|
+
* @param {string} productId - The ID of the product to retrieve.
|
|
60
|
+
* @returns {Promise<GetProductResponse>} The details of the product.
|
|
61
|
+
* @throws {ErrorResponse} Throws an error if the retrieval fails.
|
|
62
|
+
*/
|
|
63
|
+
getProduct: (productId: string) => Promise<GetProductResponse>;
|
|
64
|
+
/**
|
|
65
|
+
* Retrieves a paginated list of all products.
|
|
66
|
+
*
|
|
67
|
+
* This function fetches a list of products from the API. By default, it retrieves
|
|
68
|
+
* the 10 most recent products, but pagination can be controlled using query parameters.
|
|
69
|
+
*
|
|
70
|
+
* @function
|
|
71
|
+
* @memberof recurrente
|
|
72
|
+
* @see getAllProducts
|
|
73
|
+
* @param {number} [page=1] - The page number to retrieve, defaults to the first page.
|
|
74
|
+
* @returns {Promise<GetAllProductsResponse>} A promise that resolves with an array of product details.
|
|
75
|
+
* @throws {ErrorResponse} Throws an error if the product retrieval fails.
|
|
76
|
+
*/
|
|
77
|
+
getAllProducts: (page?: number) => Promise<GetAllProductsResponse>;
|
|
78
|
+
/**
|
|
79
|
+
* Updates an existing product by its ID.
|
|
80
|
+
*
|
|
81
|
+
* This function takes the product ID and an object containing the updated product details.
|
|
82
|
+
* It sends a PATCH request to the API to update the specified product. You can also
|
|
83
|
+
* modify product prices or delete them by passing the _destroy parameter in prices_attributes.
|
|
84
|
+
*
|
|
85
|
+
* @function
|
|
86
|
+
* @memberof recurrente
|
|
87
|
+
* @see updateProduct
|
|
88
|
+
* @param {string} productId - The ID of the product to update.
|
|
89
|
+
* @param {UpdateProductRequest} productData - The updated product details.
|
|
90
|
+
* @returns {Promise<GetProductResponse>} A promise that resolves with the updated product's details.
|
|
91
|
+
* @throws {ErrorResponse} Throws an error if the product update fails.
|
|
92
|
+
*/
|
|
93
|
+
updateProduct: (productId: string, productData: UpdateProductRequest) => Promise<GetProductResponse>;
|
|
94
|
+
/**
|
|
95
|
+
* Deletes a product by its ID.
|
|
96
|
+
*
|
|
97
|
+
* @function
|
|
98
|
+
* @memberof recurrente
|
|
99
|
+
* @see deleteProduct
|
|
100
|
+
*/
|
|
101
|
+
deleteProduct: (productId: string) => Promise<{
|
|
102
|
+
message: string;
|
|
103
|
+
}>;
|
|
104
|
+
/**
|
|
105
|
+
* Creates a new subscription for a product.
|
|
106
|
+
*
|
|
107
|
+
* @function
|
|
108
|
+
* @memberof recurrente
|
|
109
|
+
* @see createSubscription
|
|
110
|
+
*/
|
|
111
|
+
createSubscription: (productData: ProductSubscription) => Promise<CreateSubscriptionResponse>;
|
|
112
|
+
/**
|
|
113
|
+
* Cancels an existing subscription by its ID.
|
|
114
|
+
*
|
|
115
|
+
* @function
|
|
116
|
+
* @memberof recurrente
|
|
117
|
+
* @see cancelSubscription
|
|
118
|
+
*/
|
|
119
|
+
cancelSubscription: (subscriptionId: string) => Promise<{
|
|
120
|
+
message: string;
|
|
121
|
+
}>;
|
|
122
|
+
/**
|
|
123
|
+
* Retrieves details of a specific subscription by its ID.
|
|
124
|
+
*
|
|
125
|
+
* @function
|
|
126
|
+
* @memberof recurrente
|
|
127
|
+
* @see getSubscription
|
|
128
|
+
*/
|
|
129
|
+
getSubscription: (subscriptionId: string) => Promise<SubscriptionStatusResponse>;
|
|
130
|
+
};
|
|
131
|
+
export default recurrente;
|
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
const axios_1 = __importDefault(require("axios"));
|
|
16
|
+
const axiosInstance_1 = __importDefault(require("../config/axiosInstance"));
|
|
17
|
+
const conversion_1 = require("../utils/conversion");
|
|
18
|
+
/**
|
|
19
|
+
* Creates a new product with a one-time payment.
|
|
20
|
+
*
|
|
21
|
+
* This function takes the product data, converts it to snake_case,
|
|
22
|
+
* and sends it to the API to create a new one-time payment product.
|
|
23
|
+
* It returns the created product's details.
|
|
24
|
+
*
|
|
25
|
+
* @param {CreateProductRequest} productData - The product details for the one-time payment.
|
|
26
|
+
* @returns {Promise<CreateProductResponse>} The response containing product details.
|
|
27
|
+
* @throws {ErrorResponse} Throws an error if the product creation fails.
|
|
28
|
+
*/
|
|
29
|
+
const createProduct = (productData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
30
|
+
try {
|
|
31
|
+
const productDataInSnakeCase = (0, conversion_1.toSnakeCase)(productData);
|
|
32
|
+
const response = yield axiosInstance_1.default.post('/products/', productDataInSnakeCase);
|
|
33
|
+
return (0, conversion_1.toCamelCase)(response.data); // Return the created product's details
|
|
34
|
+
}
|
|
35
|
+
catch (error) {
|
|
36
|
+
// Handle errors via the centralized error handler
|
|
37
|
+
throw handleAxiosError(error);
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
/**
|
|
41
|
+
* Retrieves details of a specific product by its ID.
|
|
42
|
+
*
|
|
43
|
+
* This function fetches details of an existing product by making a GET request
|
|
44
|
+
* to the API using the provided product ID. It returns the product's details.
|
|
45
|
+
*
|
|
46
|
+
* @param {string} productId - The ID of the product to retrieve.
|
|
47
|
+
* @returns {Promise<GetProductResponse>} The response containing the product details.
|
|
48
|
+
* @throws {ErrorResponse} Throws an error if the product retrieval fails.
|
|
49
|
+
*/
|
|
50
|
+
const getProduct = (productId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
51
|
+
try {
|
|
52
|
+
const response = yield axiosInstance_1.default.get(`/products/${productId}`);
|
|
53
|
+
return (0, conversion_1.toCamelCase)(response.data);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
throw handleAxiosError(error); // Handle errors via the centralized error handler
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
/**
|
|
60
|
+
* Retrieves a list of all products.
|
|
61
|
+
*
|
|
62
|
+
* This function fetches a paginated list of products from the API.
|
|
63
|
+
* By default, it retrieves the 10 most recent products, but pagination
|
|
64
|
+
* can be controlled using query parameters.
|
|
65
|
+
*
|
|
66
|
+
* @param {number} [page=1] - The page number to retrieve, defaults to the first page.
|
|
67
|
+
* @returns {Promise<GetAllProductsResponse>} The response containing an array of product details.
|
|
68
|
+
* @throws {ErrorResponse} Throws an error if the product retrieval fails.
|
|
69
|
+
*/
|
|
70
|
+
const getAllProducts = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (page = 1) {
|
|
71
|
+
try {
|
|
72
|
+
const response = yield axiosInstance_1.default.get(`/products?page=${page}`);
|
|
73
|
+
return (0, conversion_1.toCamelCase)(response.data);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
throw handleAxiosError(error); // Handle errors via the centralized error handler
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
/**
|
|
80
|
+
* Updates an existing product by its ID.
|
|
81
|
+
*
|
|
82
|
+
* This function takes the product ID and an object containing the updated product details.
|
|
83
|
+
* It sends a PATCH request to the API to update the specified product. You can also
|
|
84
|
+
* modify product prices or delete them by passing the _destroy parameter in prices_attributes.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} productId - The ID of the product to update.
|
|
87
|
+
* @param {UpdateProductRequest} productData - The updated product details.
|
|
88
|
+
* @returns {Promise<GetProductResponse>} A promise that resolves with the updated product's details.
|
|
89
|
+
* @throws {ErrorResponse} Throws an error if the product update fails.
|
|
90
|
+
*/
|
|
91
|
+
const updateProduct = (productId, productData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
92
|
+
try {
|
|
93
|
+
const productDataInSnakeCase = (0, conversion_1.toSnakeCase)(productData);
|
|
94
|
+
const response = yield axiosInstance_1.default.patch(`/products/${productId}`, productDataInSnakeCase);
|
|
95
|
+
return (0, conversion_1.toCamelCase)(response.data); // Return the updated product's details
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
throw handleAxiosError(error); // Handle errors via the centralized error handler
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
/**
|
|
102
|
+
* Creates a new subscription for a product.
|
|
103
|
+
*
|
|
104
|
+
* This function takes a product's subscription data, converts it to snake_case,
|
|
105
|
+
* and sends it to the API to create a new subscription. It returns the created
|
|
106
|
+
* subscription's details.
|
|
107
|
+
*
|
|
108
|
+
* @param {ProductSubscription} productData - The subscription details for the product.
|
|
109
|
+
* @returns {Promise<CreateSubscriptionResponse>} The response containing subscription details.
|
|
110
|
+
* @throws {ErrorResponse} Throws an error if the subscription creation fails.
|
|
111
|
+
*/
|
|
112
|
+
const createSubscription = (productData) => __awaiter(void 0, void 0, void 0, function* () {
|
|
113
|
+
try {
|
|
114
|
+
const productDataInSnakeCase = (0, conversion_1.toSnakeCase)(productData);
|
|
115
|
+
const response = yield axiosInstance_1.default.post('/products/', productDataInSnakeCase);
|
|
116
|
+
return (0, conversion_1.toCamelCase)(response.data); // Return the success response only
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
// Throw an error to handle it in a higher-level function or component
|
|
120
|
+
throw handleAxiosError(error);
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
/**
|
|
124
|
+
* Cancels an existing subscription by its ID.
|
|
125
|
+
*
|
|
126
|
+
* This function sends a request to cancel the subscription specified by the
|
|
127
|
+
* subscription ID. It returns a message indicating the success of the operation.
|
|
128
|
+
*
|
|
129
|
+
* @param {string} subscriptionId - The ID of the subscription to cancel.
|
|
130
|
+
* @returns {Promise<{message: string}>} A message indicating whether the subscription was canceled successfully.
|
|
131
|
+
* @throws {ErrorResponse} Throws an error if the cancellation fails.
|
|
132
|
+
*/
|
|
133
|
+
const cancelSubscription = (subscriptionId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
134
|
+
try {
|
|
135
|
+
const response = yield axiosInstance_1.default.delete(`/subscriptions/${subscriptionId}`);
|
|
136
|
+
return {
|
|
137
|
+
message: `Subscription canceled successfully. Status: ${response.status}`,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
throw handleAxiosError(error);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
/**
|
|
145
|
+
* Deletes a product by its ID.
|
|
146
|
+
*
|
|
147
|
+
* This function deletes a product from the system using the product ID. It
|
|
148
|
+
* returns a message indicating whether the product was deleted successfully.
|
|
149
|
+
*
|
|
150
|
+
* @param {string} productId - The ID of the product to delete.
|
|
151
|
+
* @returns {Promise<{message: string}>} A message indicating whether the product was deleted successfully.
|
|
152
|
+
* @throws {ErrorResponse} Throws an error if the deletion fails.
|
|
153
|
+
*/
|
|
154
|
+
const deleteProduct = (productId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
155
|
+
try {
|
|
156
|
+
yield axiosInstance_1.default.delete(`/products/${productId}`);
|
|
157
|
+
return { message: 'Product deleted successfully' };
|
|
158
|
+
}
|
|
159
|
+
catch (error) {
|
|
160
|
+
throw handleAxiosError(error);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
/**
|
|
164
|
+
* Retrieves details of a specific subscription by its ID.
|
|
165
|
+
*
|
|
166
|
+
* This function fetches details of an existing subscription by making a GET request
|
|
167
|
+
* using the subscription ID.
|
|
168
|
+
*
|
|
169
|
+
* @param {string} subscriptionId - The ID of the subscription to retrieve.
|
|
170
|
+
* @returns {Promise<SubscriptionStatusResponse>} The details of the subscription.
|
|
171
|
+
* @throws {ErrorResponse} Throws an error if the retrieval fails.
|
|
172
|
+
*/
|
|
173
|
+
const getSubscription = (subscriptionId) => __awaiter(void 0, void 0, void 0, function* () {
|
|
174
|
+
try {
|
|
175
|
+
const response = yield axiosInstance_1.default.get(`/subscriptions/${subscriptionId}`);
|
|
176
|
+
return (0, conversion_1.toCamelCase)(response.data);
|
|
177
|
+
}
|
|
178
|
+
catch (error) {
|
|
179
|
+
throw handleAxiosError(error);
|
|
180
|
+
}
|
|
181
|
+
});
|
|
182
|
+
/**
|
|
183
|
+
* Centralized error handler for Axios requests.
|
|
184
|
+
*
|
|
185
|
+
* This function checks if the error is from Axios and extracts meaningful
|
|
186
|
+
* information from the response or throws a general error message if the error
|
|
187
|
+
* is not from Axios.
|
|
188
|
+
*
|
|
189
|
+
* @param {unknown} error - The error object caught during an API request.
|
|
190
|
+
* @returns {ErrorResponse} An object containing error details such as status and message.
|
|
191
|
+
*/
|
|
192
|
+
function handleAxiosError(error) {
|
|
193
|
+
if (axios_1.default.isAxiosError(error)) {
|
|
194
|
+
if (error.response && error.response.data) {
|
|
195
|
+
return {
|
|
196
|
+
status: 'error',
|
|
197
|
+
message: error.response.data.message || 'An error occurred',
|
|
198
|
+
errors: error.response.data.errors || {},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
status: 'error',
|
|
203
|
+
message: error.message || 'Unknown Axios error occurred',
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
return {
|
|
208
|
+
status: 'error',
|
|
209
|
+
message: 'An unknown error occurred',
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Makes a GET request to the '/test' endpoint.
|
|
215
|
+
*
|
|
216
|
+
* This function is not exported and is intended for internal use.
|
|
217
|
+
*
|
|
218
|
+
* @returns {Promise<{message: string}>} A message indicating success or failure of the request.
|
|
219
|
+
* @throws {ErrorResponse} Throws an error if the request fails.
|
|
220
|
+
*/
|
|
221
|
+
const test = () => __awaiter(void 0, void 0, void 0, function* () {
|
|
222
|
+
try {
|
|
223
|
+
const response = yield axiosInstance_1.default.get('/test');
|
|
224
|
+
return {
|
|
225
|
+
message: `Test request succeeded. Status: ${response.data.message}`,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
throw handleAxiosError(error);
|
|
230
|
+
}
|
|
231
|
+
});
|
|
232
|
+
/**
|
|
233
|
+
* Recurrente API utility for managing product subscriptions, cancellations, and product deletions.
|
|
234
|
+
*
|
|
235
|
+
* The `recurrente` object provides methods to create, cancel, retrieve, and delete subscriptions and products,
|
|
236
|
+
* making it easy to integrate Recurrente's payment services into your project.
|
|
237
|
+
*
|
|
238
|
+
* @namespace recurrente
|
|
239
|
+
* @property {Function} test - Test endpoint.
|
|
240
|
+
* @property {Function} createProduct - Creates a new product with a one-time payment.
|
|
241
|
+
* @property {Function} getProduct - Retrieves details of a specific product by its ID.
|
|
242
|
+
* @property {Function} getAllProducts - Retrieves a paginated list of all products.
|
|
243
|
+
* @property {Function} updateProduct - Updates an existing product by its ID.
|
|
244
|
+
* @property {Function} deleteProduct - Deletes a product by its ID.
|
|
245
|
+
* @property {Function} createSubscription - Creates a new subscription for a product.
|
|
246
|
+
* @property {Function} cancelSubscription - Cancels an existing subscription by its ID.
|
|
247
|
+
* @property {Function} getSubscription - Retrieves details of a specific subscription by its ID.
|
|
248
|
+
*/
|
|
249
|
+
const recurrente = {
|
|
250
|
+
/**
|
|
251
|
+
* Makes a GET request to the '/test' endpoint.
|
|
252
|
+
*
|
|
253
|
+
* **FOR DEVELOPMENT PURPOSES ONLY TO TEST**
|
|
254
|
+
*
|
|
255
|
+
* This method is included for testing internal API functionality.
|
|
256
|
+
*
|
|
257
|
+
* @function
|
|
258
|
+
* @memberof recurrente
|
|
259
|
+
* @returns {Promise<{message: string}>} A message indicating the success or failure of the request.
|
|
260
|
+
* @throws {ErrorResponse} Throws an error if the request fails.
|
|
261
|
+
*/
|
|
262
|
+
test,
|
|
263
|
+
/**
|
|
264
|
+
* Creates a new product with a one-time payment.
|
|
265
|
+
*
|
|
266
|
+
* This function takes the product data, converts it to snake_case,
|
|
267
|
+
* and sends it to the API to create a one-time payment product.
|
|
268
|
+
* It returns the created product's details.
|
|
269
|
+
*
|
|
270
|
+
* @function
|
|
271
|
+
* @memberof recurrente
|
|
272
|
+
* @see createProduct
|
|
273
|
+
* @param {CreateProductRequest} productData - The details of the product to create.
|
|
274
|
+
* @returns {Promise<CreateProductResponse>} A promise that resolves with the created product's details.
|
|
275
|
+
* @throws {ErrorResponse} Throws an error if the product creation fails.
|
|
276
|
+
*/
|
|
277
|
+
createProduct,
|
|
278
|
+
/**
|
|
279
|
+
* Retrieves details of a specific product by its ID.
|
|
280
|
+
*
|
|
281
|
+
* This function fetches details of an existing product by making a GET request
|
|
282
|
+
* using the product ID.
|
|
283
|
+
*
|
|
284
|
+
* @function
|
|
285
|
+
* @memberof recurrente
|
|
286
|
+
* @see getProduct
|
|
287
|
+
* @param {string} productId - The ID of the product to retrieve.
|
|
288
|
+
* @returns {Promise<GetProductResponse>} The details of the product.
|
|
289
|
+
* @throws {ErrorResponse} Throws an error if the retrieval fails.
|
|
290
|
+
*/
|
|
291
|
+
getProduct,
|
|
292
|
+
/**
|
|
293
|
+
* Retrieves a paginated list of all products.
|
|
294
|
+
*
|
|
295
|
+
* This function fetches a list of products from the API. By default, it retrieves
|
|
296
|
+
* the 10 most recent products, but pagination can be controlled using query parameters.
|
|
297
|
+
*
|
|
298
|
+
* @function
|
|
299
|
+
* @memberof recurrente
|
|
300
|
+
* @see getAllProducts
|
|
301
|
+
* @param {number} [page=1] - The page number to retrieve, defaults to the first page.
|
|
302
|
+
* @returns {Promise<GetAllProductsResponse>} A promise that resolves with an array of product details.
|
|
303
|
+
* @throws {ErrorResponse} Throws an error if the product retrieval fails.
|
|
304
|
+
*/
|
|
305
|
+
getAllProducts,
|
|
306
|
+
/**
|
|
307
|
+
* Updates an existing product by its ID.
|
|
308
|
+
*
|
|
309
|
+
* This function takes the product ID and an object containing the updated product details.
|
|
310
|
+
* It sends a PATCH request to the API to update the specified product. You can also
|
|
311
|
+
* modify product prices or delete them by passing the _destroy parameter in prices_attributes.
|
|
312
|
+
*
|
|
313
|
+
* @function
|
|
314
|
+
* @memberof recurrente
|
|
315
|
+
* @see updateProduct
|
|
316
|
+
* @param {string} productId - The ID of the product to update.
|
|
317
|
+
* @param {UpdateProductRequest} productData - The updated product details.
|
|
318
|
+
* @returns {Promise<GetProductResponse>} A promise that resolves with the updated product's details.
|
|
319
|
+
* @throws {ErrorResponse} Throws an error if the product update fails.
|
|
320
|
+
*/
|
|
321
|
+
updateProduct,
|
|
322
|
+
/**
|
|
323
|
+
* Deletes a product by its ID.
|
|
324
|
+
*
|
|
325
|
+
* @function
|
|
326
|
+
* @memberof recurrente
|
|
327
|
+
* @see deleteProduct
|
|
328
|
+
*/
|
|
329
|
+
deleteProduct,
|
|
330
|
+
/**
|
|
331
|
+
* Creates a new subscription for a product.
|
|
332
|
+
*
|
|
333
|
+
* @function
|
|
334
|
+
* @memberof recurrente
|
|
335
|
+
* @see createSubscription
|
|
336
|
+
*/
|
|
337
|
+
createSubscription,
|
|
338
|
+
/**
|
|
339
|
+
* Cancels an existing subscription by its ID.
|
|
340
|
+
*
|
|
341
|
+
* @function
|
|
342
|
+
* @memberof recurrente
|
|
343
|
+
* @see cancelSubscription
|
|
344
|
+
*/
|
|
345
|
+
cancelSubscription,
|
|
346
|
+
/**
|
|
347
|
+
* Retrieves details of a specific subscription by its ID.
|
|
348
|
+
*
|
|
349
|
+
* @function
|
|
350
|
+
* @memberof recurrente
|
|
351
|
+
* @see getSubscription
|
|
352
|
+
*/
|
|
353
|
+
getSubscription,
|
|
354
|
+
};
|
|
355
|
+
exports.default = recurrente;
|