chariow-store-manager 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/README.md ADDED
@@ -0,0 +1,205 @@
1
+ # chariow-store-manager
2
+
3
+ A strictly typed Node.js wrapper for the [Chariow](https://chariow.dev) API.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install chariow-store-manager
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ### Initialization
14
+
15
+ You can initialize the client with your API key directly:
16
+
17
+ ```typescript
18
+ import { ChariowClient } from 'chariow-store-manager';
19
+
20
+ const client = new ChariowClient({
21
+ apiKey: 'sk_live_...',
22
+ webhookSecret: 'whsec_...' // Optional: for verifying pulses (webhooks)
23
+ });
24
+ ```
25
+
26
+ Or rely on the `CHARIOW_API_KEY` and `CHARIOW_WEBHOOK_SECRET` environment variables:
27
+
28
+ ```typescript
29
+ // Ensure CHARIOW_API_KEY is set in your environment
30
+ const client = new ChariowClient();
31
+ ```
32
+
33
+ ### Products
34
+
35
+ ```typescript
36
+ // List products with pagination and filtering
37
+ const { data: products, pagination } = await client.products.list({
38
+ per_page: 10,
39
+ category: 'technology'
40
+ });
41
+
42
+ // Get a single product (by ID or slug)
43
+ const product = await client.products.retrieve('prd_abc123');
44
+ console.log(product.description);
45
+ ```
46
+
47
+ ### Customers
48
+
49
+ ```typescript
50
+ // List customers
51
+ const { data: customers } = await client.customers.list({ search: 'john' });
52
+
53
+ // Get a single customer
54
+ const customer = await client.customers.retrieve('cus_ghi789');
55
+ ```
56
+
57
+ ### Sales
58
+
59
+ ```typescript
60
+ // List sales
61
+ const { data: sales } = await client.sales.list({ status: 'completed' });
62
+
63
+ // Get a single sale
64
+ const sale = await client.sales.retrieve('sal_abc123');
65
+ console.log(sale.payment.status);
66
+ ```
67
+
68
+ ### Checkouts
69
+
70
+ Create a checkout session for your customers:
71
+
72
+ ```typescript
73
+ const checkout = await client.checkouts.create({
74
+ product_id: 'prd_abc123',
75
+ email: 'customer@example.com',
76
+ first_name: 'John',
77
+ last_name: 'Doe',
78
+ phone: {
79
+ number: '1234567890',
80
+ country_code: 'US'
81
+ },
82
+ redirect_url: 'https://yoursite.com/thank-you',
83
+ // Optional
84
+ discount_code: 'SAVE20',
85
+ custom_metadata: {
86
+ order_ref: 'ORD-123'
87
+ }
88
+ });
89
+
90
+ if (checkout.step === 'awaiting_payment' && checkout.payment.checkout_url) {
91
+ console.log('Redirect user to:', checkout.payment.checkout_url);
92
+ } else if (checkout.step === 'completed') {
93
+ console.log('Purchase completed (free product)');
94
+ }
95
+ ```
96
+
97
+ ### Discounts
98
+
99
+ Manage discount codes:
100
+
101
+ ```typescript
102
+ // Create a 20% off discount
103
+ const discount = await client.discounts.create({
104
+ code: 'SUMMER20',
105
+ type: 'percentage',
106
+ value: 20,
107
+ usage_limit: 100
108
+ });
109
+
110
+ // List all discounts
111
+ const { data: discounts } = await client.discounts.list();
112
+ ```
113
+
114
+ ### Affiliates
115
+
116
+ Manage your affiliate program:
117
+
118
+ ```typescript
119
+ // Register a new affiliate
120
+ const affiliate = await client.affiliates.create({
121
+ code: 'INFLUENCER1',
122
+ commission_rate: 15, // 15% commission
123
+ paypal_email: 'influencer@example.com'
124
+ });
125
+ ```
126
+
127
+ ### Pulses (Webhooks)
128
+
129
+ Handle incoming webhooks securely with built-in signature verification.
130
+
131
+ #### Using with Express/Node.js
132
+
133
+ ```typescript
134
+ import express from 'express';
135
+ import { ChariowClient } from 'chariow-store-manager';
136
+
137
+ const app = express();
138
+ const client = new ChariowClient();
139
+
140
+ // Use raw body parser to verify signatures correctly
141
+ app.post('/webhooks/chariow', express.raw({ type: 'application/json' }), async (req, res) => {
142
+ const signature = req.headers['x-chariow-signature'] as string;
143
+
144
+ try {
145
+ const event = client.pulses.constructEvent(req.body, signature);
146
+
147
+ // Handle specific events
148
+ if (event.type === 'sale.completed') {
149
+ console.log('Sale completed:', event.data.id);
150
+ }
151
+
152
+ // Or use the event handler system
153
+ await client.pulses.handleEvent(event);
154
+
155
+ res.json({ received: true });
156
+ } catch (err) {
157
+ console.error('Webhook Error:', err.message);
158
+ res.status(400).send(`Webhook Error: ${err.message}`);
159
+ }
160
+ });
161
+
162
+ // Register event handlers elsewhere in your app
163
+ client.pulses.on('sale.completed', async (event) => {
164
+ const sale = event.data;
165
+ console.log(`Processing sale ${sale.id} for product ${sale.product_id}`);
166
+ // Grant access, send email, etc.
167
+ });
168
+ ```
169
+
170
+ ### Pagination & Filtering
171
+
172
+ All list methods support pagination and filtering:
173
+
174
+ ```typescript
175
+ const { data, pagination } = await client.sales.list({
176
+ per_page: 20,
177
+ cursor: 'eyJ...', // From previous response
178
+ status: 'completed', // Filter by status
179
+ customer_id: 'cus_123' // Filter by customer
180
+ });
181
+ ```
182
+
183
+ ## Error Handling
184
+
185
+ The client throws structured errors when the API returns a failure response.
186
+
187
+ ```typescript
188
+ try {
189
+ await client.products.retrieve('invalid_id');
190
+ } catch (error: any) {
191
+ if (error.response) {
192
+ // API returned an error response (4xx, 5xx)
193
+ console.error('API Error:', error.message);
194
+ console.error('Status:', error.status);
195
+ console.error('Details:', error.response.errors);
196
+ } else {
197
+ // Network error or other issue
198
+ console.error('Error:', error.message);
199
+ }
200
+ }
201
+ ```
202
+
203
+ ## TypeScript Support
204
+
205
+ This package is written in TypeScript and includes full type definitions.
@@ -0,0 +1,26 @@
1
+ import { ChariowConfig } from './types';
2
+ import { Products } from './resources/products';
3
+ import { Customers } from './resources/customers';
4
+ import { Sales } from './resources/sales';
5
+ import { Licenses } from './resources/licenses';
6
+ import { Checkouts } from './resources/checkouts';
7
+ import { Discounts } from './resources/discounts';
8
+ import { Affiliates } from './resources/affiliates';
9
+ import { Pulses } from './resources/pulses';
10
+ export declare class ChariowClient {
11
+ private _axios;
12
+ config: ChariowConfig;
13
+ products: Products;
14
+ customers: Customers;
15
+ sales: Sales;
16
+ licenses: Licenses;
17
+ checkouts: Checkouts;
18
+ discounts: Discounts;
19
+ affiliates: Affiliates;
20
+ pulses: Pulses;
21
+ constructor(config?: ChariowConfig);
22
+ get<T>(path: string, params?: any): Promise<T>;
23
+ post<T>(path: string, data?: any): Promise<T>;
24
+ put<T>(path: string, data?: any): Promise<T>;
25
+ delete<T>(path: string): Promise<T>;
26
+ }
package/dist/client.js ADDED
@@ -0,0 +1,76 @@
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.ChariowClient = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const products_1 = require("./resources/products");
9
+ const customers_1 = require("./resources/customers");
10
+ const sales_1 = require("./resources/sales");
11
+ const licenses_1 = require("./resources/licenses");
12
+ const checkouts_1 = require("./resources/checkouts");
13
+ const discounts_1 = require("./resources/discounts");
14
+ const affiliates_1 = require("./resources/affiliates");
15
+ const pulses_1 = require("./resources/pulses");
16
+ const DEFAULT_BASE_URL = 'https://api.chariow.com/v1';
17
+ class ChariowClient {
18
+ constructor(config = { apiKey: '' }) {
19
+ this.config = config;
20
+ const apiKey = config.apiKey || process.env.CHARIOW_API_KEY;
21
+ if (!apiKey) {
22
+ throw new Error('API key is required. Please provide it in the constructor or set CHARIOW_API_KEY environment variable.');
23
+ }
24
+ this._axios = axios_1.default.create({
25
+ baseURL: config.baseURL || DEFAULT_BASE_URL,
26
+ timeout: config.timeout || 10000,
27
+ headers: {
28
+ 'Authorization': `Bearer ${apiKey}`,
29
+ 'Content-Type': 'application/json',
30
+ 'User-Agent': 'chariow-store-manager/1.0.0'
31
+ }
32
+ });
33
+ this._axios.interceptors.response.use((response) => response, (error) => {
34
+ if (error.response) {
35
+ const { status, data } = error.response;
36
+ // Handle rate limiting
37
+ if (status === 429) {
38
+ console.warn('Chariow API Rate Limit Exceeded');
39
+ }
40
+ // Wrap error for better DX
41
+ const errorData = data;
42
+ const message = errorData.message || error.message;
43
+ const apiError = new Error(`Chariow API Error (${status}): ${message}`);
44
+ apiError.response = errorData;
45
+ apiError.status = status;
46
+ return Promise.reject(apiError);
47
+ }
48
+ return Promise.reject(error);
49
+ });
50
+ this.products = new products_1.Products(this);
51
+ this.customers = new customers_1.Customers(this);
52
+ this.sales = new sales_1.Sales(this);
53
+ this.licenses = new licenses_1.Licenses(this);
54
+ this.checkouts = new checkouts_1.Checkouts(this);
55
+ this.discounts = new discounts_1.Discounts(this);
56
+ this.affiliates = new affiliates_1.Affiliates(this);
57
+ this.pulses = new pulses_1.Pulses(this);
58
+ }
59
+ async get(path, params) {
60
+ const response = await this._axios.get(path, { params });
61
+ return response.data.data;
62
+ }
63
+ async post(path, data) {
64
+ const response = await this._axios.post(path, data);
65
+ return response.data.data;
66
+ }
67
+ async put(path, data) {
68
+ const response = await this._axios.put(path, data);
69
+ return response.data.data;
70
+ }
71
+ async delete(path) {
72
+ const response = await this._axios.delete(path);
73
+ return response.data.data;
74
+ }
75
+ }
76
+ exports.ChariowClient = ChariowClient;
@@ -0,0 +1,11 @@
1
+ export * from './client';
2
+ export * from './types';
3
+ export * from './resources/base';
4
+ export * from './resources/products';
5
+ export * from './resources/customers';
6
+ export * from './resources/sales';
7
+ export * from './resources/licenses';
8
+ export * from './resources/checkouts';
9
+ export * from './resources/discounts';
10
+ export * from './resources/affiliates';
11
+ export * from './resources/pulses';
package/dist/index.js ADDED
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./client"), exports);
18
+ __exportStar(require("./types"), exports);
19
+ __exportStar(require("./resources/base"), exports);
20
+ __exportStar(require("./resources/products"), exports);
21
+ __exportStar(require("./resources/customers"), exports);
22
+ __exportStar(require("./resources/sales"), exports);
23
+ __exportStar(require("./resources/licenses"), exports);
24
+ __exportStar(require("./resources/checkouts"), exports);
25
+ __exportStar(require("./resources/discounts"), exports);
26
+ __exportStar(require("./resources/affiliates"), exports);
27
+ __exportStar(require("./resources/pulses"), exports);
@@ -0,0 +1,5 @@
1
+ import { BaseResource } from './base';
2
+ import { Affiliate, CreateAffiliateParams } from '../types';
3
+ export declare class Affiliates extends BaseResource<Affiliate, CreateAffiliateParams> {
4
+ protected path: string;
5
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Affiliates = void 0;
4
+ const base_1 = require("./base");
5
+ class Affiliates extends base_1.BaseResource {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.path = '/affiliates';
9
+ }
10
+ }
11
+ exports.Affiliates = Affiliates;
@@ -0,0 +1,12 @@
1
+ import type { ChariowClient } from '../client';
2
+ import { ListParams, PaginatedResponse } from '../types';
3
+ export declare abstract class BaseResource<T, C = Partial<T>, U = Partial<T>> {
4
+ protected abstract path: string;
5
+ protected client: ChariowClient;
6
+ constructor(client: ChariowClient);
7
+ list(params?: ListParams): Promise<PaginatedResponse<T>>;
8
+ retrieve(id: string): Promise<T>;
9
+ create(data: C): Promise<T>;
10
+ update(id: string, data: U): Promise<T>;
11
+ delete(id: string): Promise<void>;
12
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BaseResource = void 0;
4
+ class BaseResource {
5
+ constructor(client) {
6
+ this.client = client;
7
+ }
8
+ async list(params) {
9
+ return this.client.get(this.path, params);
10
+ }
11
+ async retrieve(id) {
12
+ return this.client.get(`${this.path}/${id}`);
13
+ }
14
+ async create(data) {
15
+ return this.client.post(this.path, data);
16
+ }
17
+ async update(id, data) {
18
+ return this.client.put(`${this.path}/${id}`, data);
19
+ }
20
+ async delete(id) {
21
+ return this.client.delete(`${this.path}/${id}`);
22
+ }
23
+ }
24
+ exports.BaseResource = BaseResource;
@@ -0,0 +1,6 @@
1
+ import { BaseResource } from './base';
2
+ import { CheckoutResponseData, CreateCheckoutParams } from '../types';
3
+ export declare class Checkouts extends BaseResource<CheckoutResponseData, CreateCheckoutParams> {
4
+ protected path: string;
5
+ create(data: CreateCheckoutParams): Promise<CheckoutResponseData>;
6
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Checkouts = void 0;
4
+ const base_1 = require("./base");
5
+ class Checkouts extends base_1.BaseResource {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.path = '/checkout';
9
+ }
10
+ async create(data) {
11
+ return this.client.post(this.path, data);
12
+ }
13
+ }
14
+ exports.Checkouts = Checkouts;
@@ -0,0 +1,5 @@
1
+ import { BaseResource } from './base';
2
+ import { Customer } from '../types';
3
+ export declare class Customers extends BaseResource<Customer> {
4
+ protected path: string;
5
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Customers = void 0;
4
+ const base_1 = require("./base");
5
+ class Customers extends base_1.BaseResource {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.path = '/customers';
9
+ }
10
+ }
11
+ exports.Customers = Customers;
@@ -0,0 +1,5 @@
1
+ import { BaseResource } from './base';
2
+ import { Discount, CreateDiscountParams } from '../types';
3
+ export declare class Discounts extends BaseResource<Discount, CreateDiscountParams> {
4
+ protected path: string;
5
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Discounts = void 0;
4
+ const base_1 = require("./base");
5
+ class Discounts extends base_1.BaseResource {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.path = '/discounts';
9
+ }
10
+ }
11
+ exports.Discounts = Discounts;
@@ -0,0 +1,6 @@
1
+ import { BaseResource } from './base';
2
+ import { License, ValidateLicenseResponse } from '../types';
3
+ export declare class Licenses extends BaseResource<License> {
4
+ protected path: string;
5
+ validate(key: string, product_id?: string): Promise<ValidateLicenseResponse>;
6
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Licenses = void 0;
4
+ const base_1 = require("./base");
5
+ class Licenses extends base_1.BaseResource {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.path = '/licenses';
9
+ }
10
+ async validate(key, product_id) {
11
+ return this.client.post(`${this.path}/validate`, { key, product_id });
12
+ }
13
+ }
14
+ exports.Licenses = Licenses;
@@ -0,0 +1,5 @@
1
+ import { BaseResource } from './base';
2
+ import { Product } from '../types';
3
+ export declare class Products extends BaseResource<Product> {
4
+ protected path: string;
5
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Products = void 0;
4
+ const base_1 = require("./base");
5
+ class Products extends base_1.BaseResource {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.path = '/products';
9
+ }
10
+ }
11
+ exports.Products = Products;
@@ -0,0 +1,36 @@
1
+ import { ChariowClient } from '../client';
2
+ import { PulseEvent, PulseHandler } from '../types';
3
+ export declare class Pulses {
4
+ protected client: ChariowClient;
5
+ private handlers;
6
+ constructor(client: ChariowClient);
7
+ /**
8
+ * Registers a handler for a specific pulse event type.
9
+ * @param eventType The event type to listen for (e.g., 'sale.created', '*')
10
+ * @param handler The function to execute when the event is received
11
+ */
12
+ on(eventType: string, handler: PulseHandler): void;
13
+ /**
14
+ * Removes a handler for a specific pulse event type.
15
+ * @param eventType The event type
16
+ * @param handler The handler function to remove
17
+ */
18
+ off(eventType: string, handler: PulseHandler): void;
19
+ /**
20
+ * Constructs a PulseEvent from the raw request body and signature.
21
+ * Verifies the signature if a webhook secret is configured.
22
+ *
23
+ * @param payload The raw request body (string or buffer)
24
+ * @param signature The signature from the X-Chariow-Signature header
25
+ * @returns The parsed PulseEvent
26
+ * @throws Error if signature verification fails
27
+ */
28
+ constructEvent(payload: string | Buffer, signature: string): PulseEvent;
29
+ /**
30
+ * Manually triggers the handlers for a given event.
31
+ * Useful when using the constructEvent method in your own webhook endpoint.
32
+ * @param event The parsed PulseEvent
33
+ */
34
+ handleEvent(event: PulseEvent): Promise<void>;
35
+ private verifySignature;
36
+ }
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.Pulses = void 0;
37
+ const crypto = __importStar(require("crypto"));
38
+ class Pulses {
39
+ constructor(client) {
40
+ this.handlers = new Map();
41
+ this.client = client;
42
+ }
43
+ /**
44
+ * Registers a handler for a specific pulse event type.
45
+ * @param eventType The event type to listen for (e.g., 'sale.created', '*')
46
+ * @param handler The function to execute when the event is received
47
+ */
48
+ on(eventType, handler) {
49
+ if (!this.handlers.has(eventType)) {
50
+ this.handlers.set(eventType, []);
51
+ }
52
+ this.handlers.get(eventType)?.push(handler);
53
+ }
54
+ /**
55
+ * Removes a handler for a specific pulse event type.
56
+ * @param eventType The event type
57
+ * @param handler The handler function to remove
58
+ */
59
+ off(eventType, handler) {
60
+ const handlers = this.handlers.get(eventType);
61
+ if (handlers) {
62
+ const index = handlers.indexOf(handler);
63
+ if (index !== -1) {
64
+ handlers.splice(index, 1);
65
+ }
66
+ }
67
+ }
68
+ /**
69
+ * Constructs a PulseEvent from the raw request body and signature.
70
+ * Verifies the signature if a webhook secret is configured.
71
+ *
72
+ * @param payload The raw request body (string or buffer)
73
+ * @param signature The signature from the X-Chariow-Signature header
74
+ * @returns The parsed PulseEvent
75
+ * @throws Error if signature verification fails
76
+ */
77
+ constructEvent(payload, signature) {
78
+ const secret = this.client.config.webhookSecret || process.env.CHARIOW_WEBHOOK_SECRET;
79
+ if (secret) {
80
+ this.verifySignature(payload, signature, secret);
81
+ }
82
+ else {
83
+ console.warn('No webhook secret provided. Skipping signature verification.');
84
+ }
85
+ const event = JSON.parse(payload.toString());
86
+ return event;
87
+ }
88
+ /**
89
+ * Manually triggers the handlers for a given event.
90
+ * Useful when using the constructEvent method in your own webhook endpoint.
91
+ * @param event The parsed PulseEvent
92
+ */
93
+ async handleEvent(event) {
94
+ const specificHandlers = this.handlers.get(event.type) || [];
95
+ const globalHandlers = this.handlers.get('*') || [];
96
+ const allHandlers = [...specificHandlers, ...globalHandlers];
97
+ await Promise.all(allHandlers.map(handler => handler(event)));
98
+ }
99
+ verifySignature(payload, signature, secret) {
100
+ // Assuming HMAC-SHA256 signature format: t=TIMESTAMP,v1=SIGNATURE or just SIGNATURE
101
+ // Adapting to a standard HMAC-SHA256 check for now.
102
+ // If Chariow uses a specific format (like Stripe's t=...,v1=...), this logic needs to be exact.
103
+ // For now, assuming raw hex digest of HMAC-SHA256(payload, secret).
104
+ const hmac = crypto.createHmac('sha256', secret);
105
+ hmac.update(payload);
106
+ const expectedSignature = hmac.digest('hex');
107
+ // Simple comparison (in production, use constant-time comparison)
108
+ // Note: If the signature header includes timestamp, this needs parsing.
109
+ // This is a basic implementation.
110
+ // Using crypto.timingSafeEqual for security if lengths match
111
+ const expectedBuffer = Buffer.from(expectedSignature);
112
+ const signatureBuffer = Buffer.from(signature);
113
+ if (expectedBuffer.length !== signatureBuffer.length || !crypto.timingSafeEqual(expectedBuffer, signatureBuffer)) {
114
+ throw new Error('Invalid signature');
115
+ }
116
+ }
117
+ }
118
+ exports.Pulses = Pulses;
@@ -0,0 +1,5 @@
1
+ import { BaseResource } from './base';
2
+ import { Sale } from '../types';
3
+ export declare class Sales extends BaseResource<Sale> {
4
+ protected path: string;
5
+ }
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Sales = void 0;
4
+ const base_1 = require("./base");
5
+ class Sales extends base_1.BaseResource {
6
+ constructor() {
7
+ super(...arguments);
8
+ this.path = '/sales';
9
+ }
10
+ }
11
+ exports.Sales = Sales;
@@ -0,0 +1,289 @@
1
+ export interface ChariowConfig {
2
+ apiKey: string;
3
+ baseURL?: string;
4
+ timeout?: number;
5
+ webhookSecret?: string;
6
+ }
7
+ export interface ApiResponse<T> {
8
+ message: string;
9
+ data: T;
10
+ errors: string[];
11
+ }
12
+ export interface ApiErrorResponse {
13
+ message: string;
14
+ data: any[];
15
+ errors: Record<string, string[]>;
16
+ }
17
+ export interface Pagination {
18
+ next_cursor: string | null;
19
+ prev_cursor: string | null;
20
+ has_more: boolean;
21
+ }
22
+ export interface PaginatedResponse<T> {
23
+ data: T[];
24
+ pagination: Pagination;
25
+ }
26
+ export interface ListParams {
27
+ cursor?: string;
28
+ per_page?: number;
29
+ search?: string;
30
+ start_date?: string;
31
+ end_date?: string;
32
+ [key: string]: any;
33
+ }
34
+ export interface Price {
35
+ value: number;
36
+ formatted: string;
37
+ short: string;
38
+ currency: string;
39
+ }
40
+ export interface ImageSet {
41
+ thumbnail: string;
42
+ cover: string;
43
+ }
44
+ export interface Category {
45
+ value: string;
46
+ label: string;
47
+ }
48
+ export interface Country {
49
+ name: string;
50
+ code: string;
51
+ alpha_3_code: string;
52
+ dial_code: string;
53
+ currency: string;
54
+ flag: string;
55
+ }
56
+ export interface Product {
57
+ id: string;
58
+ name: string;
59
+ slug: string;
60
+ description: string | null;
61
+ type: 'downloadable' | 'course' | 'license' | 'service' | 'bundle' | 'coaching';
62
+ category: Category;
63
+ status: 'draft' | 'published' | 'archived';
64
+ is_free: boolean;
65
+ pictures: ImageSet;
66
+ pricing: {
67
+ type: string;
68
+ price: Price;
69
+ current_price?: Price;
70
+ effective: Price;
71
+ sale_price: Price | null;
72
+ minimum_price?: Price;
73
+ suggested_price?: Price;
74
+ price_off: number | null;
75
+ };
76
+ has_variant_pricing: boolean;
77
+ quantity: number | null;
78
+ settings: {
79
+ is_shipping_address_required: boolean;
80
+ };
81
+ rating: {
82
+ average: number;
83
+ count: number;
84
+ };
85
+ on_sale_until: string | null;
86
+ sales_count: {
87
+ raw: number;
88
+ formatted: string;
89
+ };
90
+ seo: any | null;
91
+ custom_cta_text: {
92
+ value: string | null;
93
+ label: string | null;
94
+ };
95
+ fields: any[] | null;
96
+ store: any | null;
97
+ bundle: any | null;
98
+ created_at?: string;
99
+ updated_at?: string;
100
+ }
101
+ export interface Customer {
102
+ id: string;
103
+ name: string;
104
+ first_name: string;
105
+ last_name: string;
106
+ email: string;
107
+ avatar_url: string | null;
108
+ phone: {
109
+ number: string;
110
+ country: Country;
111
+ } | null;
112
+ store?: {
113
+ id: string;
114
+ name: string;
115
+ logo_url: string;
116
+ url: string;
117
+ };
118
+ created_at: string;
119
+ updated_at: string;
120
+ }
121
+ export interface Sale {
122
+ id: string;
123
+ status: 'completed' | 'pending' | 'failed' | 'refunded' | 'awaiting_payment' | 'abandoned' | 'settled';
124
+ channel: {
125
+ value: string;
126
+ label: string;
127
+ description: string;
128
+ };
129
+ original_amount: Price;
130
+ amount: Price;
131
+ discount_amount: Price | null;
132
+ settlement?: {
133
+ amount: Price;
134
+ due_at: string;
135
+ done_at: string | null;
136
+ service_fee: Price;
137
+ };
138
+ download?: {
139
+ total: number;
140
+ last_at: string | null;
141
+ };
142
+ invoice_download_url?: string;
143
+ payment: {
144
+ status: string;
145
+ transaction_id: string | null;
146
+ gateway: string | null;
147
+ method?: {
148
+ name: string;
149
+ icon_url: string;
150
+ };
151
+ amount: Price;
152
+ fee: Price | null;
153
+ fee_rate: string | null;
154
+ exchange_rate: Price | null;
155
+ failure_error: string | null;
156
+ };
157
+ shipping?: {
158
+ address: string;
159
+ city: string;
160
+ state: string;
161
+ country: Country;
162
+ zip: string;
163
+ };
164
+ context?: {
165
+ user_agent: string;
166
+ ip_address: string;
167
+ country: Country;
168
+ device_type: string;
169
+ locale: string;
170
+ };
171
+ custom_fields_values?: any | null;
172
+ campaign?: {
173
+ id: string;
174
+ name: string;
175
+ } | null;
176
+ rating?: {
177
+ id: string;
178
+ is_thumbs_up: boolean;
179
+ comment: string | null;
180
+ created_at: string;
181
+ } | null;
182
+ store: {
183
+ id: string;
184
+ name: string;
185
+ logo_url: string;
186
+ url: string;
187
+ };
188
+ product: Partial<Product>;
189
+ customer: Partial<Customer>;
190
+ discount: {
191
+ id: string;
192
+ name: string;
193
+ code: string;
194
+ } | null;
195
+ store_affiliate?: any | null;
196
+ affiliate_commission?: any | null;
197
+ is_reconciled: boolean;
198
+ last_reconciled_at: string | null;
199
+ failed_at: string | null;
200
+ awaiting_payment_at: string | null;
201
+ abandoned_at: string | null;
202
+ completed_at: string | null;
203
+ created_at: string;
204
+ updated_at: string;
205
+ }
206
+ export interface License {
207
+ id: string;
208
+ key: string;
209
+ product_id: string;
210
+ customer_id: string;
211
+ status: 'active' | 'expired' | 'revoked';
212
+ expires_at?: string;
213
+ created_at: string;
214
+ }
215
+ export interface ValidateLicenseResponse {
216
+ valid: boolean;
217
+ license?: License;
218
+ }
219
+ export interface CheckoutPhone {
220
+ number: string;
221
+ country_code: string;
222
+ }
223
+ export interface CreateCheckoutParams {
224
+ product_id: string;
225
+ email: string;
226
+ first_name: string;
227
+ last_name: string;
228
+ phone: CheckoutPhone;
229
+ discount_code?: string;
230
+ campaign_id?: string;
231
+ custom_fields?: Record<string, any>;
232
+ payment_currency?: string;
233
+ redirect_url?: string;
234
+ custom_metadata?: Record<string, string>;
235
+ address?: string;
236
+ city?: string;
237
+ state?: string;
238
+ country?: string;
239
+ zip?: string;
240
+ }
241
+ export interface CheckoutResponseData {
242
+ step: 'awaiting_payment' | 'completed' | 'already_purchased';
243
+ message: string | null;
244
+ purchase: Partial<Sale> | null;
245
+ payment: {
246
+ checkout_url: string | null;
247
+ transaction_id: string | null;
248
+ };
249
+ }
250
+ export interface Discount {
251
+ id: string;
252
+ code: string;
253
+ type: 'percentage' | 'fixed_amount';
254
+ value: number;
255
+ currency?: string;
256
+ usage_limit?: number;
257
+ usage_count: number;
258
+ active: boolean;
259
+ created_at: string;
260
+ }
261
+ export interface CreateDiscountParams {
262
+ code: string;
263
+ type: 'percentage' | 'fixed_amount';
264
+ value: number;
265
+ currency?: string;
266
+ usage_limit?: number;
267
+ active?: boolean;
268
+ }
269
+ export interface Affiliate {
270
+ id: string;
271
+ code: string;
272
+ commission_rate: number;
273
+ paypal_email?: string;
274
+ status: 'active' | 'inactive';
275
+ created_at: string;
276
+ }
277
+ export interface CreateAffiliateParams {
278
+ code: string;
279
+ commission_rate: number;
280
+ paypal_email?: string;
281
+ status?: 'active' | 'inactive';
282
+ }
283
+ export interface PulseEvent<T = any> {
284
+ id: string;
285
+ type: string;
286
+ data: T;
287
+ created_at: string;
288
+ }
289
+ export type PulseHandler = (event: PulseEvent) => void | Promise<void>;
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "chariow-store-manager",
3
+ "version": "1.0.0",
4
+ "description": "A simply nodejs package to use the Chariow API",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist"
9
+ ],
10
+ "scripts": {
11
+ "build": "tsc",
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [
15
+ "chariow",
16
+ "api",
17
+ "sdk"
18
+ ],
19
+ "author": "amos-gabriel",
20
+ "license": "ISC",
21
+ "devDependencies": {
22
+ "@types/node": "^25.2.3",
23
+ "axios": "^1.13.5",
24
+ "typescript": "^5.9.3"
25
+ }
26
+ }